Skip to content

Commit 73731f2

Browse files
committed
Strengthen WAN IP address retrieval and validation
1 parent ec866de commit 73731f2

File tree

12 files changed

+58
-63
lines changed

12 files changed

+58
-63
lines changed

.res/compose/docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ services:
99
environment:
1010
- "TZ=Europe/Paris"
1111
- "SCHEDULE=*/30 * * * *"
12+
- "MAX_RETRIES=3"
1213
- "LOG_LEVEL=info"
1314
- "LOG_JSON=false"
1415
restart: always

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 1.6.0 (2019/12/20)
4+
5+
* Strengthen WAN IP address retrieval and validation
6+
* Move ident.me client to pkg
7+
* Add `--max-retries` flag
8+
* Go 1.13.5
9+
310
## 1.5.0 (2019/11/11)
411

512
* Seconds field is now optional

cmd/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func main() {
2323
// Parse command line
2424
kingpin.Flag("config", "ddns-route53 configuration file.").Envar("CONFIG").Required().StringVar(&flags.Cfgfile)
2525
kingpin.Flag("schedule", "CRON expression format.").Envar("SCHEDULE").StringVar(&flags.Schedule)
26+
kingpin.Flag("max-retries", "Number of retries in case of WAN IP retrieval failure.").Envar("MAX_RETRIES").Default("3").IntVar(&flags.MaxRetries)
2627
kingpin.Flag("timezone", "Timezone assigned to ddns-route53.").Envar("TZ").Default("UTC").StringVar(&flags.Timezone)
2728
kingpin.Flag("log-level", "Set log level.").Envar("LOG_LEVEL").Default("info").StringVar(&flags.LogLevel)
2829
kingpin.Flag("log-json", "Enable JSON logging output.").Envar("LOG_JSON").Default("false").BoolVar(&flags.LogJson)

doc/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ route53:
2525
* `secret_access_key`: AWS Secret Key.
2626
* `route53`
2727
* `hosted_zone_id`: AWS Route53 hosted zone ID.
28-
* `records_set`: Map of records set.
28+
* `records_set`: Slice of records set.
2929
* `name`: AWS Route53 record set name (don't forget to add a dot at the end).
3030
* `type`: AWS Route53 record set type, can be `A` or `AAAA`.
3131
* `ttl`: AWS Route53 record TTL (time to live) in seconds.

doc/install/binary.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ After getting the binary, it can be tested with `./ddns-route53 --help` or moved
1818
$ ./ddns-route53 --help
1919
usage: ddns-route53 --config=CONFIG [<flags>]
2020
21-
Dynamic DNS for Amazon Route 53‎ on a time-based schedule. More info on
21+
Dynamic DNS for Amazon Route 53‎ on a time-based schedule. More info:
2222
https://github.com/crazy-max/ddns-route53
2323
2424
Flags:
2525
--help Show context-sensitive help (also try --help-long and
2626
--help-man).
2727
--config=CONFIG ddns-route53 configuration file.
2828
--schedule=SCHEDULE CRON expression format.
29+
--max-retries=3 Number of retries in case of WAN IP retrieval failure.
2930
--timezone="UTC" Timezone assigned to ddns-route53.
3031
--log-level="info" Set log level.
3132
--log-json Enable JSON logging output.

doc/install/docker.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Environment variables can be used within your container:
2222

2323
* `TZ` : Timezone assigned to ddns-route53
2424
* `SCHEDULE` : [CRON expression](https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format) to schedule ddns-route53
25+
* `MAX_RETRIES` : Number of retries in case of WAN IP retrieval failure (default `3`)
2526
* `LOG_LEVEL` : Log level output (default `info`)
2627
* `LOG_JSON`: Enable JSON logging output (default `false`)
2728

doc/usage.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* `--version` : Show version and exit. _Optional_.
99
* `--config <path>` : ddns-route53 YAML configuration file. **Required**. (example: `ddns-route53.yml`).
1010
* `--schedule <cron expression>` : [CRON expression](https://godoc.org/github.com/robfig/cron#hdr-CRON_Expression_Format) to schedule ddns-route53. _Optional_. (example: `*/30 * * * *`).
11+
* `--max-retries <nb of retries>` : Number of retries in case of WAN IP retrieval failure. _Optional_. (example: `3`).
1112
* `--timezone <timezone>` : Timezone assigned to ddns-route53. _Optional_. (default: `UTC`).
1213
* `--log-level <level>` : Log level output. _Optional_. (default: `info`).
1314
* `--log-json` : Enable JSON logging output. _Optional_. (default: `false`).

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ require (
66
github.com/alecthomas/kingpin v0.0.0-20190816080609-dce89ec0b9f1
77
github.com/aws/aws-sdk-go v1.26.6
88
github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84
9+
github.com/jpillora/backoff v1.0.0
10+
github.com/pkg/errors v0.8.1
911
github.com/robfig/cron/v3 v3.0.0
1012
github.com/rs/zerolog v1.17.2
1113
gopkg.in/yaml.v3 v3.0.0-20190924164351-c8b7dadae555

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84 h1:RvcDqcKLua4b/jtXez
1313
github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
1414
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
1515
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
16+
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
17+
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
18+
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
1619
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
1720
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1821
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package app
22

33
import (
44
"fmt"
5+
"net"
6+
"runtime"
7+
"strings"
58
"sync/atomic"
69
"time"
710

@@ -10,7 +13,7 @@ import (
1013
"github.com/aws/aws-sdk-go/aws/session"
1114
"github.com/aws/aws-sdk-go/service/route53"
1215
"github.com/crazy-max/ddns-route53/internal/config"
13-
"github.com/crazy-max/ddns-route53/internal/utl"
16+
"github.com/crazy-max/ddns-route53/pkg/identme"
1417
"github.com/hako/durafmt"
1518
"github.com/robfig/cron/v3"
1619
"github.com/rs/zerolog/log"
@@ -22,9 +25,10 @@ type Client struct {
2225
loc *time.Location
2326
cron *cron.Cron
2427
r53 *route53.Route53
28+
im *identme.Client
2529
jobID cron.EntryID
26-
lastIPv4 string
27-
lastIPv6 string
30+
lastIPv4 net.IP
31+
lastIPv6 net.IP
2832
locker uint32
2933
}
3034

@@ -50,6 +54,10 @@ func New(cfg *config.Configuration, loc *time.Location) (*Client, error) {
5054
cron.SecondOptional|cron.Minute|cron.Hour|cron.Dom|cron.Month|cron.Dow|cron.Descriptor),
5155
)),
5256
r53: route53.New(sess, &aws.Config{Credentials: creds}),
57+
im: identme.NewClient(
58+
fmt.Sprintf("ddns-route53/%s go/%s %s", cfg.App.Version, runtime.Version()[2:], strings.Title(runtime.GOOS)),
59+
cfg.Flags.MaxRetries,
60+
),
5361
}, nil
5462
}
5563

@@ -95,56 +103,57 @@ func (c *Client) Run() {
95103
c.cron.Entry(c.jobID).Next)
96104
}
97105

98-
// Get current WAN IP
99-
wanIPv4 := ""
106+
var wanIPv4 net.IP
100107
if c.cfg.Route53.HandleIPv4 {
101-
wanIPv4, err = utl.WanIPv4()
108+
wanIPv4, err = c.im.IPv4()
102109
if err != nil {
103-
log.Warn().Err(err).Msg("Cannot get WAN IPv4 address")
110+
log.Error().Err(err).Msg("Cannot retrieve WAN IPv4 address")
104111
} else {
105112
log.Info().Msgf("Current WAN IPv4: %s", wanIPv4)
106113
}
107-
} else {
108-
log.Debug().Msg("")
109114
}
110115

111-
wanIPv6 := ""
116+
var wanIPv6 net.IP
112117
if c.cfg.Route53.HandleIPv6 {
113-
wanIPv6, err = utl.WanIPv6()
118+
wanIPv6, err = c.im.IPv6()
114119
if err != nil {
115-
log.Warn().Err(err).Msg("Cannot get WAN IPv6 address")
120+
log.Error().Err(err).Msg("Cannot retrieve WAN IPv6 address")
116121
} else {
117122
log.Info().Msgf("Current WAN IPv6: %s", wanIPv6)
118123
}
119124
}
120125

121-
// Skip if last IP is identical
122-
if wanIPv4 == c.lastIPv4 && wanIPv6 == c.lastIPv6 {
123-
log.Info().Msg("WAN IPv4/IPv6 addresses have not changed since the last update. Skipping...")
126+
if wanIPv4 == nil && wanIPv6 == nil {
127+
return
128+
}
129+
130+
// Skip if last IP is identical or empty
131+
if wanIPv4.Equal(c.lastIPv4) && wanIPv6.Equal(c.lastIPv6) {
132+
log.Info().Msg("WAN IPv4/IPv6 addresses have not changed since last update. Skipping...")
124133
return
125134
}
126135

127136
// Create Route53 changes
128137
r53Changes := make([]*route53.Change, len(c.cfg.Route53.RecordsSet))
129138
for i, rs := range c.cfg.Route53.RecordsSet {
130-
if wanIPv4 == "" && rs.Type == route53.RRTypeA {
139+
if wanIPv4 == nil && rs.Type == route53.RRTypeA {
131140
log.Error().Msgf("No WAN IPv4 address available to update %s record", rs.Name)
132141
continue
133-
} else if wanIPv6 == "" && rs.Type == route53.RRTypeAaaa {
142+
} else if wanIPv6 == nil && rs.Type == route53.RRTypeAaaa {
134143
log.Error().Msgf("No WAN IPv6 address available to update %s record", rs.Name)
135144
continue
136145
}
137-
wanIP := wanIPv4
146+
recordValue := aws.String(wanIPv4.String())
138147
if rs.Type == route53.RRTypeAaaa {
139-
wanIP = wanIPv6
148+
recordValue = aws.String(wanIPv6.String())
140149
}
141150
r53Changes[i] = &route53.Change{
142151
Action: aws.String("UPSERT"),
143152
ResourceRecordSet: &route53.ResourceRecordSet{
144153
Name: aws.String(rs.Name),
145154
Type: aws.String(rs.Type),
146155
TTL: aws.Int64(rs.TTL),
147-
ResourceRecords: []*route53.ResourceRecord{{Value: aws.String(wanIP)}},
156+
ResourceRecords: []*route53.ResourceRecord{{Value: recordValue}},
148157
},
149158
}
150159
}

0 commit comments

Comments
 (0)