@@ -12,6 +12,7 @@ import (
1212 "fmt"
1313 "github.com/1Panel-dev/1Panel/agent/app/model"
1414 "github.com/go-acme/lego/v4/certificate"
15+ "github.com/miekg/dns"
1516 "golang.org/x/crypto/acme"
1617 "log"
1718 "net"
@@ -123,7 +124,7 @@ func queryDNSRecords(domain string) (map[string]string, error) {
123124 return records , nil
124125}
125126
126- func (c * ManualClient ) handleAuthorization (ctx context.Context , authzURL string ) error {
127+ func (c * ManualClient ) handleAuthorization (ctx context.Context , authzURL string , nameservers [] string ) error {
127128 authz , err := c .client .GetAuthorization (ctx , authzURL )
128129 if err != nil {
129130 return fmt .Errorf ("failed to get authorization: %v" , err )
@@ -158,9 +159,22 @@ func (c *ManualClient) handleAuthorization(ctx context.Context, authzURL string)
158159
159160 for {
160161 c .logger .Printf ("[INFO] [%s] acme: Checking DNS record propagation." , domain )
161- currentRecords , err := queryDNSRecords (domain )
162- if err != nil {
163- return fmt .Errorf ("failed to query DNS records: %v" , err )
162+ var currentRecords map [string ]string
163+ var queryErr error
164+ if len (nameservers ) == 0 {
165+ currentRecords , queryErr = queryDNSRecords (domain )
166+ } else {
167+ var errs []string
168+ for _ , nameserver := range nameservers {
169+ currentRecords , queryErr = queryDNSRecordsWithResolver (ctx , c .logger , domain , nameserver )
170+ errs = append (errs , fmt .Sprintf ("%s: %v" , nameserver , queryErr ))
171+ }
172+ if queryErr != nil && len (errs ) > 0 {
173+ queryErr = fmt .Errorf ("all nameservers failed: %s" , strings .Join (errs , "; " ))
174+ }
175+ }
176+ if currentRecords == nil && queryErr != nil {
177+ return fmt .Errorf ("failed to query DNS records: %v" , queryErr )
164178 }
165179 recordName := fmt .Sprintf ("_acme-challenge.%s" , domain )
166180 providedRecord , exists := currentRecords [recordName ]
@@ -262,7 +276,7 @@ func (c *ManualClient) RequestCertificate(ctx context.Context, websiteSSL *model
262276 defer delete (Orders , websiteSSL .ID )
263277
264278 for _ , authzURL := range order .AuthzURLs {
265- if err := c .handleAuthorization (ctx , authzURL ); err != nil {
279+ if err := c .handleAuthorization (ctx , authzURL , getNameservers ( * websiteSSL ) ); err != nil {
266280 return res , err
267281 }
268282 }
@@ -306,3 +320,73 @@ func (c *ManualClient) RequestCertificate(ctx context.Context, websiteSSL *model
306320 }
307321 return resource , nil
308322}
323+
324+ func getNameservers (websiteSSL model.WebsiteSSL ) []string {
325+ var nameservers []string
326+ if websiteSSL .Nameserver1 != "" {
327+ nameservers = append (nameservers , handleNameserver (websiteSSL .Nameserver1 ))
328+ }
329+ if websiteSSL .Nameserver2 != "" {
330+ nameservers = append (nameservers , handleNameserver (websiteSSL .Nameserver2 ))
331+ }
332+ return nameservers
333+ }
334+
335+ func handleNameserver (nameserver string ) string {
336+ if strings .Contains (nameserver , ":" ) {
337+ return nameserver
338+ }
339+ return fmt .Sprintf ("%s:53" , nameserver )
340+ }
341+
342+ func queryDNSRecordsWithResolver (ctx context.Context , logger * log.Logger , domain string , dnsServer string ) (map [string ]string , error ) {
343+ recordName := fmt .Sprintf ("_acme-challenge.%s" , domain )
344+ c := new (dns.Client )
345+ c .Timeout = 10 * time .Second
346+ c .Net = "udp"
347+
348+ m := new (dns.Msg )
349+ m .SetQuestion (dns .Fqdn (recordName ), dns .TypeTXT )
350+ m .RecursionDesired = true
351+
352+ r , _ , err := c .ExchangeContext (ctx , m , dnsServer )
353+ if isNetworkError (err ) {
354+ logger .Printf ("[WARN] Network error occurred while querying DNS: %v" , err )
355+ return nil , nil
356+ }
357+ if err != nil {
358+ return nil , fmt .Errorf ("DNS query failed: %w" , err )
359+ }
360+
361+ if r .Rcode == dns .RcodeNameError {
362+ logger .Printf ("[INFO] DNS record does not exist yet (NXDOMAIN)" )
363+ return nil , nil
364+ }
365+
366+ if r .Rcode != dns .RcodeSuccess {
367+ return nil , fmt .Errorf ("DNS query failed with code: %s" , dns .RcodeToString [r .Rcode ])
368+ }
369+
370+ records := make (map [string ]string )
371+
372+ for _ , answer := range r .Answer {
373+ if txt , ok := answer .(* dns.TXT ); ok {
374+ if len (txt .Txt ) > 0 {
375+ records [recordName ] = txt .Txt [0 ]
376+ break
377+ }
378+ }
379+ }
380+
381+ return records , nil
382+ }
383+
384+ func isNetworkError (err error ) bool {
385+ if err == nil {
386+ return false
387+ }
388+ return strings .Contains (err .Error (), "i/o timeout" ) ||
389+ strings .Contains (err .Error (), "connection refused" ) ||
390+ strings .Contains (err .Error (), "network is unreachable" ) ||
391+ strings .Contains (err .Error (), "no route to host" )
392+ }
0 commit comments