fix: 修复裸域名与泛域名共用 ACME TXT 记录时相互覆盖

abc.com 与 *.abc.com 共用 _acme-challenge.abc.com,需同时存在两条
TXT 记录,但 SetRecords 以 (name, type) 为单位覆盖,导致后写入的
challenge 覆盖前者,DNS 验证一直卡死。改为按记录名累积所有 keyAuth
一次性写入。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
耗子
2026-05-14 19:37:37 +08:00
parent d152f4c59f
commit 5495a17748
2 changed files with 23 additions and 13 deletions
+4 -3
View File
@@ -34,9 +34,10 @@ type DnsOption struct {
// UseDns 使用 DNS 接口验证
func (c *Client) UseDns(dnsType DnsType, param DNSParam, opt ...DnsOption) {
solver := &dnsSolver{
dns: dnsType,
param: param,
records: make(map[string][]libdns.Record),
dns: dnsType,
param: param,
keyAuths: make(map[string][]string),
records: make(map[string][]libdns.Record),
}
if len(opt) > 0 {
solver.alias = opt[0].Alias
+19 -10
View File
@@ -414,7 +414,8 @@ type dnsSolver struct {
mu sync.Mutex
dns DnsType
param DNSParam
records map[string][]libdns.Record // dnsName|keyAuth → records
keyAuths map[string][]string // dnsNamekeyAuth 列表
records map[string][]libdns.Record // dnsName → 已设置的记录
alias map[string]string // DNS 验证别名映射 (domain → delegated domain)
dnsServer string // DNS 验证服务器地址
skipVerify bool // 跳过解析验证
@@ -434,12 +435,20 @@ func (s *dnsSolver) Present(ctx context.Context, challenge acme.Challenge) error
s.report(fmt.Sprintf("setting DNS TXT record %s", dnsName))
rec := libdns.TXT{
Name: libdns.RelativeName(dnsName+".", zone+"."),
Text: keyAuth,
// 同名 TXT 记录可能对应多个 challenge SetRecords 以 (name, type) 为单位覆盖
// 因此需把该记录名下所有 keyAuth 一次性写入,避免后者覆盖前者
s.mu.Lock()
s.keyAuths[dnsName] = append(s.keyAuths[dnsName], keyAuth)
recs := make([]libdns.Record, 0, len(s.keyAuths[dnsName]))
for _, ka := range s.keyAuths[dnsName] {
recs = append(recs, libdns.TXT{
Name: libdns.RelativeName(dnsName+".", zone+"."),
Text: ka,
})
}
s.mu.Unlock()
results, err := provider.SetRecords(ctx, zone+".", []libdns.Record{rec})
results, err := provider.SetRecords(ctx, zone+".", recs)
if err != nil {
return fmt.Errorf("failed to set DNS record %q for %q: %w", dnsName, zone, err)
}
@@ -448,8 +457,7 @@ func (s *dnsSolver) Present(ctx context.Context, challenge acme.Challenge) error
}
s.mu.Lock()
key := dnsName + "|" + keyAuth
s.records[key] = append(s.records[key], results...)
s.records[dnsName] = results
s.mu.Unlock()
s.report(fmt.Sprintf("DNS TXT record %s set successfully", dnsName))
@@ -538,10 +546,11 @@ func (s *dnsSolver) CleanUp(ctx context.Context, challenge acme.Challenge) error
s.report("cleaning up DNS TXT records")
// 同名 TXT 记录下的多条 challenge 记录由首次 CleanUp 一并删除
s.mu.Lock()
key := dnsName + "|" + challenge.DNS01KeyAuthorization()
records := s.records[key]
delete(s.records, key)
records := s.records[dnsName]
delete(s.records, dnsName)
delete(s.keyAuths, dnsName)
s.mu.Unlock()
if len(records) > 0 {