aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShubham Sharma <shubham.sha12@gmail.com>2019-03-21 21:10:12 +0530
committerBrad Fitzpatrick <bradfitz@golang.org>2019-04-23 14:11:33 +0000
commitfac3b5d05ecf31a2491949cc905312a34e272ae8 (patch)
tree4a82ef10460246d855e9ece69b40addfbfe561b2
parent7e08c7f43da876bc451b774808e323215a193abd (diff)
downloadgo-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.go5
-rw-r--r--src/net/dnsclient_unix.go15
-rw-r--r--src/net/dnsclient_unix_test.go38
-rw-r--r--src/net/lookup.go4
-rw-r--r--src/net/lookup_test.go3
-rw-r--r--src/net/lookup_windows.go21
-rw-r--r--src/net/net.go1
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 {