Skip to content

Commit

Permalink
Add a flag to enable strict DNS resolution
Browse files Browse the repository at this point in the history
This commit adds a flag to enable strict DNS resolution on ACME
challenges.
  • Loading branch information
maraino committed Jul 12, 2024
1 parent 0a9dd62 commit 21d73a5
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 23 deletions.
11 changes: 9 additions & 2 deletions acme/challenge.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ var (
//
// This variable can be used for testing purposes.
InsecurePortTLSALPN01 int

// StrictFQDN allows to enforce a fully qualified domain name in the DNS
// resolution. By default it allows domain resolution using a search list
// defined in the resolv.conf or similar configuration.
StrictFQDN bool
)

// Challenge represents an ACME response Challenge type.
Expand Down Expand Up @@ -163,8 +168,10 @@ func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWeb

// rootedName adds a trailing "." to a given domain name.
func rootedName(name string) string {
if name == "" || name[len(name)-1] != '.' {
return name + "."
if StrictFQDN {
if name == "" || name[len(name)-1] != '.' {
return name + "."
}
}
return name
}
Expand Down
78 changes: 57 additions & 21 deletions acme/challenge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2767,19 +2767,34 @@ func Test_serverName(t *testing.T) {

func Test_http01ChallengeHost(t *testing.T) {
tests := []struct {
name string
value string
want string
name string
strictFQDN bool
value string
want string
}{
{
name: "dns",
value: "www.example.com",
want: "www.example.com.",
name: "dns",
strictFQDN: false,
value: "www.example.com",
want: "www.example.com",
},
{
name: "rooted dns",
value: "www.example.com.",
want: "www.example.com.",
name: "dns strict",
strictFQDN: true,
value: "www.example.com",
want: "www.example.com.",
},
{
name: "rooted dns",
strictFQDN: false,
value: "www.example.com.",
want: "www.example.com.",
},
{
name: "rooted dns strict",
strictFQDN: true,
value: "www.example.com.",
want: "www.example.com.",
},
{
name: "ipv4",
Expand All @@ -2794,6 +2809,11 @@ func Test_http01ChallengeHost(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmp := StrictFQDN
t.Cleanup(func() {
StrictFQDN = tmp
})
StrictFQDN = tt.strictFQDN
if got := http01ChallengeHost(tt.value); got != tt.want {
t.Errorf("http01ChallengeHost() = %v, want %v", got, tt.want)
}
Expand Down Expand Up @@ -4500,17 +4520,25 @@ func Test_tlsAlpn01ChallengeHost(t *testing.T) {
name string
}
tests := []struct {
name string
args args
want string
name string
strictFQDN bool
args args
want string
}{
{"dns", args{"smallstep.com"}, "smallstep.com."},
{"rooted dns", args{"smallstep.com."}, "smallstep.com."},
{"ipv4", args{"1.2.3.4"}, "1.2.3.4"},
{"ipv6", args{"2607:f8b0:4023:1009::71"}, "2607:f8b0:4023:1009::71"},
{"dns", false, args{"smallstep.com"}, "smallstep.com"},
{"dns strict", true, args{"smallstep.com"}, "smallstep.com."},
{"rooted dns", false, args{"smallstep.com."}, "smallstep.com."},
{"rooted dns strict", true, args{"smallstep.com."}, "smallstep.com."},
{"ipv4", true, args{"1.2.3.4"}, "1.2.3.4"},
{"ipv6", true, args{"2607:f8b0:4023:1009::71"}, "2607:f8b0:4023:1009::71"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmp := StrictFQDN
t.Cleanup(func() {
StrictFQDN = tmp
})
StrictFQDN = tt.strictFQDN
assert.Equal(t, tt.want, tlsAlpn01ChallengeHost(tt.args.name))
})
}
Expand All @@ -4521,15 +4549,23 @@ func Test_dns01ChallengeHost(t *testing.T) {
domain string
}
tests := []struct {
name string
args args
want string
name string
strictFQDN bool
args args
want string
}{
{"dns", args{"smallstep.com"}, "_acme-challenge.smallstep.com."},
{"rooted dns", args{"smallstep.com."}, "_acme-challenge.smallstep.com."},
{"dns", false, args{"smallstep.com"}, "_acme-challenge.smallstep.com"},
{"dns strict", true, args{"smallstep.com"}, "_acme-challenge.smallstep.com."},
{"rooted dns", false, args{"smallstep.com."}, "_acme-challenge.smallstep.com."},
{"rooted dns strict", true, args{"smallstep.com."}, "_acme-challenge.smallstep.com."},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmp := StrictFQDN
t.Cleanup(func() {
StrictFQDN = tmp
})
StrictFQDN = tt.strictFQDN
assert.Equal(t, tt.want, dns01ChallengeHost(tt.args.domain))
})
}
Expand Down
7 changes: 7 additions & 0 deletions commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ Requires **--insecure** flag.`,
Usage: `the <port> used on tls-alpn-01 challenges. It can be changed for testing purposes.
Requires **--insecure** flag.`,
},
cli.BoolFlag{
Name: "acme-strict-fqdn",
Usage: `enable strict DNS resolution using a fully qualified domain name.`,
},
cli.StringFlag{
Name: "pidfile",
Usage: "the path to the <file> to write the process ID.",
Expand Down Expand Up @@ -125,6 +129,9 @@ func appAction(ctx *cli.Context) error {
return fmt.Errorf("flag '--acme-tls-port' requires the '--insecure' flag")
}
}
if acmeStrictFQDN := ctx.Bool("acme-strict-fqdn"); acmeStrictFQDN {
acme.StrictFQDN = acmeStrictFQDN
}

// Allow custom contexts.
if caCtx := ctx.String("context"); caCtx != "" {
Expand Down

0 comments on commit 21d73a5

Please sign in to comment.