@@ -71,12 +71,39 @@ type Resolve struct {
7171}
7272
7373func (c * ManualClient ) GetDNSResolve (ctx context.Context , websiteSSL * model.WebsiteSSL ) (map [string ]Resolve , error ) {
74- order , err := c .client .AuthorizeOrder (ctx , acme .DomainIDs (getWebsiteSSLDomains (websiteSSL )... ))
74+ var order * acme.Order
75+ var err error
76+
77+ // Check if we have an existing valid order for this SSL
78+ existingOrder , exists := Orders [websiteSSL .ID ]
79+ if exists && existingOrder != nil {
80+ // Verify the order is still valid (not expired and still pending)
81+ // If Expires is zero, order is still valid (ACME doesn't always set expiry immediately)
82+ isNotExpired := existingOrder .Expires .IsZero () || existingOrder .Expires .After (time .Now ())
83+ if isNotExpired && (existingOrder .Status == acme .StatusPending || existingOrder .Status == acme .StatusReady ) {
84+ // Try to reuse the existing order
85+ records , err := c .extractDNSChallenges (ctx , existingOrder )
86+ if err == nil && len (records ) > 0 {
87+ return records , nil
88+ }
89+ // If extraction failed, fall through to create a new order
90+ }
91+ // Existing order is expired or invalid, remove it
92+ delete (Orders , websiteSSL .ID )
93+ }
94+
95+ // Create a new order
96+ order , err = c .client .AuthorizeOrder (ctx , acme .DomainIDs (getWebsiteSSLDomains (websiteSSL )... ))
7597 if err != nil {
7698 return nil , err
7799 }
78100 Orders [websiteSSL .ID ] = order
79101
102+ return c .extractDNSChallenges (ctx , order )
103+ }
104+
105+ // extractDNSChallenges extracts DNS-01 challenge values from an ACME order
106+ func (c * ManualClient ) extractDNSChallenges (ctx context.Context , order * acme.Order ) (map [string ]Resolve , error ) {
80107 records := make (map [string ]Resolve )
81108
82109 for _ , authzURL := range order .AuthzURLs {
@@ -103,23 +130,30 @@ func (c *ManualClient) GetDNSResolve(ctx context.Context, websiteSSL *model.Webs
103130 return nil , err
104131 }
105132
106- records [domain ] = Resolve {
133+ // Use different map key for wildcard vs non-wildcard to avoid overwriting
134+ // Both use the same DNS record name (_acme-challenge.domain) but different values
135+ mapKey := domain
136+ if authz .Wildcard {
137+ mapKey = "*." + domain
138+ }
139+
140+ records [mapKey ] = Resolve {
107141 Key : fmt .Sprintf ("_acme-challenge.%s" , domain ),
108142 Value : txtValue ,
109143 }
110144 }
111145 return records , nil
112146}
113147
114- func queryDNSRecords (domain string ) (map [string ]string , error ) {
148+ func queryDNSRecords (domain string ) (map [string ][] string , error ) {
115149 recordName := fmt .Sprintf ("_acme-challenge.%s" , domain )
116150 txts , err := net .LookupTXT (recordName )
117151 if err != nil {
118152 return nil , err
119153 }
120- records := make (map [string ]string )
154+ records := make (map [string ][] string )
121155 if len (txts ) > 0 {
122- records [recordName ] = txts [ 0 ]
156+ records [recordName ] = txts
123157 }
124158 return records , nil
125159}
@@ -159,7 +193,7 @@ func (c *ManualClient) handleAuthorization(ctx context.Context, authzURL string,
159193
160194 for {
161195 c .logger .Printf ("[INFO] [%s] acme: Checking DNS record propagation." , domain )
162- var currentRecords map [string ]string
196+ var currentRecords map [string ][] string
163197 var queryErr error
164198 if len (nameservers ) == 0 {
165199 currentRecords , queryErr = queryDNSRecords (domain )
@@ -177,16 +211,26 @@ func (c *ManualClient) handleAuthorization(ctx context.Context, authzURL string,
177211 return fmt .Errorf ("failed to query DNS records: %v" , queryErr )
178212 }
179213 recordName := fmt .Sprintf ("_acme-challenge.%s" , domain )
180- providedRecord , exists := currentRecords [recordName ]
181- if exists && providedRecord == expectedRecord {
214+ providedRecords , exists := currentRecords [recordName ]
215+ // Check if expected record is in any of the TXT values
216+ found := false
217+ if exists {
218+ for _ , record := range providedRecords {
219+ if record == expectedRecord {
220+ found = true
221+ break
222+ }
223+ }
224+ }
225+ if found {
182226 break
183227 }
184228 if time .Now ().After (deadline ) {
185- if ! exists {
229+ if ! exists || len ( providedRecords ) == 0 {
186230 return fmt .Errorf ("TXT record not provided for domain %s after retrying" , domain )
187231 }
188- c .logger .Printf ("[INFO] [%s] TXT record mismatch for %s: expected %s, got %s \" " , domain , domain , expectedRecord , providedRecord )
189- return fmt .Errorf ("TXT record mismatch for %s: expected %s, got %s " , domain , expectedRecord , providedRecord )
232+ c .logger .Printf ("[INFO] [%s] TXT record mismatch for %s: expected %s, got %v" , domain , domain , expectedRecord , providedRecords )
233+ return fmt .Errorf ("TXT record mismatch for %s: expected %s, got %v " , domain , expectedRecord , providedRecords )
190234 }
191235 time .Sleep (pollingInterval )
192236 }
@@ -339,7 +383,7 @@ func handleNameserver(nameserver string) string {
339383 return fmt .Sprintf ("%s:53" , nameserver )
340384}
341385
342- func queryDNSRecordsWithResolver (ctx context.Context , logger * log.Logger , domain string , dnsServer string ) (map [string ]string , error ) {
386+ func queryDNSRecordsWithResolver (ctx context.Context , logger * log.Logger , domain string , dnsServer string ) (map [string ][] string , error ) {
343387 recordName := fmt .Sprintf ("_acme-challenge.%s" , domain )
344388 c := new (dns.Client )
345389 c .Timeout = 10 * time .Second
@@ -367,16 +411,19 @@ func queryDNSRecordsWithResolver(ctx context.Context, logger *log.Logger, domain
367411 return nil , fmt .Errorf ("DNS query failed with code: %s" , dns .RcodeToString [r .Rcode ])
368412 }
369413
370- records := make (map [string ]string )
414+ records := make (map [string ][]string )
415+ var txtValues []string
371416
372417 for _ , answer := range r .Answer {
373418 if txt , ok := answer .(* dns.TXT ); ok {
374419 if len (txt .Txt ) > 0 {
375- records [recordName ] = txt .Txt [0 ]
376- break
420+ txtValues = append (txtValues , txt .Txt [0 ])
377421 }
378422 }
379423 }
424+ if len (txtValues ) > 0 {
425+ records [recordName ] = txtValues
426+ }
380427
381428 return records , nil
382429}
0 commit comments