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.
// 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 {
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 {
}
lines, err := queryDNS(ctx, target, "srv")
if err != nil {
- return
+ return "", nil, handlePlan9DNSError(err, name)
}
for _, line := range lines {
f := getFields(line)
}
lines, err := queryDNS(ctx, name, "mx")
if err != nil {
- return
+ return nil, handlePlan9DNSError(err, name)
}
for _, line := range lines {
f := getFields(line)
}
lines, err := queryDNS(ctx, name, "ns")
if err != nil {
- return
+ return nil, handlePlan9DNSError(err, name)
}
for _, line := range lines {
f := getFields(line)
}
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 {
}
lines, err := queryDNS(ctx, arpa, "ptr")
if err != nil {
- return
+ return nil, handlePlan9DNSError(err, addr)
}
for _, line := range lines {
f := getFields(line)
}
})
}
+
+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
+ }
+ })
+ })
+ }
+}
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)
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)
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)
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)
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)
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)
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)
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)