From dc25fc421a66e59b130957d2db0f54b9af7367e0 Mon Sep 17 00:00:00 2001 From: Marius Kimmina Date: Tue, 23 Aug 2022 11:14:25 +0200 Subject: [PATCH] fixed CAA records timeout problem --- manager.go | 24 ++++++++++++------------ setup.go | 39 +++++++++++++++++++-------------------- solver.go | 28 +++++++++++----------------- solver_test.go | 2 +- 4 files changed, 43 insertions(+), 50 deletions(-) diff --git a/manager.go b/manager.go index 6e29fa9..acfb28d 100644 --- a/manager.go +++ b/manager.go @@ -16,9 +16,9 @@ import ( ) type ACMEManager struct { - Config *certmagic.Config - Issuer *certmagic.ACMEIssuer - Zone string + Config *certmagic.Config + Issuer *certmagic.ACMEIssuer + Zone string } // NewACMEManager create a new ACMEManager @@ -27,12 +27,12 @@ func NewACMEManager(config *dnsserver.Config, zone string, ca string, path strin ca = "localhost:14001/dir" //pebble default } - // default email if none is provided - // providing a reail email is recommended to receiv notifications for expiring certificates - // in case that something goes wrong - if email == "" { - email = "test@test.com" - } + // default email if none is provided + // providing a reail email is recommended to receiv notifications for expiring certificates + // in case that something goes wrong + if email == "" { + email = "test@test.com" + } pool, err := x509.SystemCertPool() if err != nil { @@ -46,7 +46,7 @@ func NewACMEManager(config *dnsserver.Config, zone string, ca string, path strin } pemcert, _ := pem.Decode(certbytes) if pemcert == nil { - log.Errorf("Failed to decode CaCert: %v \n", err) + log.Errorf("Failed to decode CaCert: %v \n", err) } cert, err := x509.ParseCertificate(pemcert.Bytes) if err != nil { @@ -57,7 +57,7 @@ func NewACMEManager(config *dnsserver.Config, zone string, ca string, path strin readyChan := make(chan string) solver := &DNSSolver{ - Port: port, + Port: port, readyChan: readyChan, } @@ -104,7 +104,7 @@ func (am *ACMEManager) configureTLSwithACME(ctx context.Context) (*tls.Config, * // try loading existing certificate cert, err = am.Config.CacheManagedCertificate(ctx, am.Zone) if err != nil { - log.Info("Obtaining TLS Certificate") + log.Info("Obtaining TLS Certificate, may take a moment") if !errors.Is(err, fs.ErrNotExist) { return nil, nil, err } diff --git a/setup.go b/setup.go index 5259617..3d127e1 100644 --- a/setup.go +++ b/setup.go @@ -36,13 +36,13 @@ var ( ) const ( - argDomain = "domain" - argCheckInternal = "checkinterval" - argCa = "ca" - argCaCert = "cacert" - argEmail = "email" - argCertPath = "certpath" - argPort = "port" + argDomain = "domain" + argCheckInternal = "checkinterval" + argCa = "ca" + argCaCert = "cacert" + argEmail = "email" + argCertPath = "certpath" + argPort = "port" ) func parseTLS(c *caddy.Controller) error { @@ -70,8 +70,8 @@ func parseTLS(c *caddy.Controller) error { var ca string var caCert string var port string - var email string - checkInterval := 15 + var email string + checkInterval := 15 userHome, homeExists := os.LookupEnv("HOME") if !homeExists { log.Error("Environment Variable $HOME needs to be set.") @@ -122,19 +122,18 @@ func parseTLS(c *caddy.Controller) error { if len(checkIntervalArgs) > 1 { return plugin.Error("tls", c.Errf("Too many arguments to checkInterval")) } - interval, err := strconv.Atoi(checkIntervalArgs[0]) - if err != nil { - return plugin.Error("Failed to convert checkInterval argument to integer: %v \n", err) - } - checkInterval = interval + interval, err := strconv.Atoi(checkIntervalArgs[0]) + if err != nil { + return plugin.Error("Failed to convert checkInterval argument to integer: %v \n", err) + } + checkInterval = interval default: return c.Errf("unknown argument to acme '%s'", token) } } - - // the ACME DNS-01 Challenge doesn't work with other ports than 53 - // this option is really only there to use in tests with Pebble + // the ACME DNS-01 Challenge doesn't work with other ports than 53 + // this option is really only there to use in tests with Pebble portNumber := 53 if port != "" { portNumber, err = strconv.Atoi(port) @@ -149,9 +148,9 @@ func parseTLS(c *caddy.Controller) error { names = append(names, manager.Zone) tlsconf, cert, err = manager.configureTLSwithACME(ctx) - if err != nil { - log.Errorf("Failed to setup TLS automatically: %v \n", err) - } + if err != nil { + log.Errorf("Failed to setup TLS automatically: %v \n", err) + } config.TLSConfig = tlsconf once.Do(func() { diff --git a/solver.go b/solver.go index e973953..ca20053 100644 --- a/solver.go +++ b/solver.go @@ -14,13 +14,12 @@ import ( // DNSSolver is minimal dns.Server that can solve the ACME Challenge type DNSSolver struct { - Port int + Port int m sync.Mutex server *dns.Server readyChan chan string } - // Start starts a dns.Server that can solve the ACME Challenge, which means it answer on TXT requests // that start with _acme-challenge - this server will ignore all other requests func (ds *DNSSolver) Start(p net.PacketConn, challenge acme.Challenge) error { @@ -31,16 +30,13 @@ func (ds *DNSSolver) Start(p net.PacketConn, challenge acme.Challenge) error { state := request.Request{W: w, Req: r} log.Debugf("Received DNS request | name: %s, type: %s, source ip: %s \n", state.Name(), state.Type(), state.IP()) - hdr := dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeTXT, Class: dns.ClassANY, Ttl: 0} m := new(dns.Msg) m.SetReply(r) - //if state.QType() == dns.TypeCAA { - //log.Debug("Answering CAA request:", state.Name()) - //m.Answer = append(m.Answer, &dns.CAA{Hdr: hdr, Value: "letsencrypt.org"}) - //w.WriteMsg(m) - //return - //} + if state.QType() == dns.TypeCAA { + hdr := dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeCAA, Class: dns.ClassANY, Ttl: 0} + m.Answer = append(m.Answer, &dns.CAA{Hdr: hdr}) + } if state.QType() != dns.TypeTXT { acme_request = false @@ -50,13 +46,11 @@ func (ds *DNSSolver) Start(p net.PacketConn, challenge acme.Challenge) error { acme_request = false } - if !acme_request { - log.Debugf("Ignoring DNS request name: %s\n", state.Name()) - return + if acme_request { + log.Info("Answering ACME DNS request:", state.Name()) + hdr := dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeTXT, Class: dns.ClassANY, Ttl: 0} + m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{challenge.DNS01KeyAuthorization()}}) } - - log.Info("Answering DNS request:", state.Name()) - m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{challenge.DNS01KeyAuthorization()}}) w.WriteMsg(m) return })} @@ -95,14 +89,14 @@ func (ds *DNSSolver) Present(ctx context.Context, challenge acme.Challenge) erro l, err := net.ListenUDP("udp", &addr) if err != nil { - log.Errorf("Failed to create Listener: %v \n", err) + log.Errorf("Failed to create Listener: %v \n", err) } go func() { // start a dns.server that runs in a seperate goroutine err := ds.Start(l, challenge) if err != nil { - log.Errorf("Failed to start DNS Server for ACME Challenge: %v \n", err) + log.Errorf("Failed to start DNS Server for ACME Challenge: %v \n", err) } }() return nil diff --git a/solver_test.go b/solver_test.go index 78471d8..7940f6f 100644 --- a/solver_test.go +++ b/solver_test.go @@ -11,7 +11,7 @@ import ( func setupACME(readyChan chan string) { acmeServer := &DNSSolver{ - Port: 2053, + Port: 2053, readyChan: readyChan, } addr := net.UDPAddr{