diff --git a/acme/dns_challenge.go b/acme/dns_challenge.go index 61d0df5a..198a1bcb 100644 --- a/acme/dns_challenge.go +++ b/acme/dns_challenge.go @@ -9,8 +9,18 @@ import ( "net/http" "strings" "time" + + "github.com/miekg/dns" ) +type preCheckDNSFunc func() bool + +var preCheckDNS = func() bool { + return true +} + +var preCheckDNSFallbackCount = 5 + // DNSProvider represents a service for creating dns records. type DNSProvider interface { // CreateTXT creates a TXT record @@ -44,6 +54,43 @@ func (s *dnsChallenge) Solve(chlng challenge, domain string) error { return err } + if preCheckDNS() { + // check if the expected DNS entry was created. If not wait for some time and try again. + m := new(dns.Msg) + m.SetQuestion(domain+".", dns.TypeSOA) + c := new(dns.Client) + in, _, err := c.Exchange(m, "8.8.8.8:53") + if err != nil { + return err + } + + var authorativeNS string + for _, answ := range in.Answer { + soa := answ.(*dns.SOA) + authorativeNS = soa.Ns + } + + fallbackCnt := 0 + for fallbackCnt < preCheckDNSFallbackCount { + m.SetQuestion(fqdn, dns.TypeTXT) + in, _, err = c.Exchange(m, authorativeNS+":53") + if err != nil { + return err + } + + if len(in.Answer) > 0 { + break + } + + fallbackCnt++ + if fallbackCnt >= preCheckDNSFallbackCount { + return errors.New("Could not retrieve the value from DNS in a timely manner. Aborting.") + } + + time.Sleep(time.Second * time.Duration(fallbackCnt)) + } + } + jsonBytes, err := json.Marshal(challenge{Resource: "challenge", Type: chlng.Type, Token: chlng.Token, KeyAuthorization: keyAuth}) if err != nil { return errors.New("Failed to marshal network message...") diff --git a/acme/dns_challenge_test.go b/acme/dns_challenge_test.go index 567391e6..e69d7c4b 100644 --- a/acme/dns_challenge_test.go +++ b/acme/dns_challenge_test.go @@ -11,6 +11,9 @@ import ( ) func TestDNSValidServerResponse(t *testing.T) { + preCheckDNS = func() bool { + return false + } privKey, _ := generatePrivateKey(rsakey, 512) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {