Skip to content

Commit

Permalink
Query CNAME before setting the TXT record
Browse files Browse the repository at this point in the history
CNAME can be used to delegate answering the chanllenge to another DNS
zone, in order to reduce the exposure of the DNS credential [1]. The
solver already follows CNAME when checking propagation against the
authoritative source, it should follow CNAME when setting the TXT record
as well.

[1] https://letsencrypt.org/docs/challenge-types/#dns-01-challenge
  • Loading branch information
crccw committed Dec 28, 2021
1 parent 9b2c6ac commit 0138270
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
27 changes: 27 additions & 0 deletions dnsutil.go
Expand Up @@ -328,6 +328,33 @@ func recursiveNameservers(custom []string) []string {
return servers
}

// Follows CNAME records and returns the canonical name. The function
// supports CNAME pointing to another CNAME.
func followCName(fqdn string, nameservers []string) (string, error) {
if !strings.HasSuffix(fqdn, ".") {
fqdn += "."
}
cname, err := dnsQuery(fqdn, dns.TypeCNAME, nameservers, true)
if err != nil {
return "", err
}
switch cname.Rcode {
case dns.RcodeSuccess:
canoncialFqdn := updateDomainWithCName(cname, fqdn)
if canoncialFqdn == fqdn {
return canoncialFqdn, nil
}
return followCName(canoncialFqdn, nameservers)
case dns.RcodeNameError:
// It's OK if the FQDN doesn't exist. This is possible during the
// DNS-01 chanllenge. The solver will create a TXT record for the
// FQDN.
return fqdn, nil
default:
return "", fmt.Errorf("got error when querying CNAME for domain %q: %v", fqdn, cname.Rcode)
}
}

var defaultNameservers = []string{
"8.8.8.8:53",
"8.8.4.4:53",
Expand Down
6 changes: 6 additions & 0 deletions solvers.go
Expand Up @@ -268,6 +268,12 @@ func (s *DNS01Solver) Present(ctx context.Context, challenge acme.Challenge) err
// https://github.com/caddyserver/caddy/issues/3474
activeDNSChallenges.Lock(dnsName)

resolvers := recursiveNameservers(s.Resolvers)

dnsName, err := followCName(dnsName, resolvers)
if err != nil {
return fmt.Errorf("could not query CNAME for domain %q: %v", dnsName, err)
}
zone, err := findZoneByFQDN(dnsName, recursiveNameservers(s.Resolvers))
if err != nil {
return fmt.Errorf("could not determine zone for domain %q: %v", dnsName, err)
Expand Down

0 comments on commit 0138270

Please sign in to comment.