feat: refactor DNS handling in providers to improve zone ID management and enhance ECH DNS record synchronization

Kim committed May 8, 2026 at 17:29 UTC 8669f74e239f08f06bbad838fb6d0250c32848ec
7 files changed +209 -62
portal/acme/cloudflare/provider.go
+38 -14
@@ -7,6 +7,7 @@ import (
7 "net/http"
8 "net/url"
9 "strings"
10 + "sync"
11
12 "github.com/go-acme/lego/v4/challenge"
13 "github.com/go-acme/lego/v4/providers/dns/cloudflare"
@@ -20,6 +21,9 @@ const (
21
22 type Provider struct {
23 token string
24 +
25 + zoneMu sync.RWMutex
26 + zones map[string]string
27 }
28
29 type apiError struct {
@@ -117,7 +121,7 @@ func (p *Provider) EnsureARecords(ctx context.Context, baseDomain, publicIPv4 st
121 }
122 publicIPv4 = strings.TrimSpace(publicIPv4)
123
120 - zoneID, err := findZoneID(ctx, p.token, baseDomain)
124 + zoneID, err := p.findZoneID(ctx, baseDomain)
125 if err != nil {
126 return fmt.Errorf("find cloudflare zone: %w", err)
127 }
@@ -146,7 +150,7 @@ func (p *Provider) EnsureARecord(ctx context.Context, name, publicIPv4 string) e
150 }
151 publicIPv4 = strings.TrimSpace(publicIPv4)
152
149 - zoneID, err := findZoneID(ctx, p.token, name)
153 + zoneID, err := p.findZoneID(ctx, name)
154 if err != nil {
155 return fmt.Errorf("find cloudflare zone: %w", err)
156 }
@@ -168,7 +172,7 @@ func (p *Provider) DeleteARecord(ctx context.Context, name string) error {
172 return errors.New("cloudflare token is required")
173 }
174
171 - zoneID, err := findZoneID(ctx, p.token, name)
175 + zoneID, err := p.findZoneID(ctx, name)
176 if err != nil {
177 return fmt.Errorf("find cloudflare zone: %w", err)
178 }
@@ -204,7 +208,7 @@ func (p *Provider) EnsureTXTRecord(ctx context.Context, name, value string) erro
208 return errors.New("txt record value is required")
209 }
210
207 - zoneID, err := findZoneID(ctx, p.token, name)
211 + zoneID, err := p.findZoneID(ctx, name)
212 if err != nil {
213 return fmt.Errorf("find cloudflare zone: %w", err)
214 }
@@ -230,7 +234,7 @@ func (p *Provider) DeleteTXTRecords(ctx context.Context, name, matchPrefix strin
234 return errors.New("txt record match prefix is required")
235 }
236
233 - zoneID, err := findZoneID(ctx, p.token, name)
237 + zoneID, err := p.findZoneID(ctx, name)
238 if err != nil {
239 return fmt.Errorf("find cloudflare zone: %w", err)
240 }
@@ -274,7 +278,7 @@ func (p *Provider) EnsureHTTPSRecord(ctx context.Context, name string, priority
278 return errors.New("https record content is required")
279 }
280
277 - zoneID, err := findZoneID(ctx, p.token, name)
281 + zoneID, err := p.findZoneID(ctx, name)
282 if err != nil {
283 return fmt.Errorf("find cloudflare zone: %w", err)
284 }
@@ -296,7 +300,7 @@ func (p *Provider) DeleteHTTPSRecord(ctx context.Context, name string) error {
300 return errors.New("cloudflare token is required")
301 }
302
299 - zoneID, err := findZoneID(ctx, p.token, name)
303 + zoneID, err := p.findZoneID(ctx, name)
304 if err != nil {
305 return fmt.Errorf("find cloudflare zone: %w", err)
306 }
@@ -328,7 +332,7 @@ func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (state,
332 return "", "", "", errors.New("cloudflare token is required")
333 }
334
331 - zoneID, err := findZoneID(ctx, p.token, baseDomain)
335 + zoneID, err := p.findZoneID(ctx, baseDomain)
336 if err != nil {
337 return "", "", "", fmt.Errorf("find cloudflare zone: %w", err)
338 }
@@ -358,17 +362,37 @@ func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (state,
362 return state, dsRecord, message, nil
363 }
364
361 -func findZoneID(ctx context.Context, token, domain string) (string, error) {
362 - parts := strings.Split(domain, ".")
363 - for i := range len(parts) - 1 {
364 - candidate := strings.Join(parts[i:], ".")
365 - zones, err := listZones(ctx, token, candidate)
365 +func (p *Provider) findZoneID(ctx context.Context, domain string) (string, error) {
366 + domain = utils.NormalizeHostname(domain)
367 + candidates := utils.DomainCandidates(domain)
368 +
369 + p.zoneMu.RLock()
370 + for _, candidate := range candidates {
371 + if zoneID := p.zones[candidate]; zoneID != "" {
372 + p.zoneMu.RUnlock()
373 + return zoneID, nil
374 + }
375 + }
376 + p.zoneMu.RUnlock()
377 +
378 + for _, candidate := range candidates {
379 + zones, err := listZones(ctx, p.token, candidate)
380 if err != nil {
381 return "", err
382 }
383 for _, z := range zones {
384 if strings.EqualFold(z.Name, candidate) {
371 - return z.ID, nil
385 + zoneID := strings.TrimSpace(z.ID)
386 + if zoneID == "" {
387 + continue
388 + }
389 + p.zoneMu.Lock()
390 + if p.zones == nil {
391 + p.zones = make(map[string]string)
392 + }
393 + p.zones[utils.NormalizeHostname(z.Name)] = zoneID
394 + p.zoneMu.Unlock()
395 + return zoneID, nil
396 }
397 }
398 }
portal/acme/gcloud/provider.go
+48 -14
@@ -7,6 +7,7 @@ import (
7 "net/http"
8 "strconv"
9 "strings"
10 + "sync"
11 "time"
12
13 "cloud.google.com/go/compute/metadata"
@@ -31,7 +32,9 @@ type Config struct {
32 }
33
34 type Provider struct {
34 - cfg Config
35 + cfg Config
36 + zoneMu sync.RWMutex
37 + zones map[string]string
38 }
39
40 type runtimeConfig struct {
@@ -87,7 +90,7 @@ func (p *Provider) EnsureARecords(ctx context.Context, baseDomain, publicIPv4 st
90 return err
91 }
92
90 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, baseDomain)
93 + service, runtimeCfg, zone, err := p.newService(ctx, baseDomain)
94 if err != nil {
95 return err
96 }
@@ -117,7 +120,7 @@ func (p *Provider) EnsureARecord(ctx context.Context, name, publicIPv4 string) e
120 return err
121 }
122
120 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, name)
123 + service, runtimeCfg, zone, err := p.newService(ctx, name)
124 if err != nil {
125 return err
126 }
@@ -142,7 +145,7 @@ func (p *Provider) DeleteARecord(ctx context.Context, name string) error {
145 return errors.New("record name is required")
146 }
147
145 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, name)
148 + service, runtimeCfg, zone, err := p.newService(ctx, name)
149 if err != nil {
150 return err
151 }
@@ -175,7 +178,7 @@ func (p *Provider) EnsureTXTRecord(ctx context.Context, name, value string) erro
178 return errors.New("txt record value is required")
179 }
180
178 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, name)
181 + service, runtimeCfg, zone, err := p.newService(ctx, name)
182 if err != nil {
183 return err
184 }
@@ -229,7 +232,7 @@ func (p *Provider) DeleteTXTRecords(ctx context.Context, name, matchPrefix strin
232 return errors.New("txt record match prefix is required")
233 }
234
232 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, name)
235 + service, runtimeCfg, zone, err := p.newService(ctx, name)
236 if err != nil {
237 return err
238 }
@@ -299,7 +302,7 @@ func (p *Provider) EnsureHTTPSRecord(ctx context.Context, name string, _ uint16,
302 return errors.New("https record content is required")
303 }
304
302 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, name)
305 + service, runtimeCfg, zone, err := p.newService(ctx, name)
306 if err != nil {
307 return err
308 }
@@ -324,7 +327,7 @@ func (p *Provider) DeleteHTTPSRecord(ctx context.Context, name string) error {
327 return errors.New("record name is required")
328 }
329
327 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, name)
330 + service, runtimeCfg, zone, err := p.newService(ctx, name)
331 if err != nil {
332 return err
333 }
@@ -353,11 +356,15 @@ func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (state,
356 return "", "", "", errors.New("base domain is required")
357 }
358
356 - service, runtimeCfg, zone, err := newService(ctx, p.cfg, baseDomain)
359 + service, runtimeCfg, zone, err := p.newService(ctx, baseDomain)
360 if err != nil {
361 return "", "", "", err
362 }
363 managedZone := zone.Name
364 + zone, err = service.ManagedZones.Get(runtimeCfg.ProjectID, managedZone).Context(ctx).Do()
365 + if err != nil {
366 + return "", "", "", fmt.Errorf("get gcloud managed zone %s: %w", managedZone, err)
367 + }
368
369 currentState := strings.ToLower(strings.TrimSpace(dnssecState(zone)))
370 if currentState != "on" && currentState != "transfer" {
@@ -404,8 +411,8 @@ func newRuntimeConfig(ctx context.Context, cfg Config) (runtimeConfig, error) {
411 }, nil
412 }
413
407 -func newService(ctx context.Context, cfg Config, domain string) (*dns.Service, runtimeConfig, *dns.ManagedZone, error) {
408 - runtimeCfg, err := newRuntimeConfig(ctx, cfg)
414 +func (p *Provider) newService(ctx context.Context, domain string) (*dns.Service, runtimeConfig, *dns.ManagedZone, error) {
415 + runtimeCfg, err := newRuntimeConfig(ctx, p.cfg)
416 if err != nil {
417 return nil, runtimeConfig{}, nil, err
418 }
@@ -415,17 +422,28 @@ func newService(ctx context.Context, cfg Config, domain string) (*dns.Service, r
422 return nil, runtimeConfig{}, nil, fmt.Errorf("create gcloud dns service: %w", err)
423 }
424
418 - zone, err := findManagedZone(ctx, service, runtimeCfg.ProjectID, domain, runtimeCfg.ManagedZone)
425 + zone, err := p.findManagedZone(ctx, service, runtimeCfg.ProjectID, domain, runtimeCfg.ManagedZone)
426 if err != nil {
427 return nil, runtimeConfig{}, nil, err
428 }
429 return service, runtimeCfg, zone, nil
430 }
431
425 -func findManagedZone(ctx context.Context, service *dns.Service, projectID, domain, explicit string) (*dns.ManagedZone, error) {
432 +func (p *Provider) findManagedZone(ctx context.Context, service *dns.Service, projectID, domain, explicit string) (*dns.ManagedZone, error) {
433 if service == nil {
434 return nil, errors.New("gcloud dns service is nil")
435 }
436 + domain = utils.NormalizeHostname(domain)
437 + candidates := utils.DomainCandidates(domain)
438 +
439 + p.zoneMu.RLock()
440 + for _, candidate := range candidates {
441 + if zoneName := p.zones[candidate]; zoneName != "" {
442 + p.zoneMu.RUnlock()
443 + return &dns.ManagedZone{Name: zoneName, DnsName: fqdn(candidate)}, nil
444 + }
445 + }
446 + p.zoneMu.RUnlock()
447
448 if explicit = strings.TrimSpace(explicit); explicit != "" {
449 zone, err := service.ManagedZones.Get(projectID, explicit).Context(ctx).Do()
@@ -435,10 +453,18 @@ func findManagedZone(ctx context.Context, service *dns.Service, projectID, domai
453 if err := validateManagedZone(zone, domain, explicit); err != nil {
454 return nil, err
455 }
456 + if zoneDomain := utils.NormalizeHostname(zone.DnsName); zoneDomain != "" && zone.Name != "" {
457 + p.zoneMu.Lock()
458 + if p.zones == nil {
459 + p.zones = make(map[string]string)
460 + }
461 + p.zones[zoneDomain] = zone.Name
462 + p.zoneMu.Unlock()
463 + }
464 return zone, nil
465 }
466
441 - for _, candidate := range utils.DomainCandidates(domain) {
467 + for _, candidate := range candidates {
468 out, err := service.ManagedZones.List(projectID).DnsName(fqdn(candidate)).Context(ctx).Do()
469 if err != nil {
470 return nil, fmt.Errorf("list gcloud managed zones: %w", err)
@@ -447,6 +473,14 @@ func findManagedZone(ctx context.Context, service *dns.Service, projectID, domai
473 if !isPublicZone(zone) || utils.NormalizeHostname(zone.DnsName) != candidate {
474 continue
475 }
476 + if zone.Name != "" {
477 + p.zoneMu.Lock()
478 + if p.zones == nil {
479 + p.zones = make(map[string]string)
480 + }
481 + p.zones[candidate] = zone.Name
482 + p.zoneMu.Unlock()
483 + }
484 return zone, nil
485 }
486 }
portal/acme/route53/provider.go
+34 -11
@@ -6,6 +6,7 @@ import (
6 "fmt"
7 "strconv"
8 "strings"
9 + "sync"
10 "time"
11
12 "github.com/aws/aws-sdk-go-v2/aws"
@@ -34,7 +35,9 @@ type Config struct {
35 }
36
37 type Provider struct {
37 - cfg Config
38 + cfg Config
39 + zoneMu sync.RWMutex
40 + zones map[string]string
41 }
42
43 func New(cfg Config) *Provider {
@@ -93,7 +96,7 @@ func (p *Provider) EnsureARecords(ctx context.Context, baseDomain, publicIPv4 st
96 return err
97 }
98
96 - hostedZoneID, err := findHostedZoneID(ctx, client, baseDomain, p.cfg.HostedZoneID)
99 + hostedZoneID, err := p.findHostedZoneID(ctx, client, baseDomain)
100 if err != nil {
101 return err
102 }
@@ -123,7 +126,7 @@ func (p *Provider) EnsureARecord(ctx context.Context, name, publicIPv4 string) e
126 return err
127 }
128
126 - hostedZoneID, err := findHostedZoneID(ctx, client, name, p.cfg.HostedZoneID)
129 + hostedZoneID, err := p.findHostedZoneID(ctx, client, name)
130 if err != nil {
131 return err
132 }
@@ -147,7 +150,7 @@ func (p *Provider) DeleteARecord(ctx context.Context, name string) error {
150 return err
151 }
152
150 - hostedZoneID, err := findHostedZoneID(ctx, client, name, p.cfg.HostedZoneID)
153 + hostedZoneID, err := p.findHostedZoneID(ctx, client, name)
154 if err != nil {
155 return err
156 }
@@ -182,7 +185,7 @@ func (p *Provider) EnsureTXTRecord(ctx context.Context, name, value string) erro
185 return err
186 }
187
185 - hostedZoneID, err := findHostedZoneID(ctx, client, name, p.cfg.HostedZoneID)
188 + hostedZoneID, err := p.findHostedZoneID(ctx, client, name)
189 if err != nil {
190 return err
191 }
@@ -210,7 +213,7 @@ func (p *Provider) DeleteTXTRecords(ctx context.Context, name, matchPrefix strin
213 return err
214 }
215
213 - hostedZoneID, err := findHostedZoneID(ctx, client, name, p.cfg.HostedZoneID)
216 + hostedZoneID, err := p.findHostedZoneID(ctx, client, name)
217 if err != nil {
218 return err
219 }
@@ -238,7 +241,7 @@ func (p *Provider) EnsureHTTPSRecord(ctx context.Context, name string, _ uint16,
241 return err
242 }
243
241 - hostedZoneID, err := findHostedZoneID(ctx, client, name, p.cfg.HostedZoneID)
244 + hostedZoneID, err := p.findHostedZoneID(ctx, client, name)
245 if err != nil {
246 return err
247 }
@@ -262,7 +265,7 @@ func (p *Provider) DeleteHTTPSRecord(ctx context.Context, name string) error {
265 return err
266 }
267
265 - hostedZoneID, err := findHostedZoneID(ctx, client, name, p.cfg.HostedZoneID)
268 + hostedZoneID, err := p.findHostedZoneID(ctx, client, name)
269 if err != nil {
270 return err
271 }
@@ -293,7 +296,7 @@ func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (state,
296 return "", "", "", err
297 }
298
296 - hostedZoneID, err := findHostedZoneID(ctx, client, baseDomain, p.cfg.HostedZoneID)
299 + hostedZoneID, err := p.findHostedZoneID(ctx, client, baseDomain)
300 if err != nil {
301 return "", "", "", err
302 }
@@ -355,8 +358,8 @@ func newClient(ctx context.Context, cfg Config) (*awsroute53.Client, error) {
358 return awsroute53.NewFromConfig(awsCfg), nil
359 }
360
358 -func findHostedZoneID(ctx context.Context, client *awsroute53.Client, domain, explicitZoneID string) (string, error) {
359 - if explicitZoneID = normalizeZoneID(explicitZoneID); explicitZoneID != "" {
361 +func (p *Provider) findHostedZoneID(ctx context.Context, client *awsroute53.Client, domain string) (string, error) {
362 + if explicitZoneID := normalizeZoneID(p.cfg.HostedZoneID); explicitZoneID != "" {
363 return explicitZoneID, nil
364 }
365 if client == nil {
@@ -368,6 +371,15 @@ func findHostedZoneID(ctx context.Context, client *awsroute53.Client, domain, ex
371 return "", fmt.Errorf("invalid base domain for hosted zone lookup: %q", domain)
372 }
373
374 + p.zoneMu.RLock()
375 + for _, candidate := range candidates {
376 + if zoneID := p.zones[candidate]; zoneID != "" {
377 + p.zoneMu.RUnlock()
378 + return zoneID, nil
379 + }
380 + }
381 + p.zoneMu.RUnlock()
382 +
383 zonesByName := make(map[string]string)
384 paginator := awsroute53.NewListHostedZonesPaginator(client, &awsroute53.ListHostedZonesInput{})
385 for paginator.HasMorePages() {
@@ -388,6 +400,17 @@ func findHostedZoneID(ctx context.Context, client *awsroute53.Client, domain, ex
400 }
401 }
402
403 + if len(zonesByName) > 0 {
404 + p.zoneMu.Lock()
405 + if p.zones == nil {
406 + p.zones = make(map[string]string)
407 + }
408 + for zoneName, zoneID := range zonesByName {
409 + p.zones[zoneName] = zoneID
410 + }
411 + p.zoneMu.Unlock()
412 + }
413 +
414 for _, candidate := range candidates {
415 if zoneID, ok := zonesByName[candidate]; ok {
416 return zoneID, nil
portal/acme/route53/provider_test.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 func TestFindHostedZoneIDExplicitOverride(t *testing.T) {
9 t.Parallel()
10
11 - got, err := findHostedZoneID(context.Background(), nil, "portal.example.com", "/hostedzone/Z123456789")
11 + got, err := New(Config{HostedZoneID: "/hostedzone/Z123456789"}).findHostedZoneID(context.Background(), nil, "portal.example.com")
12 if err != nil {
13 t.Fatalf("findHostedZoneID() error = %v", err)
14 }
portal/api_server.go
+6 -4
@@ -284,7 +284,7 @@ func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) {
284 return
285 }
286 dnsCtx, cancel := context.WithTimeout(context.WithoutCancel(r.Context()), defaultClaimTimeout)
287 - deleteECHOnRollback, err := record.syncDNS(dnsCtx, s.acmeManager, s.cfg.SNIPort)
287 + err = record.syncENSGaslessDNS(dnsCtx, s.acmeManager)
288 cancel()
289 if err != nil {
290 removed, _ := s.registry.Unregister(types.UnregisterRequest{AccessToken: resp.AccessToken})
@@ -293,11 +293,12 @@ func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) {
293 removed = record
294 }
295 cleanupCtx, cleanupCancel := context.WithTimeout(context.WithoutCancel(r.Context()), defaultClaimTimeout)
296 - removed.deleteDNS(cleanupCtx, s.acmeManager, deleteECHOnRollback)
296 + removed.deleteDNS(cleanupCtx, s.acmeManager, false)
297 cleanupCancel()
298 writeAPIErrorResponse(w, err)
299 return
300 }
301 + s.registry.promoteECHDNS(record, s.acmeManager, s.cfg.SNIPort)
302
303 utils.WriteAPIData(w, http.StatusCreated, resp)
304 }
@@ -468,7 +469,7 @@ func (s *Server) handleHop(w http.ResponseWriter, r *http.Request) {
469 return
470 }
471 dnsCtx, cancel := context.WithTimeout(context.WithoutCancel(r.Context()), defaultClaimTimeout)
471 - deleteECHOnRollback, err := record.syncDNS(dnsCtx, s.acmeManager, s.cfg.SNIPort)
472 + err = record.syncENSGaslessDNS(dnsCtx, s.acmeManager)
473 cancel()
474 if err != nil {
475 removed := s.registry.DeleteHopRoute(&route)
@@ -476,11 +477,12 @@ func (s *Server) handleHop(w http.ResponseWriter, r *http.Request) {
477 removed = record
478 }
479 cleanupCtx, cleanupCancel := context.WithTimeout(context.WithoutCancel(r.Context()), defaultClaimTimeout)
479 - removed.deleteDNS(cleanupCtx, s.acmeManager, deleteECHOnRollback)
480 + removed.deleteDNS(cleanupCtx, s.acmeManager, false)
481 cleanupCancel()
482 writeAPIErrorResponse(w, err)
483 return
484 }
485 + s.registry.promoteECHDNS(record, s.acmeManager, s.cfg.SNIPort)
486 var accessToken string
487 if record.isPublicEntry() {
488 accessToken, err = s.registry.issueLeaseAccessToken(record, now)
portal/lease.go
+55
@@ -2,6 +2,7 @@ package portal
2
3 import (
4 "bytes"
5 + "context"
6 "errors"
7 "fmt"
8 "net"
@@ -10,6 +11,9 @@ import (
11 "sync"
12 "time"
13
14 + "github.com/rs/zerolog/log"
15 +
16 + "github.com/gosuda/portal-tunnel/v2/portal/acme"
17 "github.com/gosuda/portal-tunnel/v2/portal/auth"
18 "github.com/gosuda/portal-tunnel/v2/portal/keyless"
19 "github.com/gosuda/portal-tunnel/v2/portal/policy"
@@ -647,6 +651,57 @@ func (r *leaseRegistry) DeleteHopRoute(route *types.HopRoute) *leaseRecord {
651 return deleted
652 }
653
654 +func (r *leaseRegistry) promoteECHDNS(record *leaseRecord, manager *acme.Manager, sniPort int) {
655 + if !record.hasECHDNSRecord() {
656 + return
657 + }
658 +
659 + go func() {
660 + active := false
661 + now := time.Now()
662 + r.mu.RLock()
663 + for _, existing := range r.records {
664 + if existing == record && !existing.isExpired(now) {
665 + active = true
666 + break
667 + }
668 + }
669 + r.mu.RUnlock()
670 + if !active {
671 + return
672 + }
673 +
674 + ctx, cancel := context.WithTimeout(context.Background(), defaultClaimTimeout)
675 + err := record.syncECHDNS(ctx, manager, sniPort)
676 + cancel()
677 +
678 + if err != nil {
679 + log.Warn().
680 + Err(err).
681 + Str("hostname", record.ECHDNSHostname).
682 + Str("route_hostname", record.Hostname).
683 + Str("address", record.Address).
684 + Msg("promote ech dns record")
685 + }
686 +
687 + hostnameActive := false
688 + now = time.Now()
689 + r.mu.RLock()
690 + for _, existing := range r.records {
691 + if existing != nil && !existing.isExpired(now) && existing.hasECHDNSRecord() && existing.ECHDNSHostname == record.ECHDNSHostname {
692 + hostnameActive = true
693 + break
694 + }
695 + }
696 + r.mu.RUnlock()
697 + if !hostnameActive {
698 + cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), defaultClaimTimeout)
699 + record.deleteECHDNS(cleanupCtx, manager)
700 + cleanupCancel()
701 + }
702 + }()
703 +}
704 +
705 func (r *leaseRegistry) issueRegisterChallenge(req types.RegisterChallengeRequest, domain, uri, clientIP string) (types.RegisterChallengeResponse, error) {
706 if r == nil {
707 return types.RegisterChallengeResponse{}, errFeatureUnavailable
portal/record.go
+27 -18
@@ -132,21 +132,38 @@ func (r *leaseRecord) Close() {
132 }
133 }
134
135 -func (r *leaseRecord) syncDNS(ctx context.Context, manager *acme.Manager, sniPort int) (bool, error) {
135 +func (r *leaseRecord) syncENSGaslessDNS(ctx context.Context, manager *acme.Manager) error {
136 if r == nil || manager == nil {
137 - return false, nil
137 + return nil
138 }
139 if ensHostname := r.ensGaslessDNSHostname(); ensHostname != "" {
140 if err := manager.SyncENSGaslessHostname(ctx, ensHostname, r.Address); err != nil {
141 - return false, err
141 + return err
142 }
143 }
144 - if r.hasECHDNSRecord() {
145 - if err := manager.SyncECHConfig(ctx, r.ECHDNSHostname, r.ECHConfigList, sniPort); err != nil {
146 - return true, err
147 - }
144 + return nil
145 +}
146 +
147 +func (r *leaseRecord) syncECHDNS(ctx context.Context, manager *acme.Manager, sniPort int) error {
148 + if r == nil || manager == nil || !r.hasECHDNSRecord() {
149 + return nil
150 + }
151 + return manager.SyncECHConfig(ctx, r.ECHDNSHostname, r.ECHConfigList, sniPort)
152 +}
153 +
154 +func (r *leaseRecord) deleteECHDNS(ctx context.Context, manager *acme.Manager) {
155 + if r == nil || manager == nil || !r.hasECHDNSRecord() {
156 + return
157 + }
158 + err := manager.DeleteECHConfig(ctx, r.ECHDNSHostname)
159 + if err != nil {
160 + log.Warn().
161 + Err(err).
162 + Str("hostname", r.ECHDNSHostname).
163 + Str("route_hostname", r.Hostname).
164 + Str("address", r.Address).
165 + Msg("delete ech dns record")
166 }
149 - return false, nil
167 }
168
169 func (r *leaseRecord) deleteDNS(ctx context.Context, manager *acme.Manager, includeECH bool) {
@@ -163,15 +180,7 @@ func (r *leaseRecord) deleteDNS(ctx context.Context, manager *acme.Manager, incl
180 Msg("delete ens gasless hostname")
181 }
182 }
166 - if includeECH && r.hasECHDNSRecord() {
167 - err := manager.DeleteECHConfig(ctx, r.ECHDNSHostname)
168 - if err != nil {
169 - log.Warn().
170 - Err(err).
171 - Str("hostname", r.ECHDNSHostname).
172 - Str("route_hostname", r.Hostname).
173 - Str("address", r.Address).
174 - Msg("delete ech dns record")
175 - }
183 + if includeECH {
184 + r.deleteECHDNS(ctx, manager)
185 }
186 }