From 773d8cc95915e5f4b469af57f6130ebf0ab55d59 Mon Sep 17 00:00:00 2001 From: Mechiel Lukkien Date: Fri, 21 Mar 2025 18:42:02 +0100 Subject: [PATCH] update to latest github.com/mjl-/adns, synced to go1.24.1 --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/mjl-/adns/Makefile | 3 +- vendor/github.com/mjl-/adns/conf.go | 58 ++++++++------- vendor/github.com/mjl-/adns/dnsclient.go | 40 ++++++---- vendor/github.com/mjl-/adns/dnsclient_unix.go | 74 ++++++------------- vendor/github.com/mjl-/adns/dnsconfig.go | 20 ++++- .../github.com/mjl-/adns/dnsconfig_windows.go | 27 ++++--- vendor/github.com/mjl-/adns/doc.go | 3 +- .../github.com/mjl-/adns/interface_windows.go | 3 +- vendor/github.com/mjl-/adns/lookup.go | 33 +++------ vendor/github.com/mjl-/adns/net.go | 65 +++++++++++++--- vendor/github.com/mjl-/adns/parse.go | 11 --- vendor/modules.txt | 4 +- 14 files changed, 188 insertions(+), 159 deletions(-) diff --git a/go.mod b/go.mod index abe0d75..537fbb3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/mjl-/mox go 1.22.0 require ( - github.com/mjl-/adns v0.0.0-20240509092456-2dc8715bf4af + github.com/mjl-/adns v0.0.0-20250321173553-ab04b05bdfea github.com/mjl-/autocert v0.0.0-20231214125928-31b7400acb05 github.com/mjl-/bstore v0.0.6 github.com/mjl-/flate v0.0.0-20250221133712-6372d09eb978 diff --git a/go.sum b/go.sum index c7a11cc..f24b6c8 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/mjl-/adns v0.0.0-20240509092456-2dc8715bf4af h1:sEDWZPIi5K1qKk7JQoAZyDwXkRQseIf7y5ony8JeYEQ= -github.com/mjl-/adns v0.0.0-20240509092456-2dc8715bf4af/go.mod h1:v47qUMJnipnmDTRGaHwpCwzE6oypa5K33mUvBfzZBn8= +github.com/mjl-/adns v0.0.0-20250321173553-ab04b05bdfea h1:8dftsVL1tHhRksXzFZRhSJ7gSlcy/t87Nvucs3JnTGE= +github.com/mjl-/adns v0.0.0-20250321173553-ab04b05bdfea/go.mod h1:rWZMqGA2HoBm5b5q/A5J8u1sSVuEYh6zBz9tMoVs+RU= github.com/mjl-/autocert v0.0.0-20231214125928-31b7400acb05 h1:s6ay4bh4tmpPLdxjyeWG45mcwHfEluBMuGPkqxHWUJ4= github.com/mjl-/autocert v0.0.0-20231214125928-31b7400acb05/go.mod h1:taMFU86abMxKLPV4Bynhv8enbYmS67b8LG80qZv2Qus= github.com/mjl-/bstore v0.0.6 h1:ntlu9MkfCkpm2XfBY4+Ws4KK9YzXzewr3+lCueFB+9c= diff --git a/vendor/github.com/mjl-/adns/Makefile b/vendor/github.com/mjl-/adns/Makefile index 72b9664..89a0402 100644 --- a/vendor/github.com/mjl-/adns/Makefile +++ b/vendor/github.com/mjl-/adns/Makefile @@ -8,7 +8,8 @@ test: check: GOARCH=386 go vet - staticcheck ./... + # don't warn about using deprecated functions like net.Temporary + staticcheck -checks inherit,-SA1019 ./... # having "err" shadowed is common, best to not have others check-shadow: diff --git a/vendor/github.com/mjl-/adns/conf.go b/vendor/github.com/mjl-/adns/conf.go index b8ae568..33e15a3 100644 --- a/vendor/github.com/mjl-/adns/conf.go +++ b/vendor/github.com/mjl-/adns/conf.go @@ -11,8 +11,8 @@ import ( "io/fs" "os" "runtime" + "strings" "sync" - "syscall" "github.com/mjl-/adns/internal/bytealg" ) @@ -99,19 +99,30 @@ func initConfVal() { if confVal.dnsDebugLevel > 1 { println("go package net: confVal.netCgo =", confVal.netCgo, " netGo =", confVal.netGo) } + if dnsMode != "go" && dnsMode != "cgo" && dnsMode != "" { + println("go package net: GODEBUG=netdns contains an invalid dns mode, ignoring it") + } switch { - case confVal.netGo: - if netGoBuildTag { - println("go package net: built with netgo build tag; using Go's DNS resolver") + case netGoBuildTag || !cgoAvailable: + if dnsMode == "cgo" { + println("go package net: ignoring GODEBUG=netdns=cgo as the binary was compiled without support for the cgo resolver") } else { - println("go package net: GODEBUG setting forcing use of Go's resolver") + println("go package net: using the Go DNS resolver") + } + case netCgoBuildTag: + if dnsMode == "go" { + println("go package net: GODEBUG setting forcing use of the Go resolver") + } else { + println("go package net: using the cgo DNS resolver") } - case !cgoAvailable: - println("go package net: cgo resolver not supported; using Go's DNS resolver") - case confVal.netCgo || confVal.preferCgo: - println("go package net: using cgo DNS resolver") default: - println("go package net: dynamic selection of DNS resolver") + if dnsMode == "go" { + println("go package net: GODEBUG setting forcing use of the Go resolver") + } else if dnsMode == "cgo" { + println("go package net: GODEBUG setting forcing use of the cgo resolver") + } else { + println("go package net: dynamic selection of DNS resolver") + } } }() } @@ -143,7 +154,7 @@ func initConfVal() { // prefer the cgo resolver. // Note that LOCALDOMAIN can change behavior merely by being // specified with the empty string. - _, localDomainDefined := syscall.Getenv("LOCALDOMAIN") + _, localDomainDefined := os.LookupEnv("LOCALDOMAIN") if localDomainDefined || os.Getenv("RES_OPTIONS") != "" || os.Getenv("HOSTALIASES") != "" { confVal.preferCgo = true return @@ -324,16 +335,7 @@ func (c *conf) lookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, d } // Canonicalize the hostname by removing any trailing dot. - if stringsHasSuffix(hostname, ".") { - hostname = hostname[:len(hostname)-1] - } - if canUseCgo && stringsHasSuffixFold(hostname, ".local") { - // Per RFC 6762, the ".local" TLD is special. And - // because Go's native resolver doesn't do mDNS or - // similar local resolution mechanisms, assume that - // libc might (via Avahi, etc) and use cgo. - return hostLookupCgo, dnsConf - } + hostname = strings.TrimSuffix(hostname, ".") nss := getSystemNSS() srcs := nss.sources["hosts"] @@ -392,10 +394,14 @@ func (c *conf) lookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, d return hostLookupCgo, dnsConf } continue - case hostname != "" && stringsHasPrefix(src.source, "mdns"): - // e.g. "mdns4", "mdns4_minimal" - // We already returned true before if it was *.local. - // libc wouldn't have found a hit on this anyway. + case hostname != "" && strings.HasPrefix(src.source, "mdns"): + if stringsHasSuffixFold(hostname, ".local") { + // Per RFC 6762, the ".local" TLD is special. And + // because Go's native resolver doesn't do mDNS or + // similar local resolution mechanisms, assume that + // libc might (via Avahi, etc) and use cgo. + return hostLookupCgo, dnsConf + } // We don't parse mdns.allow files. They're rare. If one // exists, it might list other TLDs (besides .local) or even @@ -492,7 +498,7 @@ func isGateway(h string) bool { return stringsEqualFold(h, "_gateway") } -// isOutbound reports whether h should be considered a "outbound" +// isOutbound reports whether h should be considered an "outbound" // name for the myhostname NSS module. func isOutbound(h string) bool { return stringsEqualFold(h, "_outbound") diff --git a/vendor/github.com/mjl-/adns/dnsclient.go b/vendor/github.com/mjl-/adns/dnsclient.go index 0d48607..22a00a0 100644 --- a/vendor/github.com/mjl-/adns/dnsclient.go +++ b/vendor/github.com/mjl-/adns/dnsclient.go @@ -5,9 +5,10 @@ package adns import ( - mathrand "math/rand" + "cmp" + mathrand "math/rand/v2" "net" - "sort" + "slices" "golang.org/x/net/dns/dnsmessage" @@ -16,7 +17,7 @@ import ( ) func randInt() int { - return mathrand.Int() + return int(uint(mathrand.Uint64()) >> 1) // clear sign bit } func randIntn(n int) int { @@ -72,6 +73,16 @@ func equalASCIIName(x, y dnsmessage.Name) bool { // isDomainName checks if a string is a presentation-format domain name // (currently restricted to hostname-compatible "preferred name" LDH labels and // SRV-like "underscore labels"; see golang.org/issue/12421). +// +// isDomainName should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// disabled: go:linkname isDomainName func isDomainName(s string) bool { // The root domain name is valid. See golang.org/issue/45715. if s == "." { @@ -149,12 +160,6 @@ func absDomainName(s string) string { // byPriorityWeight sorts SRV records by ascending priority and weight. type byPriorityWeight []*net.SRV -func (s byPriorityWeight) Len() int { return len(s) } -func (s byPriorityWeight) Less(i, j int) bool { - return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) -} -func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // shuffleByWeight shuffles SRV records by weight using the algorithm // described in RFC 2782. func (addrs byPriorityWeight) shuffleByWeight() { @@ -181,7 +186,12 @@ func (addrs byPriorityWeight) shuffleByWeight() { // sort reorders SRV records as specified in RFC 2782. func (addrs byPriorityWeight) sort() { - sort.Sort(addrs) + slices.SortFunc(addrs, func(a, b *net.SRV) int { + if r := cmp.Compare(a.Priority, b.Priority); r != 0 { + return r + } + return cmp.Compare(a.Weight, b.Weight) + }) i := 0 for j := 1; j < len(addrs); j++ { if addrs[i].Priority != addrs[j].Priority { @@ -192,18 +202,16 @@ func (addrs byPriorityWeight) sort() { addrs[i:].shuffleByWeight() } -// byPref implements sort.Interface to sort MX records by preference +// byPref sorts MX records by preference type byPref []*net.MX -func (s byPref) Len() int { return len(s) } -func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } -func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // sort reorders MX records as specified in RFC 5321. func (s byPref) sort() { for i := range s { j := randIntn(i + 1) s[i], s[j] = s[j], s[i] } - sort.Sort(s) + slices.SortFunc(s, func(a, b *net.MX) int { + return cmp.Compare(a.Pref, b.Pref) + }) } diff --git a/vendor/github.com/mjl-/adns/dnsclient_unix.go b/vendor/github.com/mjl-/adns/dnsclient_unix.go index f744a7b..e0c2f1f 100644 --- a/vendor/github.com/mjl-/adns/dnsclient_unix.go +++ b/vendor/github.com/mjl-/adns/dnsclient_unix.go @@ -23,6 +23,7 @@ import ( "net" "os" "runtime" + "strings" "sync" "sync/atomic" "time" @@ -54,7 +55,7 @@ var ( // errServerTemporarilyMisbehaving is like errServerMisbehaving, except // that when it gets translated to a DNSError, the IsTemporary field // gets set to true. - errServerTemporarilyMisbehaving = errors.New("server misbehaving") + errServerTemporarilyMisbehaving = &temporaryError{"server misbehaving"} ) func newRequest(q dnsmessage.Question, ad bool) (id uint16, udpReq, tcpReq []byte, err error) { @@ -346,7 +347,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, n, err := dnsmessage.NewName(name) if err != nil { - return dnsmessage.Parser{}, "", Result{}, errCannotMarshalDNSMessage + return dnsmessage.Parser{}, "", Result{}, &DNSError{Err: errCannotMarshalDNSMessage.Error(), Name: name} } q := dnsmessage.Question{ Name: n, @@ -360,14 +361,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD) if err != nil { - dnsErr := &DNSError{ - Err: err.Error(), - Name: name, - Server: server, - } - if nerr, ok := err.(net.Error); ok && nerr.Timeout() { - dnsErr.IsTimeout = true - } + dnsErr := newDNSError(err, name, server) // Set IsTemporary for socket-level errors. Note that this flag // may also be used to indicate a SERVFAIL response. if _, ok := err.(*net.OpError); ok { @@ -381,49 +375,27 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, result := Result{Authentic: cfg.trustAD && h.AuthenticData && useAD} if err := checkHeader(&p, h); err != nil { - dnsErr := &DNSError{ - Underlying: err, - Err: err.Error(), - Name: name, - Server: server, - } - if err == errServerTemporarilyMisbehaving { - dnsErr.IsTemporary = true - } else if edeErr, isEDE := err.(ExtendedError); isEDE && edeErr.IsTemporary() { - dnsErr.IsTemporary = true - } else if isEDE { - // Something wrong with the zone, no point asking another server or retrying. - return p, server, result, dnsErr - } if err == errNoSuchHost { // The name does not exist, so trying // another server won't help. - - dnsErr.IsNotFound = true - return p, server, result, dnsErr + return p, server, result, newDNSError(errNoSuchHost, name, server) } - lastErr = dnsErr + lastErr = newDNSError(err, name, server) lastResult = result continue } - err = skipToAnswer(&p, qtype) - if err == nil { - return p, server, result, nil - } - lastErr = &DNSError{ - Err: err.Error(), - Name: name, - Server: server, - } - lastResult = result - if err == errNoSuchHost { - // The name does not exist, so trying another - // server won't help. - - lastErr.(*DNSError).IsNotFound = true - return p, server, lastResult, lastErr + if err := skipToAnswer(&p, qtype); err != nil { + if err == errNoSuchHost { + // The name does not exist, so trying + // another server won't help. + return p, server, result, newDNSError(errNoSuchHost, name, server) + } + lastErr = newDNSError(err, name, server) + lastResult = result + continue } + return p, server, result, nil } } return dnsmessage.Parser{}, "", lastResult, lastErr @@ -523,7 +495,7 @@ func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Typ // Other lookups might allow broader name syntax // (for example Multicast DNS allows UTF-8; see RFC 6762). // For consistency with libc resolvers, report no such host. - return dnsmessage.Parser{}, "", Result{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return dnsmessage.Parser{}, "", Result{}, newDNSError(errNoSuchHost, name, "") } if conf == nil { @@ -568,9 +540,7 @@ func avoidDNS(name string) bool { if name == "" { return true } - if name[len(name)-1] == '.' { - name = name[:len(name)-1] - } + name = strings.TrimSuffix(name, ".") return stringsHasSuffixFold(name, ".onion") } @@ -653,7 +623,7 @@ func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hos } if order == hostLookupFiles { - return nil, result, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, result, newDNSError(errNoSuchHost, name, "") } } ips, _, result, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order, conf) @@ -704,13 +674,13 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name strin } if order == hostLookupFiles { - return nil, dnsmessage.Name{}, result, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, dnsmessage.Name{}, result, newDNSError(errNoSuchHost, name, "") } } if !isDomainName(name) { // See comment in func lookup above about use of errNoSuchHost. - return nil, dnsmessage.Name{}, result, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, dnsmessage.Name{}, result, newDNSError(errNoSuchHost, name, "") } type result0 struct { p dnsmessage.Parser @@ -920,7 +890,7 @@ func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLooku } if order == hostLookupFiles { - return nil, Result{}, &DNSError{Err: errNoSuchHost.Error(), Name: addr, IsNotFound: true} + return nil, Result{}, newDNSError(errNoSuchHost, addr, "") } } diff --git a/vendor/github.com/mjl-/adns/dnsconfig.go b/vendor/github.com/mjl-/adns/dnsconfig.go index 5d0fb19..b65e0fe 100644 --- a/vendor/github.com/mjl-/adns/dnsconfig.go +++ b/vendor/github.com/mjl-/adns/dnsconfig.go @@ -10,10 +10,22 @@ import ( "time" ) -var ( - defaultNS = []string{"127.0.0.1:53", "[::1]:53"} - getHostname = os.Hostname // variable for testing -) +// defaultNS is the default name servers to use in the absence of DNS configuration. +// +// defaultNS should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/pojntfx/hydrapp/hydrapp +// - github.com/mtibben/androiddnsfix +// - github.com/metacubex/mihomo +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// disabled: go:linkname defaultNS +var defaultNS = []string{"127.0.0.1:53", "[::1]:53"} + +var getHostname = os.Hostname // variable for testing type dnsConfig struct { servers []string // server addresses (in host:port form) to use diff --git a/vendor/github.com/mjl-/adns/dnsconfig_windows.go b/vendor/github.com/mjl-/adns/dnsconfig_windows.go index bb703c2..e21ef50 100644 --- a/vendor/github.com/mjl-/adns/dnsconfig_windows.go +++ b/vendor/github.com/mjl-/adns/dnsconfig_windows.go @@ -27,16 +27,19 @@ func dnsReadConfig(ignoredFilename string) (conf *dnsConfig) { if err != nil { return } - // TODO(bradfitz): this just collects all the DNS servers on all - // the interfaces in some random order. It should order it by - // default route, or only use the default route(s) instead. - // In practice, however, it mostly works. + for _, aa := range aas { + // Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs. + if aa.OperStatus != windows.IfOperStatusUp { + continue + } + + // Only take interfaces which have at least one gateway + if aa.FirstGatewayAddress == nil { + continue + } + for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { - // Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs. - if aa.OperStatus != windows.IfOperStatusUp { - continue - } sa, err := dns.Address.Sockaddr.Sockaddr() if err != nil { continue @@ -49,9 +52,11 @@ func dnsReadConfig(ignoredFilename string) (conf *dnsConfig) { ip = make(net.IP, net.IPv6len) copy(ip, sa.Addr[:]) if ip[0] == 0xfe && ip[1] == 0xc0 { - // Ignore these fec0/10 ones. Windows seems to - // populate them as defaults on its misc rando - // interfaces. + // fec0/10 IPv6 addresses are site local anycast DNS + // addresses Microsoft sets by default if no other + // IPv6 DNS address is set. Site local anycast is + // deprecated since 2004, see + // https://datatracker.ietf.org/doc/html/rfc3879 continue } default: diff --git a/vendor/github.com/mjl-/adns/doc.go b/vendor/github.com/mjl-/adns/doc.go index f4dd410..9e38952 100644 --- a/vendor/github.com/mjl-/adns/doc.go +++ b/vendor/github.com/mjl-/adns/doc.go @@ -14,7 +14,6 @@ Modifications are still also trusted if /etc/resolv.conf has "trust-ad" in the "options". - New function LookupTLSA, to support DANE which uses DNS records of type TLSA. - Support Extended DNS Errors (EDE) for details about DNSSEC errors. - - adns uses its own DNSError type, with an additional "Underlying error" field - and Unwrap function, so callers can check for the new ExtendedError type. + - adns.DNSError wraps ExtendedError for EDE. */ package adns diff --git a/vendor/github.com/mjl-/adns/interface_windows.go b/vendor/github.com/mjl-/adns/interface_windows.go index f7fb862..063c691 100644 --- a/vendor/github.com/mjl-/adns/interface_windows.go +++ b/vendor/github.com/mjl-/adns/interface_windows.go @@ -21,7 +21,8 @@ func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { l := uint32(15000) // recommended initial size for { b = make([]byte, l) - err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) + const flags = windows.GAA_FLAG_INCLUDE_PREFIX | windows.GAA_FLAG_INCLUDE_GATEWAYS + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, flags, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) if err == nil { if l == 0 { return nil, nil diff --git a/vendor/github.com/mjl-/adns/lookup.go b/vendor/github.com/mjl-/adns/lookup.go index 66f1dc2..960960e 100644 --- a/vendor/github.com/mjl-/adns/lookup.go +++ b/vendor/github.com/mjl-/adns/lookup.go @@ -106,7 +106,7 @@ func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, er if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { return port, nil } - return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, errNetwork+"/"+service, "") } return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service} } @@ -193,7 +193,7 @@ func LookupHost(host string) (addrs []string, result Result, err error) { func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, result Result, err error) { // Make sure that no matter what we do later, host=="" is rejected. if host == "" { - return nil, result, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} + return nil, result, newDNSError(errNoSuchHost, host, "") } if _, err := netip.ParseAddr(host); err == nil { return []string{host}, result, nil @@ -237,7 +237,7 @@ func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]net.IP } if host == "" { - return nil, Result{}, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} + return nil, Result{}, newDNSError(errNoSuchHost, host, "") } addrs, result, err := r.internetAddrList(ctx, afnet, host) if err != nil { @@ -305,7 +305,7 @@ func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context { func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]net.IPAddr, Result, error) { // Make sure that no matter what we do later, host=="" is rejected. if host == "" { - return nil, Result{}, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} + return nil, Result{}, newDNSError(errNoSuchHost, host, "") } if ip, err := netip.ParseAddr(host); err == nil { return []net.IPAddr{{IP: net.IP(ip.AsSlice()).To16(), Zone: ip.Zone()}}, Result{}, nil @@ -354,12 +354,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]ne } else { go dnsWaitGroupDone(ch, lookupGroupCancel) } - ctxErr := ctx.Err() - err := &DNSError{ - Err: mapErr(ctxErr).Error(), - Name: host, - IsTimeout: ctxErr == context.DeadlineExceeded, - } + err := newDNSError(mapErr(ctx.Err()), host, "") return nil, Result{}, err case r := <-ch: dnsWaitGroup.Done() @@ -367,17 +362,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]ne err := r.Err if err != nil { if _, ok := err.(*DNSError); !ok { - isTimeout := false - if err == context.DeadlineExceeded { - isTimeout = true - } else if terr, ok := err.(timeout); ok { - isTimeout = terr.Timeout() - } - err = &DNSError{ - Err: err.Error(), - Name: host, - IsTimeout: isTimeout, - } + err = newDNSError(mapErr(err), host, "") } } tuple := r.Val.(Tuple) @@ -614,6 +599,9 @@ func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*net.NS, Result // LookupTXT returns the DNS TXT records for the given domain name. // +// If a DNS TXT record holds multiple strings, they are concatenated as a +// single string. +// // LookupTXT uses context.Background internally; to specify the context, use // Resolver.LookupTXT. func LookupTXT(name string) ([]string, Result, error) { @@ -621,6 +609,9 @@ func LookupTXT(name string) ([]string, Result, error) { } // LookupTXT returns the DNS TXT records for the given domain name. +// +// If a DNS TXT record holds multiple strings, they are concatenated as a +// single string. func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, Result, error) { return r.lookupTXT(ctx, name) } diff --git a/vendor/github.com/mjl-/adns/net.go b/vendor/github.com/mjl-/adns/net.go index 6e9bc29..8c069c1 100644 --- a/vendor/github.com/mjl-/adns/net.go +++ b/vendor/github.com/mjl-/adns/net.go @@ -7,6 +7,7 @@ package adns import ( "context" "errors" + "net" ) // Various errors contained in OpError. @@ -39,15 +40,26 @@ func mapErr(err error) error { } } -type timeout interface { - Timeout() bool -} - // Various errors contained in DNSError. var ( - errNoSuchHost = errors.New("no such host") + errNoSuchHost = ¬FoundError{"no such host"} + errUnknownPort = ¬FoundError{"unknown port"} ) +// notFoundError is a special error understood by the newDNSError function, +// which causes a creation of a DNSError with IsNotFound field set to true. +type notFoundError struct{ s string } + +func (e *notFoundError) Error() string { return e.s } + +// temporaryError is an error type that implements the [Error] interface. +// It returns true from the Temporary method. +type temporaryError struct{ s string } + +func (e *temporaryError) Error() string { return e.s } +func (e *temporaryError) Temporary() bool { return true } +func (e *temporaryError) Timeout() bool { return false } + // errTimeout exists to return the historical "i/o timeout" string // for context.DeadlineExceeded. See mapErr. // It is also used when Dialer.Deadline is exceeded. @@ -73,7 +85,7 @@ func (e *timeoutError) Is(err error) bool { // DNSError represents a DNS lookup error. type DNSError struct { - Underlying error // Underlying error, could be an ExtendedError. + UnwrapErr error // error returned by the [DNSError.Unwrap] method, might be nil Err string // description of the error Name string // name looked for Server string // server used @@ -86,11 +98,46 @@ type DNSError struct { IsNotFound bool } -// Unwrap returns the underlying error, which could be an ExtendedError. -func (e *DNSError) Unwrap() error { - return e.Underlying +// newDNSError creates a new *DNSError. +// Based on the err, it sets the UnwrapErr, IsTimeout, IsTemporary, IsNotFound fields. +func newDNSError(err error, name, server string) *DNSError { + var ( + isTimeout bool + isTemporary bool + unwrapErr error + ) + + if err, ok := err.(net.Error); ok { + isTimeout = err.Timeout() + isTemporary = err.Temporary() + } + + // At this time, the only errors we wrap are context errors, to allow + // users to check for canceled/timed out requests. + if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) { + unwrapErr = err + } else if edeErr, ok := err.(ExtendedError); ok { + unwrapErr = edeErr + if edeErr.IsTemporary() { + isTemporary = true + } + } + + _, isNotFound := err.(*notFoundError) + return &DNSError{ + UnwrapErr: unwrapErr, + Err: err.Error(), + Name: name, + Server: server, + IsTimeout: isTimeout, + IsTemporary: isTemporary, + IsNotFound: isNotFound, + } } +// Unwrap returns e.UnwrapErr. +func (e *DNSError) Unwrap() error { return e.UnwrapErr } + func (e *DNSError) Error() string { if e == nil { return "" diff --git a/vendor/github.com/mjl-/adns/parse.go b/vendor/github.com/mjl-/adns/parse.go index 1402356..ec55495 100644 --- a/vendor/github.com/mjl-/adns/parse.go +++ b/vendor/github.com/mjl-/adns/parse.go @@ -213,23 +213,12 @@ func foreachField(x string, fn func(field string) error) error { return nil } -// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in -// suffix. -func stringsHasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} - // stringsHasSuffixFold reports whether s ends in suffix, // ASCII-case-insensitively. func stringsHasSuffixFold(s, suffix string) bool { return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix) } -// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix. -func stringsHasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[:len(prefix)] == prefix -} - // stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t // are equal, ASCII-case-insensitively. func stringsEqualFold(s, t string) bool { diff --git a/vendor/modules.txt b/vendor/modules.txt index 7c45af5..7ba0d63 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -7,8 +7,8 @@ github.com/cespare/xxhash/v2 # github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 ## explicit; go 1.19 github.com/matttproud/golang_protobuf_extensions/v2/pbutil -# github.com/mjl-/adns v0.0.0-20240509092456-2dc8715bf4af -## explicit; go 1.20 +# github.com/mjl-/adns v0.0.0-20250321173553-ab04b05bdfea +## explicit; go 1.22 github.com/mjl-/adns github.com/mjl-/adns/internal/bytealg github.com/mjl-/adns/internal/itoa