From 0c2cc00c4f09d43c1d4884b24bbfe42ed6b2ac56 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 14 Apr 2025 22:58:04 +0700 Subject: [PATCH] Using ControlD bootstrap DNS again So on system where there's no available DNS, non-ControlD upstreams could be bootstrapped like before. While at it, also improving lookupIP to not initializing OS resolver anymore, removing the un-necessary contention for accquiring/releasing OS resolver mutex. --- config.go | 14 +++++++++++++- resolver.go | 23 +++++++++++------------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/config.go b/config.go index 626fc32..fdea19f 100644 --- a/config.go +++ b/config.go @@ -427,11 +427,18 @@ func (uc *UpstreamConfig) UID() string { // SetupBootstrapIP manually find all available IPs of the upstream. // The first usable IP will be used as bootstrap IP of the upstream. +// The upstream domain will be looked up using following orders: +// +// - Current system DNS settings. +// - Direct IPs table for ControlD upstreams. +// - ControlD Bootstrap DNS 76.76.2.22 +// +// The setup process will block until there's usable IPs found. func (uc *UpstreamConfig) SetupBootstrapIP() { b := backoff.NewBackoff("setupBootstrapIP", func(format string, args ...any) {}, 10*time.Second) isControlD := uc.IsControlD() for { - uc.bootstrapIPs = lookupIP(uc.Domain, uc.Timeout) + uc.bootstrapIPs = lookupIP(uc.Domain, uc.Timeout, defaultNameservers()) // For ControlD upstream, the bootstrap IPs could not be RFC 1918 addresses, // filtering them out here to prevent weird behavior. if isControlD { @@ -449,6 +456,11 @@ func (uc *UpstreamConfig) SetupBootstrapIP() { ProxyLogger.Load().Warn().Msgf("no record found for %q, lookup from direct IP table", uc.Domain) } } + if len(uc.bootstrapIPs) == 0 { + ProxyLogger.Load().Warn().Msgf("no record found for %q, using bootstrap server: %s", uc.Domain, PremiumDNSBoostrapIP) + uc.bootstrapIPs = lookupIP(uc.Domain, uc.Timeout, []string{net.JoinHostPort(PremiumDNSBoostrapIP, "53")}) + + } if len(uc.bootstrapIPs) > 0 { break } diff --git a/resolver.go b/resolver.go index 52a17fc..401a7f9 100644 --- a/resolver.go +++ b/resolver.go @@ -466,27 +466,26 @@ func (d dummyResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, err return ans, nil } -// LookupIP looks up host using OS resolver. +// LookupIP looks up domain using current system nameservers settings. // It returns a slice of that host's IPv4 and IPv6 addresses. func LookupIP(domain string) []string { - return lookupIP(domain, -1) + return lookupIP(domain, -1, defaultNameservers()) } -func lookupIP(domain string, timeout int) (ips []string) { +// lookupIP looks up domain with given timeout and bootstrapDNS. +// If timeout is negative, default timeout 2000 ms will be used. +// It returns nil if bootstrapDNS is nil or empty. +func lookupIP(domain string, timeout int, bootstrapDNS []string) (ips []string) { if net.ParseIP(domain) != nil { return []string{domain} } - resolverMutex.Lock() - if or == nil { - ProxyLogger.Load().Debug().Msgf("Initialize OS resolver in lookupIP") - or = newResolverWithNameserver(defaultNameservers()) + if bootstrapDNS == nil { + ProxyLogger.Load().Debug().Msgf("empty bootstrap DNS") + return nil } - nss := *or.lanServers.Load() - nss = append(nss, *or.publicServers.Load()...) - resolverMutex.Unlock() - resolver := newResolverWithNameserver(nss) - ProxyLogger.Load().Debug().Msgf("resolving %q using bootstrap DNS %q", domain, nss) + resolver := newResolverWithNameserver(bootstrapDNS) + ProxyLogger.Load().Debug().Msgf("resolving %q using bootstrap DNS %q", domain, bootstrapDNS) timeoutMs := 2000 if timeout > 0 && timeout < timeoutMs { timeoutMs = timeout