Skip to content

Commit

Permalink
feat(provider): happy eyeballs for 1.1.1.1 and 1.0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
favonia committed Aug 23, 2024
1 parent bf0361c commit 140b7fc
Show file tree
Hide file tree
Showing 41 changed files with 724 additions and 546 deletions.
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# We use cross-compilation because QEMU is slow.
FROM --platform=${BUILDPLATFORM} golang:1.22.3-alpine3.18@sha256:d1a601b64de09e2fa38c95e55838961811d5ca11062a8f4230a5c434b3ae2a34 AS build
FROM --platform=${BUILDPLATFORM} golang:1.23.0-alpine3.20@sha256:d0b31558e6b3e4cc59f6011d79905835108c919143ebecc58f35965bf79948f4 AS build

ARG GIT_DESCRIBE
ARG TARGETOS
ARG TARGETARCH
Expand Down
4 changes: 2 additions & 2 deletions cmd/ddns/ddns.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func realMain() int { //nolint:funlen
// We still want to keep the quiet mode extremely quiet for the single-run mode (UPDATE_CRON=@once),
// hence we are checking whether cron is enabled or not. (The single-run mode is defined as
// having the internal cron disabled.)
if c.UpdateCron != nil && ppfmt.Verbosity() <= pp.Quiet {
if c.UpdateCron != nil && ppfmt.IsShowing(pp.Verbose) {

Check warning on line 113 in cmd/ddns/ddns.go

View check run for this annotation

Codecov / codecov/patch

cmd/ddns/ddns.go#L113

Added line #L113 was not covered by tests
ppfmt.Noticef(pp.EmojiMute, "Quiet mode enabled")
}

Expand Down Expand Up @@ -165,7 +165,7 @@ func realMain() int { //nolint:funlen

signaled:
// Wait for the next signal or the alarm, whichever comes first
if sig.ReportSignalsUntil(ppfmt, next) {
if sig.WaitForSignalsUntil(ppfmt, next) {

Check warning on line 168 in cmd/ddns/ddns.go

View check run for this annotation

Codecov / codecov/patch

cmd/ddns/ddns.go#L168

Added line #L168 was not covered by tests
stopUpdating(ctx, ppfmt, c, s)
monitor.ExitStatusAll(ctx, ppfmt, c.Monitors, 0, "Stopped")
if c.UpdateCron != nil {
Expand Down
7 changes: 5 additions & 2 deletions docs/DESIGN.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Principles and Priorities

Be the 🌟 best DDNS updater 🌟 that [favonia](mailto:favonia+github@gmail.com) wants to use.
Be the 🌟 best DDNS updater 🌟 that [favonia](mailto:favonia+github@gmail.com) (me) wants to use.

1. Support all features [favonia](mailto:favonia+github@gmail.com) wants, including emojis.

Expand All @@ -25,9 +25,12 @@ Be the 🌟 best DDNS updater 🌟 that [favonia](mailto:favonia+github@gmail.co

The source code follows the [standard Go project layout](https://github.com/golang-standards/project-layout), where `/cmd/` holds the command-line interface and `/internal/` holds the internal packages. The updater is factored into many internal packages, each in charged of a small part of the program logic. See the [Go Reference](https://pkg.go.dev/github.com/favonia/cloudflare-ddns/) for a detailed documentation of the code structure.

### Logging Message Convention
### Coding Convention

Here is some arbitrary coding convention that I chose to follow. It may change in the future, but the whole codebase should be consistent with it at any time:

1. Cloudflare IDs (zone IDs, DNS record IDs, etc.) are already designed to use only “very safe” characters and should not be quoted. The formatter `%s` should be used instead of `%q`.
2. A variable name of type `map[..]...` is not in a plural form just because it is of type `map[...]...`. For example, a mapping from IP networks to detected IPs should be named `detectedIP` not `detectedIPs`.

## Network Security Threat Model

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/favonia/cloudflare-ddns

go 1.22.0
go 1.23.0 // with patch version to satisfy CodeQL

require (
github.com/cloudflare/cloudflare-go v0.102.0
Expand Down
6 changes: 3 additions & 3 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
type Config struct {
Auth api.Auth
Provider map[ipnet.Type]provider.Provider
ShouldWeUse1001 *bool
ShouldWeUsePrimary map[ipnet.Type]*bool
Domains map[ipnet.Type][]domain.Domain
WAFLists []api.WAFList
UpdateCron cron.Schedule
Expand All @@ -44,7 +44,7 @@ func Default() *Config {
ipnet.IP4: provider.NewCloudflareTrace(),
ipnet.IP6: provider.NewCloudflareTrace(),
},
ShouldWeUse1001: nil,
ShouldWeUsePrimary: map[ipnet.Type]*bool{},
Domains: map[ipnet.Type][]domain.Domain{
ipnet.IP4: nil,
ipnet.IP6: nil,
Expand All @@ -59,8 +59,8 @@ func Default() *Config {
Proxied: map[domain.Domain]bool{},
RecordComment: "",
WAFListDescription: "",
UpdateTimeout: time.Second * 30, //nolint:mnd
DetectionTimeout: time.Second * 5, //nolint:mnd
UpdateTimeout: time.Second * 30, //nolint:mnd
Monitors: nil,
Notifiers: nil,
}
Expand Down
2 changes: 1 addition & 1 deletion internal/config/config_print.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func computeInverseMap[V comparable](m map[domain.Domain]V) ([]V, map[V][]domain

// Print prints the Config on the screen.
func (c *Config) Print(ppfmt pp.PP) {
if ppfmt.Verbosity() < pp.Info {
if !ppfmt.IsShowing(pp.Info) {
return
}

Expand Down
8 changes: 4 additions & 4 deletions internal/config/config_print_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestPrintDefault(t *testing.T) {
mockPP := mocks.NewMockPP(mockCtrl)
innerMockPP := mocks.NewMockPP(mockCtrl)
gomock.InOrder(
mockPP.EXPECT().Verbosity().Return(pp.Info),
mockPP.EXPECT().IsShowing(pp.Info).Return(true),
mockPP.EXPECT().Infof(pp.EmojiEnvVars, "Current settings:"),
mockPP.EXPECT().Indent().Return(mockPP),
mockPP.EXPECT().Indent().Return(innerMockPP),
Expand Down Expand Up @@ -66,7 +66,7 @@ func TestPrintValues(t *testing.T) {
mockPP := mocks.NewMockPP(mockCtrl)
innerMockPP := mocks.NewMockPP(mockCtrl)
gomock.InOrder(
mockPP.EXPECT().Verbosity().Return(pp.Info),
mockPP.EXPECT().IsShowing(pp.Info).Return(true),
mockPP.EXPECT().Infof(pp.EmojiEnvVars, "Current settings:"),
mockPP.EXPECT().Indent().Return(mockPP),
mockPP.EXPECT().Indent().Return(innerMockPP),
Expand Down Expand Up @@ -138,7 +138,7 @@ func TestPrintEmpty(t *testing.T) {
mockPP := mocks.NewMockPP(mockCtrl)
innerMockPP := mocks.NewMockPP(mockCtrl)
gomock.InOrder(
mockPP.EXPECT().Verbosity().Return(pp.Info),
mockPP.EXPECT().IsShowing(pp.Info).Return(true),
mockPP.EXPECT().Infof(pp.EmojiEnvVars, "Current settings:"),
mockPP.EXPECT().Indent().Return(mockPP),
mockPP.EXPECT().Indent().Return(innerMockPP),
Expand Down Expand Up @@ -171,7 +171,7 @@ func TestPrintHidden(t *testing.T) {
store(t, "TZ", "UTC")

mockPP := mocks.NewMockPP(mockCtrl)
mockPP.EXPECT().Verbosity().Return(pp.Notice)
mockPP.EXPECT().IsShowing(pp.Info).Return(false)

var cfg config.Config
cfg.Print(mockPP)
Expand Down
35 changes: 31 additions & 4 deletions internal/config/config_read.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package config

import (
"maps"

"github.com/favonia/cloudflare-ddns/internal/api"
"github.com/favonia/cloudflare-ddns/internal/domain"
"github.com/favonia/cloudflare-ddns/internal/domainexp"
Expand All @@ -15,7 +17,7 @@ import (
// - output-related ones (QUIET and EMOJI)
// One should subsequently call [Config.Normalize] to restore invariants across fields.
func (c *Config) ReadEnv(ppfmt pp.PP) bool {
if ppfmt.Verbosity() >= pp.Info {
if ppfmt.IsShowing(pp.Info) {
ppfmt.Infof(pp.EmojiEnvVars, "Reading settings . . .")
ppfmt = ppfmt.Indent()
}
Expand Down Expand Up @@ -48,7 +50,7 @@ func (c *Config) ReadEnv(ppfmt pp.PP) bool {
//
//nolint:funlen
func (c *Config) Normalize(ppfmt pp.PP) bool {
if ppfmt.Verbosity() >= pp.Info {
if ppfmt.IsShowing(pp.Info) {
ppfmt.Infof(pp.EmojiEnvVars, "Checking settings . . .")
ppfmt = ppfmt.Indent()
}
Expand Down Expand Up @@ -121,7 +123,7 @@ func (c *Config) Normalize(ppfmt pp.PP) bool {
}
}

// Step 4: fill in proxiedMap
// Step 4: regenerate proxiedMap from [Config.Proxied]
proxiedMap := map[domain.Domain]bool{}
if len(activeDomainSet) > 0 {
proxiedPredicate, ok := domainexp.ParseExpression(ppfmt, "PROXIED", c.ProxiedTemplate)
Expand Down Expand Up @@ -155,8 +157,33 @@ func (c *Config) Normalize(ppfmt pp.PP) bool {
}
}

// Part 6: override the old values
// Part 6: Fill in missing [Config.ShouldWeUsePrimary] items:
// if a provider does not have alternatives,
// then [Config.ShouldWeUsePrimary] should give true.
shouldWeUsePrimary := map[ipnet.Type]*bool{}
maps.Copy(shouldWeUsePrimary, c.ShouldWeUsePrimary)
for ipNet, p := range providerMap {
if shouldWeUsePrimary[ipNet] == nil && !p.HasAlternative(ipNet) {
t := true
shouldWeUsePrimary[ipNet] = &t
}
}

// Part 7: Warn about short DetectionTimeout
if c.DetectionTimeout <= AlternativeDetectionDelay {
for ipNet, p := range providerMap {
if p.HasAlternative(ipNet) {
ppfmt.Noticef(pp.EmojiUserWarning,
"DETECTION_TIMEOUT=%s is too short for trying 1.0.0.1 (when 1.1.1.1 does not work)", c.DetectionTimeout)
ShowHintForTrying1001(ppfmt)
break
}
}
}

// Final Part: override the old values
c.Provider = providerMap
c.ShouldWeUsePrimary = shouldWeUsePrimary
c.Proxied = proxiedMap

return true
Expand Down
Loading

0 comments on commit 140b7fc

Please sign in to comment.