From 04d8f7c92759d6f0663621d6f00b0f33d75bc615 Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Mon, 22 Dec 2025 15:45:11 +0100 Subject: [PATCH] lookup for management domains using an additional timeout in some cases iOS and macOS may be locked when looking for management domains during network changes This change introduce an additional timeout on top of the context call --- client/internal/dns/mgmt/mgmt.go | 40 ++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/client/internal/dns/mgmt/mgmt.go b/client/internal/dns/mgmt/mgmt.go index 290395473..ceb73101a 100644 --- a/client/internal/dns/mgmt/mgmt.go +++ b/client/internal/dns/mgmt/mgmt.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "net/netip" "net/url" "strings" "sync" @@ -26,6 +27,11 @@ type Resolver struct { mutex sync.RWMutex } +type ipsResponse struct { + ips []netip.Addr + err error +} + // NewResolver creates a new management domains cache resolver. func NewResolver() *Resolver { return &Resolver{ @@ -99,9 +105,9 @@ func (m *Resolver) AddDomain(ctx context.Context, d domain.Domain) error { ctx, cancel := context.WithTimeout(ctx, dnsTimeout) defer cancel() - ips, err := net.DefaultResolver.LookupNetIP(ctx, "ip", d.PunycodeString()) + ips, err := lookupIPWithExtraTimeout(ctx, d) if err != nil { - return fmt.Errorf("resolve domain %s: %w", d.SafeString(), err) + return err } var aRecords, aaaaRecords []dns.RR @@ -159,6 +165,36 @@ func (m *Resolver) AddDomain(ctx context.Context, d domain.Domain) error { return nil } +func lookupIPWithExtraTimeout(ctx context.Context, d domain.Domain) ([]netip.Addr, error) { + log.Infof("looking up IP for mgmt domain=%s", d.SafeString()) + defer log.Infof("done looking up IP for mgmt domain=%s", d.SafeString()) + errChan := make(chan *ipsResponse, 1) + + go func() { + ips, err := net.DefaultResolver.LookupNetIP(ctx, "ip", d.PunycodeString()) + errChan <- &ipsResponse{ + err: err, + ips: ips, + } + }() + + var resp *ipsResponse + + select { + case <-time.After(dnsTimeout + time.Millisecond*500): + log.Warnf("timed out waiting for IP for mgmt domain=%s", d.SafeString()) + return nil, fmt.Errorf("timed out waiting for ips to be available for domain %s", d.SafeString()) + case <-ctx.Done(): + return nil, ctx.Err() + case resp = <-errChan: + } + + if resp.err != nil { + return nil, fmt.Errorf("resolve domain %s: %w", d.SafeString(), resp.err) + } + return resp.ips, nil +} + // PopulateFromConfig extracts and caches domains from the client configuration. func (m *Resolver) PopulateFromConfig(ctx context.Context, mgmtURL *url.URL) error { if mgmtURL == nil {