diff options
author | Shubham Sharma <shubham.sha12@gmail.com> | 2019-03-21 21:10:12 +0530 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2019-04-23 14:11:33 +0000 |
commit | fac3b5d05ecf31a2491949cc905312a34e272ae8 (patch) | |
tree | 4a82ef10460246d855e9ece69b40addfbfe561b2 | |
parent | 7e08c7f43da876bc451b774808e323215a193abd (diff) | |
download | go-fac3b5d05ecf31a2491949cc905312a34e272ae8.tar.gz go-fac3b5d05ecf31a2491949cc905312a34e272ae8.zip |
net: add IsNotFound field to DNSError
This adds the ability to determine if a lookup error was
due to a non-existent hostname. Previously users needed
to do string matching on the DNSError.Err value.
Fixes #28635
Change-Id: If4bd3ad32cbc2db5614f2c6b72e0a9161d813efa
Reviewed-on: https://go-review.googlesource.com/c/go/+/168597
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
-rw-r--r-- | src/net/cgo_unix.go | 5 | ||||
-rw-r--r-- | src/net/dnsclient_unix.go | 15 | ||||
-rw-r--r-- | src/net/dnsclient_unix_test.go | 38 | ||||
-rw-r--r-- | src/net/lookup.go | 4 | ||||
-rw-r--r-- | src/net/lookup_test.go | 3 | ||||
-rw-r--r-- | src/net/lookup_windows.go | 21 | ||||
-rw-r--r-- | src/net/net.go | 1 |
7 files changed, 68 insertions, 19 deletions
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go index 6420fd05e7..2baab5f193 100644 --- a/src/net/cgo_unix.go +++ b/src/net/cgo_unix.go @@ -158,6 +158,7 @@ func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err e var res *C.struct_addrinfo gerrno, err := C.getaddrinfo((*C.char)(unsafe.Pointer(&h[0])), nil, &hints, &res) if gerrno != 0 { + isErrorNoSuchHost := false switch gerrno { case C.EAI_SYSTEM: if err == nil { @@ -172,10 +173,12 @@ func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err e } case C.EAI_NONAME: err = errNoSuchHost + isErrorNoSuchHost = true default: err = addrinfoErrno(gerrno) } - return nil, "", &DNSError{Err: err.Error(), Name: name} + + return nil, "", &DNSError{Err: err.Error(), Name: name, IsNotFound: isErrorNoSuchHost} } defer C.freeaddrinfo(res) diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index 7ed4ea8708..478ee51a81 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -284,10 +284,8 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, if err == errNoSuchHost { // The name does not exist, so trying // another server won't help. - // - // TODO: indicate this in a more - // obvious way, such as a field on - // DNSError? + + dnsErr.IsNotFound = true return p, server, dnsErr } lastErr = dnsErr @@ -306,9 +304,8 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, if err == errNoSuchHost { // The name does not exist, so trying another // server won't help. - // - // TODO: indicate this in a more obvious way, - // such as a field on DNSError? + + lastErr.(*DNSError).IsNotFound = true return p, server, lastErr } } @@ -398,7 +395,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{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name} + return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} } resolvConf.tryUpdate("/etc/resolv.conf") resolvConf.mu.RLock() @@ -575,7 +572,7 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, name string, order } if !isDomainName(name) { // See comment in func lookup above about use of errNoSuchHost. - return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name} + return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} } resolvConf.tryUpdate("/etc/resolv.conf") resolvConf.mu.RLock() diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index f1ed58c837..1b67494e51 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -666,7 +666,7 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) { wantErr *DNSError }{ {true, &DNSError{Name: fqdn, Err: "server misbehaving", IsTemporary: true}}, - {false, &DNSError{Name: fqdn, Err: errNoSuchHost.Error()}}, + {false, &DNSError{Name: fqdn, Err: errNoSuchHost.Error(), IsNotFound: true}}, } for _, tt := range cases { r := Resolver{PreferGo: true, StrictErrors: tt.strictErrors, Dial: fake.DialContext} @@ -1138,9 +1138,10 @@ func TestStrictErrorsLookupIP(t *testing.T) { } makeNxDomain := func() error { return &DNSError{ - Err: errNoSuchHost.Error(), - Name: name, - Server: server, + Err: errNoSuchHost.Error(), + Name: name, + Server: server, + IsNotFound: true, } } @@ -1472,6 +1473,32 @@ func TestIssue8434(t *testing.T) { } } +func TestIssueNoSuchHostExists(t *testing.T) { + err := lookupWithFake(fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + return dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.ID, + Response: true, + RCode: dnsmessage.RCodeNameError, + }, + Questions: q.Questions, + }, nil + }, + }, "golang.org.", dnsmessage.TypeALL) + if err == nil { + t.Fatal("expected an error") + } + if _, ok := err.(Error); !ok { + t.Fatalf("err = %#v; wanted something supporting net.Error", err) + } + if de, ok := err.(*DNSError); !ok { + t.Fatalf("err = %#v; wanted a *net.DNSError", err) + } else if !de.IsNotFound { + t.Fatalf("IsNotFound = false for err = %#v; want IsNotFound == true", err) + } +} + // TestNoSuchHost verifies that tryOneName works correctly when the domain does // not exist. // @@ -1541,6 +1568,9 @@ func TestNoSuchHost(t *testing.T) { if de.Err != errNoSuchHost.Error() { t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error()) } + if !de.IsNotFound { + t.Fatalf("IsNotFound = %v wanted true", de.IsNotFound) + } }) } } diff --git a/src/net/lookup.go b/src/net/lookup.go index 0af1e2c289..24d0d25c3a 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -177,7 +177,7 @@ func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, // Make sure that no matter what we do later, host=="" is rejected. // parseIP, for example, does accept empty strings. if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} + return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} } if ip, _ := parseIPZone(host); ip != nil { return []string{host}, nil @@ -238,7 +238,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP // Make sure that no matter what we do later, host=="" is rejected. // parseIP, for example, does accept empty strings. if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} + return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} } if ip, zone := parseIPZone(host); ip != nil { return []IPAddr{{IP: ip, Zone: zone}}, nil diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 28a895e15d..ed477a78c9 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -877,6 +877,9 @@ func TestLookupNonLDH(t *testing.T) { if !strings.HasSuffix(err.Error(), errNoSuchHost.Error()) { t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost) } + if !err.(*DNSError).IsNotFound { + t.Fatalf("lookup error = %v, want true", err.(*DNSError).IsNotFound) + } } func TestLookupContextCancel(t *testing.T) { diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go index 8a68d18a67..cd071c54b0 100644 --- a/src/net/lookup_windows.go +++ b/src/net/lookup_windows.go @@ -56,7 +56,12 @@ func lookupProtocol(ctx context.Context, name string) (int, error) { if proto, err := lookupProtocolMap(name); err == nil { return proto, nil } - r.err = &DNSError{Err: r.err.Error(), Name: name} + + dnsError := &DNSError{Err: r.err.Error(), Name: name} + if r.err == errNoSuchHost { + dnsError.IsNotFound = true + } + r.err = dnsError } return r.proto, r.err case <-ctx.Done(): @@ -98,7 +103,12 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr var result *syscall.AddrinfoW e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result) if e != nil { - return nil, &DNSError{Err: winError("getaddrinfow", e).Error(), Name: name} + err := winError("getaddrinfow", e) + dnsError := &DNSError{Err: err.Error(), Name: name} + if err == errNoSuchHost { + dnsError.IsNotFound = true + } + return nil, dnsError } defer syscall.FreeAddrInfoW(result) addrs := make([]IPAddr, 0, 5) @@ -176,7 +186,12 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int if port, err := lookupPortMap(network, service); err == nil { return port, nil } - return 0, &DNSError{Err: winError("getaddrinfow", e).Error(), Name: network + "/" + service} + err := winError("getaddrinfow", e) + dnsError := &DNSError{Err: err.Error(), Name: network + "/" + service} + if err == errNoSuchHost { + dnsError.IsNotFound = true + } + return 0, dnsError } defer syscall.FreeAddrInfoW(result) if result == nil { diff --git a/src/net/net.go b/src/net/net.go index b44ecb6711..0e078620a5 100644 --- a/src/net/net.go +++ b/src/net/net.go @@ -579,6 +579,7 @@ type DNSError struct { Server string // server used IsTimeout bool // if true, timed out; not all timeouts set this IsTemporary bool // if true, error is temporary; not all errors set this + IsNotFound bool // if true, host could not be found } func (e *DNSError) Error() string { |