From: Mateusz Poliwczak Date: Fri, 20 Oct 2023 08:35:15 +0000 (+0000) Subject: net: set IsNotFound on windows and plan9 DNS queries X-Git-Tag: go1.22rc1~536 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=95974b379f925ee588cfae258144a117db25b0a2;p=gostls13.git net: set IsNotFound on windows and plan9 DNS queries Change-Id: I2a12acb3e4f31dd561d49f47a3b1ae3ac47ab894 GitHub-Last-Rev: 4733964f691c567ccad0279fb553442322543024 GitHub-Pull-Request: golang/go#63542 Reviewed-on: https://go-review.googlesource.com/c/go/+/534937 Auto-Submit: Ian Lance Taylor Reviewed-by: Benny Siegert Run-TryBot: Mateusz Poliwczak TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor Reviewed-by: Quim Muntal --- diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go index 9d2c4cda5b..8cfc4f6bb3 100644 --- a/src/net/lookup_plan9.go +++ b/src/net/lookup_plan9.go @@ -106,6 +106,22 @@ func queryDNS(ctx context.Context, addr string, typ string) (res []string, err e return query(ctx, netdir+"/dns", addr+" "+typ, 1024) } +func handlePlan9DNSError(err error, name string) error { + if stringsHasSuffix(err.Error(), "dns: name does not exist") || + stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode 0") || + stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode") { + return &DNSError{ + Err: errNoSuchHost.Error(), + Name: name, + IsNotFound: true, + } + } + return &DNSError{ + Err: err.Error(), + Name: name, + } +} + // toLower returns a lower-case version of in. Restricting us to // ASCII is sufficient to handle the IP protocol names and allow // us to not depend on the strings and unicode packages. @@ -153,12 +169,10 @@ func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, e // host names in local network (e.g. from /lib/ndb/local) lines, err := queryCS(ctx, "net", host, "1") if err != nil { - dnsError := &DNSError{Err: err.Error(), Name: host} if stringsHasSuffix(err.Error(), "dns failure") { - dnsError.Err = errNoSuchHost.Error() - dnsError.IsNotFound = true + return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} } - return nil, dnsError + return nil, handlePlan9DNSError(err, host) } loop: for _, line := range lines { @@ -252,10 +266,9 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (cname string, lines, err := queryDNS(ctx, name, "cname") if err != nil { if stringsHasSuffix(err.Error(), "dns failure") || stringsHasSuffix(err.Error(), "resource does not exist; negrcode 0") { - cname = name + "." - err = nil + return absDomainName(name), nil } - return + return "", handlePlan9DNSError(err, cname) } if len(lines) > 0 { if f := getFields(lines[0]); len(f) >= 3 { @@ -277,7 +290,7 @@ func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) ( } lines, err := queryDNS(ctx, target, "srv") if err != nil { - return + return "", nil, handlePlan9DNSError(err, name) } for _, line := range lines { f := getFields(line) @@ -303,7 +316,7 @@ func (r *Resolver) lookupMX(ctx context.Context, name string) (mx []*MX, err err } lines, err := queryDNS(ctx, name, "mx") if err != nil { - return + return nil, handlePlan9DNSError(err, name) } for _, line := range lines { f := getFields(line) @@ -324,7 +337,7 @@ func (r *Resolver) lookupNS(ctx context.Context, name string) (ns []*NS, err err } lines, err := queryDNS(ctx, name, "ns") if err != nil { - return + return nil, handlePlan9DNSError(err, name) } for _, line := range lines { f := getFields(line) @@ -342,7 +355,7 @@ func (r *Resolver) lookupTXT(ctx context.Context, name string) (txt []string, er } lines, err := queryDNS(ctx, name, "txt") if err != nil { - return + return nil, handlePlan9DNSError(err, name) } for _, line := range lines { if i := bytealg.IndexByteString(line, '\t'); i >= 0 { @@ -362,7 +375,7 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) (name []string, } lines, err := queryDNS(ctx, arpa, "ptr") if err != nil { - return + return nil, handlePlan9DNSError(err, addr) } for _, line := range lines { f := getFields(line) diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 1e222763bd..57ac9a933a 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -1524,3 +1524,125 @@ func allResolvers(t *testing.T, f func(t *testing.T)) { } }) } + +func TestLookupNoSuchHost(t *testing.T) { + mustHaveExternalNetwork(t) + + const testNXDOMAIN = "invalid.invalid." + const testNODATA = "_ldap._tcp.google.com." + + tests := []struct { + name string + query func() error + }{ + { + name: "LookupCNAME NXDOMAIN", + query: func() error { + _, err := LookupCNAME(testNXDOMAIN) + return err + }, + }, + { + name: "LookupHost NXDOMAIN", + query: func() error { + _, err := LookupHost(testNXDOMAIN) + return err + }, + }, + { + name: "LookupHost NODATA", + query: func() error { + _, err := LookupHost(testNODATA) + return err + }, + }, + { + name: "LookupMX NXDOMAIN", + query: func() error { + _, err := LookupMX(testNXDOMAIN) + return err + }, + }, + { + name: "LookupMX NODATA", + query: func() error { + _, err := LookupMX(testNODATA) + return err + }, + }, + { + name: "LookupNS NXDOMAIN", + query: func() error { + _, err := LookupNS(testNXDOMAIN) + return err + }, + }, + { + name: "LookupNS NODATA", + query: func() error { + _, err := LookupNS(testNODATA) + return err + }, + }, + { + name: "LookupSRV NXDOMAIN", + query: func() error { + _, _, err := LookupSRV("unknown", "tcp", testNXDOMAIN) + return err + }, + }, + { + name: "LookupTXT NXDOMAIN", + query: func() error { + _, err := LookupTXT(testNXDOMAIN) + return err + }, + }, + { + name: "LookupTXT NODATA", + query: func() error { + _, err := LookupTXT(testNODATA) + return err + }, + }, + } + + for _, v := range tests { + t.Run(v.name, func(t *testing.T) { + allResolvers(t, func(t *testing.T) { + attempts := 0 + for { + err := v.query() + if err == nil { + t.Errorf("unexpected success") + return + } + if dnsErr, ok := err.(*DNSError); ok { + succeeded := true + if !dnsErr.IsNotFound { + succeeded = false + t.Log("IsNotFound is set to false") + } + if dnsErr.Err != errNoSuchHost.Error() { + succeeded = false + t.Logf("error message is not equal to: %v", errNoSuchHost.Error()) + } + if succeeded { + return + } + } + testenv.SkipFlakyNet(t) + if attempts < len(backoffDuration) { + dur := backoffDuration[attempts] + t.Logf("backoff %v after failure %v\n", dur, err) + time.Sleep(dur) + attempts++ + continue + } + t.Errorf("unexpected error: %v", err) + return + } + }) + }) + } +} diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go index b6ef6da716..3048f3269b 100644 --- a/src/net/lookup_windows.go +++ b/src/net/lookup_windows.go @@ -20,6 +20,9 @@ import ( const cgoAvailable = true const ( + _DNS_ERROR_RCODE_NAME_ERROR = syscall.Errno(9003) + _DNS_INFO_NO_RECORDS = syscall.Errno(9501) + _WSAHOST_NOT_FOUND = syscall.Errno(11001) _WSATRY_AGAIN = syscall.Errno(11002) _WSATYPE_NOT_FOUND = syscall.Errno(10109) @@ -27,7 +30,7 @@ const ( func winError(call string, err error) error { switch err { - case _WSAHOST_NOT_FOUND: + case _WSAHOST_NOT_FOUND, _DNS_ERROR_RCODE_NAME_ERROR, _DNS_INFO_NO_RECORDS: return errNoSuchHost } return os.NewSyscallError(call, err) @@ -271,7 +274,8 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) return absDomainName(name), nil } if e != nil { - return "", &DNSError{Err: winError("dnsquery", e).Error(), Name: name} + err := winError("dnsquery", e) + return "", &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} } defer syscall.DnsRecordListFree(rec, 1) @@ -296,7 +300,8 @@ func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) ( var rec *syscall.DNSRecord e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &rec, nil) if e != nil { - return "", nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: target} + err := winError("dnsquery", e) + return "", nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} } defer syscall.DnsRecordListFree(rec, 1) @@ -319,7 +324,8 @@ func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) { var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &rec, nil) if e != nil { - return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name} + err := winError("dnsquery", e) + return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} } defer syscall.DnsRecordListFree(rec, 1) @@ -342,7 +348,8 @@ func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) { var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &rec, nil) if e != nil { - return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name} + err := winError("dnsquery", e) + return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} } defer syscall.DnsRecordListFree(rec, 1) @@ -364,7 +371,8 @@ func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &rec, nil) if e != nil { - return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name} + err := winError("dnsquery", e) + return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} } defer syscall.DnsRecordListFree(rec, 1) @@ -395,7 +403,8 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error var rec *syscall.DNSRecord e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &rec, nil) if e != nil { - return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: addr} + err := winError("dnsquery", e) + return nil, &DNSError{Err: err.Error(), Name: addr, IsNotFound: err == errNoSuchHost} } defer syscall.DnsRecordListFree(rec, 1)