From 348b6f37210277d253918183741327b386d315bf Mon Sep 17 00:00:00 2001 From: Matthew Horan Date: Fri, 8 Feb 2019 23:02:58 -0500 Subject: [PATCH] Resolve CNAME when creating dns-01 challenge (#791) * Resolve CNAME when creating dns-01 challenge It may be desirable to host the dns-01 challenge in a zone other than the one where the challenge is presented. For example, when validating a.example.com, the challenge may need to live on example.org. This change resolves CNAMEs encountered when determining the FQDN of the challenge, and replaces them with the alias. This PR is based on the original work in #584. Co-authored-by: Gurvinder Singh * review: feature-flip. * review: restore acmedns test. --- challenge/dns01/cname.go | 16 ++++++++++++++++ challenge/dns01/dns_challenge.go | 12 ++++++++++++ challenge/dns01/precheck.go | 10 +--------- 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 challenge/dns01/cname.go diff --git a/challenge/dns01/cname.go b/challenge/dns01/cname.go new file mode 100644 index 00000000..619c8476 --- /dev/null +++ b/challenge/dns01/cname.go @@ -0,0 +1,16 @@ +package dns01 + +import "github.com/miekg/dns" + +// Update FQDN with CNAME if any +func updateDomainWithCName(r *dns.Msg, fqdn string) string { + for _, rr := range r.Answer { + if cn, ok := rr.(*dns.CNAME); ok { + if cn.Hdr.Name == fqdn { + return cn.Target + } + } + } + + return fqdn +} diff --git a/challenge/dns01/dns_challenge.go b/challenge/dns01/dns_challenge.go index b780d8f2..68c79589 100644 --- a/challenge/dns01/dns_challenge.go +++ b/challenge/dns01/dns_challenge.go @@ -4,8 +4,11 @@ import ( "crypto/sha256" "encoding/base64" "fmt" + "os" + "strconv" "time" + "github.com/miekg/dns" "github.com/xenolf/lego/acme" "github.com/xenolf/lego/acme/api" "github.com/xenolf/lego/challenge" @@ -172,5 +175,14 @@ func GetRecord(domain, keyAuth string) (fqdn string, value string) { // base64URL encoding without padding value = base64.RawURLEncoding.EncodeToString(keyAuthShaBytes[:sha256.Size]) fqdn = fmt.Sprintf("_acme-challenge.%s.", domain) + + if ok, _ := strconv.ParseBool(os.Getenv("LEGO_EXPERIMENTAL_CNAME_SUPPORT")); ok { + r, err := dnsQuery(fqdn, dns.TypeCNAME, recursiveNameservers, true) + // Check if the domain has CNAME then return that + if err == nil && r.Rcode == dns.RcodeSuccess { + fqdn = updateDomainWithCName(r, fqdn) + } + } + return } diff --git a/challenge/dns01/precheck.go b/challenge/dns01/precheck.go index 63b72cef..c3389110 100644 --- a/challenge/dns01/precheck.go +++ b/challenge/dns01/precheck.go @@ -60,15 +60,7 @@ func (p preCheck) checkDNSPropagation(fqdn, value string) (bool, error) { } if r.Rcode == dns.RcodeSuccess { - // If we see a CNAME here then use the alias - for _, rr := range r.Answer { - if cn, ok := rr.(*dns.CNAME); ok { - if cn.Hdr.Name == fqdn { - fqdn = cn.Target - break - } - } - } + fqdn = updateDomainWithCName(r, fqdn) } authoritativeNss, err := lookupNameservers(fqdn)