Skip to content

Commit 4459693

Browse files
committed
Handle mismatch in DNS record
1 parent 4043075 commit 4459693

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dns
1+
package cloudflare
22

33
import (
44
"context"
@@ -8,8 +8,34 @@ import (
88
"github.com/rs/zerolog/log"
99
)
1010

11-
// UpdateCloudFlare updates the CloudFlare DNS record
12-
func UpdateCloudFlare(ctx context.Context, token, domain, record, ip string) error {
11+
// Get fetches the IP of the given record, returning empty string if it doesn't exist
12+
func Get(ctx context.Context, token, domain, record string) (string, error) {
13+
api, err := cloudflare.NewWithAPIToken(token)
14+
if err != nil {
15+
return "", errors.Annotate(err, "unable to connect to CloudFlare, token may be invalid")
16+
}
17+
// Get the zone ID for the domain
18+
zoneID, err := api.ZoneIDByName(domain)
19+
if err != nil {
20+
return "", errors.Annotatef(err, "unable to retrieve zone ID for domain '%s' from CloudFlare", domain)
21+
}
22+
// Get the record ID
23+
records, err := api.DNSRecords(ctx, zoneID, cloudflare.DNSRecord{Type: "A"})
24+
if err != nil {
25+
return "", errors.Annotate(err, "unable to retrieve zone ID from CloudFlare")
26+
}
27+
// Find the specific record
28+
for _, r := range records {
29+
log.Debug().Msgf("Examining DNS record ID '%s' with name '%s'", r.ID, r.Name)
30+
if r.Name == record {
31+
return r.Content, nil
32+
}
33+
}
34+
return "", nil
35+
}
36+
37+
// Update updates the CloudFlare DNS record
38+
func Update(ctx context.Context, token, domain, record, ip string) error {
1339
api, err := cloudflare.NewWithAPIToken(token)
1440
if err != nil {
1541
return errors.Annotate(err, "unable to connect to CloudFlare, token may be invalid")

ddns/ddns.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"time"
66

77
"github.com/juju/errors"
8+
"github.com/mattolenik/cloudflare-ddns-client/cloudflare"
89
"github.com/mattolenik/cloudflare-ddns-client/conf"
9-
"github.com/mattolenik/cloudflare-ddns-client/dns"
1010
"github.com/mattolenik/cloudflare-ddns-client/ip"
1111
"github.com/rs/zerolog/log"
1212
)
@@ -18,7 +18,7 @@ func Run(ctx context.Context) error {
1818
return errors.Annotate(err, "unable to retrieve public IP")
1919
}
2020
log.Info().Msgf("Found public IP '%s'", ip)
21-
err = dns.UpdateCloudFlare(
21+
err = cloudflare.Update(
2222
ctx,
2323
conf.Token.Get(),
2424
conf.Domain.Get(),
@@ -45,13 +45,23 @@ func Daemon(ctx context.Context, updatePeriod, failureRetryDelay time.Duration)
4545
log.Info().Msgf("Daemon running, will now monitor for IP updates every %d seconds", int(updatePeriod.Seconds()))
4646

4747
for {
48+
dnsRecordIP, err := cloudflare.Get(
49+
ctx,
50+
conf.Token.Get(),
51+
conf.Domain.Get(),
52+
conf.Record.Get())
53+
if err != nil {
54+
log.Error().Msgf("unable to look up current DNS record, will retry in %d seconds", int(updatePeriod.Seconds()))
55+
time.Sleep(failureRetryDelay)
56+
continue
57+
}
4858
newIP, err := ip.GetPublicIPWithRetry(10, 5*time.Second)
4959
if err != nil {
5060
log.Error().Msgf("unable to retrieve public IP, will retry in %d seconds", int(updatePeriod.Seconds()))
5161
time.Sleep(failureRetryDelay)
5262
continue
5363
}
54-
if newIP == lastIP {
64+
if newIP == lastIP && newIP == dnsRecordIP {
5565
log.Info().Msgf(
5666
"No IP change detected since %s (%d seconds ago)",
5767
lastIPUpdate.Format(time.RFC1123Z),
@@ -60,14 +70,19 @@ func Daemon(ctx context.Context, updatePeriod, failureRetryDelay time.Duration)
6070
continue
6171
}
6272
if lastIP == "" {
63-
log.Info().Msgf("Found public IP '%s'", lastIP)
73+
// Log line for first time
74+
log.Info().Msgf("Found public IP '%s'", newIP)
6475
} else if newIP != lastIP {
76+
// Log line for IP change
6577
log.Info().Msgf("Detected new public IP address, it changed from '%s' to '%s'", lastIP, newIP)
78+
} else if dnsRecordIP != newIP {
79+
// Log line for no new IP, but mismatch with DNS record
80+
log.Info().Msgf("Public IP address did not change, but DNS record did match, is '%s' but expected '%s', correcting", dnsRecordIP, newIP)
6681
}
6782
lastIP = newIP
6883
lastIPUpdate = time.Now()
6984

70-
err = dns.UpdateCloudFlare(
85+
err = cloudflare.Update(
7186
ctx,
7287
conf.Token.Get(),
7388
conf.Domain.Get(),

0 commit comments

Comments
 (0)