]> Cypherpunks repositories - gostls13.git/commitdiff
net: fix inconsistent error values on Lookup
authorMikio Hara <mikioh.mikioh@gmail.com>
Sun, 19 Apr 2015 11:54:01 +0000 (20:54 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Tue, 21 Apr 2015 05:16:07 +0000 (05:16 +0000)
This change fixes inconsistent error values on
Lookup{Addr,CNAME,Host,IP.MX,NS,Port,SRV,TXT}.

Updates #4856.

Change-Id: I059bc8ffb96ee74dff8a8c4e8e6ae3e4a462a7ef
Reviewed-on: https://go-review.googlesource.com/9108
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/cgo_unix.go
src/net/dnsclient.go
src/net/dnsclient_unix.go
src/net/lookup.go
src/net/lookup_unix.go
src/net/lookup_windows.go
src/net/net.go
src/net/port.go
src/net/port_unix.go

index 38c3d70d55699a94a7beff496d7ce66d1ff018c0..7f7b6000034c273a1bfba113a35ddc1334f73fa5 100644 (file)
@@ -54,7 +54,7 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
                hints.ai_socktype = C.SOCK_DGRAM
                hints.ai_protocol = C.IPPROTO_UDP
        default:
-               return 0, UnknownNetworkError(network), true
+               return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true
        }
        if len(network) >= 4 {
                switch network[3] {
@@ -78,7 +78,7 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
                default:
                        err = addrinfoErrno(gerrno)
                }
-               return 0, err, true
+               return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true
        }
        defer C.freeaddrinfo(res)
 
@@ -94,7 +94,7 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
                        return int(p[0])<<8 | int(p[1]), nil, true
                }
        }
-       return 0, &AddrError{"unknown port", network + "/" + service}, true
+       return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true
 }
 
 func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
@@ -110,7 +110,6 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
        var res *C.struct_addrinfo
        gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
        if gerrno != 0 {
-               var str string
                switch gerrno {
                case C.EAI_SYSTEM:
                        if err == nil {
@@ -123,13 +122,12 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
                                // comes up again. golang.org/issue/6232.
                                err = syscall.EMFILE
                        }
-                       str = err.Error()
                case C.EAI_NONAME:
-                       str = noSuchHost
+                       err = errNoSuchHost
                default:
-                       str = addrinfoErrno(gerrno).Error()
+                       err = addrinfoErrno(gerrno)
                }
-               return nil, "", &DNSError{Err: str, Name: name}, true
+               return nil, "", &DNSError{Err: err.Error(), Name: name}, true
        }
        defer C.freeaddrinfo(res)
 
index 121cd9d21dc5f52b14612f117b26d39663df119b..e5d0ae039b8663fff6565d1a7667e5ad12f17706 100644 (file)
@@ -9,38 +9,6 @@ import (
        "sort"
 )
 
-// DNSError represents a DNS lookup error.
-type DNSError struct {
-       Err       string // description of the error
-       Name      string // name looked for
-       Server    string // server used
-       IsTimeout bool   // if true, timed out; not all timeouts set this
-}
-
-func (e *DNSError) Error() string {
-       if e == nil {
-               return "<nil>"
-       }
-       s := "lookup " + e.Name
-       if e.Server != "" {
-               s += " on " + e.Server
-       }
-       s += ": " + e.Err
-       return s
-}
-
-// Timeout reports whether the DNS lookup is known to have timed out.
-// This is not always known; a DNS lookup may fail due to a timeout
-// and return a DNSError for which Timeout returns false.
-func (e *DNSError) Timeout() bool { return e.IsTimeout }
-
-// Temporary reports whether the DNS error is known to be temporary.
-// This is not always known; a DNS lookup may fail due to a temporary
-// error and return a DNSError for which Temporary returns false.
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
-
-const noSuchHost = "no such host"
-
 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
 // address addr suitable for rDNS (PTR) record lookup or an error if it fails
 // to parse the IP address.
@@ -50,8 +18,7 @@ func reverseaddr(addr string) (arpa string, err error) {
                return "", &DNSError{Err: "unrecognized address", Name: addr}
        }
        if ip.To4() != nil {
-               return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." +
-                       uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
+               return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
        }
        // Must be IPv6
        buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
@@ -74,7 +41,7 @@ func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs
        addrs = make([]dnsRR, 0, len(dns.answer))
 
        if dns.rcode == dnsRcodeNameError && dns.recursion_available {
-               return "", nil, &DNSError{Err: noSuchHost, Name: name}
+               return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name}
        }
        if dns.rcode != dnsRcodeSuccess {
                // None of the error codes make sense
@@ -113,7 +80,7 @@ Cname:
                        }
                }
                if len(addrs) == 0 {
-                       return "", nil, &DNSError{Err: noSuchHost, Name: name, Server: server}
+                       return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
                }
                return name, addrs, nil
        }
@@ -201,13 +168,10 @@ type SRV struct {
 type byPriorityWeight []*SRV
 
 func (s byPriorityWeight) Len() int { return len(s) }
-
-func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
 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)
+       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.
@@ -255,11 +219,9 @@ type MX struct {
 // byPref implements sort.Interface to sort MX records by preference
 type byPref []*MX
 
-func (s byPref) Len() int { return len(s) }
-
+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] }
+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() {
index 30c7ada5baa334eebec9d2271be69960d5c6ee82..3dd22f2804c2de4835413d06b5a7fc9e467f4351 100644 (file)
@@ -185,7 +185,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
                                continue
                        }
                        cname, addrs, err := answer(name, server, msg, qtype)
-                       if err == nil || err.(*DNSError).Err == noSuchHost {
+                       if err == nil || err.(*DNSError).Err == errNoSuchHost.Error() {
                                return cname, addrs, err
                        }
                        lastErr = err
@@ -269,7 +269,7 @@ func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan cha
        }()
 }
 
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
+func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
        if !isDomainName(name) {
                return name, nil, &DNSError{Err: "invalid domain name", Name: name}
        }
@@ -296,7 +296,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
                        rname += "."
                }
                // Can try as ordinary name.
-               cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+               cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
                if rooted || err == nil {
                        return
                }
@@ -308,7 +308,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
                if rname[len(rname)-1] != '.' {
                        rname += "."
                }
-               cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+               cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
                if err == nil {
                        return
                }
@@ -317,7 +317,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
        // Last ditch effort: try unsuffixed only if we haven't already,
        // that is, name is not rooted and has less than ndots dots.
        if count(name, '.') < cfg.dnsConfig.ndots {
-               cname, addrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
+               cname, rrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
                if err == nil {
                        return
                }
index 5adcd8bb68916b6d77de2553c67e8de194ed2d45..e2becc5a90cfaefcd468234900f3dd0924e7bc72 100644 (file)
@@ -132,22 +132,22 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
 }
 
 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mx []*MX, err error) {
+func LookupMX(name string) (mxs []*MX, err error) {
        return lookupMX(name)
 }
 
 // LookupNS returns the DNS NS records for the given domain name.
-func LookupNS(name string) (ns []*NS, err error) {
+func LookupNS(name string) (nss []*NS, err error) {
        return lookupNS(name)
 }
 
 // LookupTXT returns the DNS TXT records for the given domain name.
-func LookupTXT(name string) (txt []string, err error) {
+func LookupTXT(name string) (txts []string, err error) {
        return lookupTXT(name)
 }
 
 // LookupAddr performs a reverse lookup for the given address, returning a list
 // of names mapping to that address.
-func LookupAddr(addr string) (name []string, err error) {
+func LookupAddr(addr string) (names []string, err error) {
        return lookupAddr(addr)
 }
index 473adf87f6dedd3e02d7dc0be6fbde10dfd7cb2b..f9c23938511ba4b3f24b5905731705a7132e8601 100644 (file)
@@ -6,10 +6,7 @@
 
 package net
 
-import (
-       "errors"
-       "sync"
-)
+import "sync"
 
 var onceReadProtocols sync.Once
 
@@ -43,126 +40,121 @@ func readProtocols() {
 
 // lookupProtocol looks up IP protocol name in /etc/protocols and
 // returns correspondent protocol number.
-func lookupProtocol(name string) (proto int, err error) {
+func lookupProtocol(name string) (int, error) {
        onceReadProtocols.Do(readProtocols)
        proto, found := protocols[name]
        if !found {
-               return 0, errors.New("unknown IP protocol specified: " + name)
+               return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
        }
-       return
+       return proto, nil
 }
 
-func lookupHost(host string) (addrs []string, err error) {
+func lookupHost(host string) ([]string, error) {
        addrs, err, ok := cgoLookupHost(host)
        if !ok {
                addrs, err = goLookupHost(host)
        }
-       return
+       return addrs, err
 }
 
-func lookupIP(host string) (addrs []IPAddr, err error) {
+func lookupIP(host string) ([]IPAddr, error) {
        addrs, err, ok := cgoLookupIP(host)
        if !ok {
                addrs, err = goLookupIP(host)
        }
-       return
+       return addrs, err
 }
 
-func lookupPort(network, service string) (port int, err error) {
+func lookupPort(network, service string) (int, error) {
        port, err, ok := cgoLookupPort(network, service)
        if !ok {
                port, err = goLookupPort(network, service)
        }
-       return
+       return port, err
 }
 
-func lookupCNAME(name string) (cname string, err error) {
+func lookupCNAME(name string) (string, error) {
        cname, err, ok := cgoLookupCNAME(name)
        if !ok {
                cname, err = goLookupCNAME(name)
        }
-       return
+       return cname, err
 }
 
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func lookupSRV(service, proto, name string) (string, []*SRV, error) {
        var target string
        if service == "" && proto == "" {
                target = name
        } else {
                target = "_" + service + "._" + proto + "." + name
        }
-       var records []dnsRR
-       cname, records, err = lookup(target, dnsTypeSRV)
+       cname, rrs, err := lookup(target, dnsTypeSRV)
        if err != nil {
-               return
+               return "", nil, err
        }
-       addrs = make([]*SRV, len(records))
-       for i, rr := range records {
-               r := rr.(*dnsRR_SRV)
-               addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+       srvs := make([]*SRV, len(rrs))
+       for i, rr := range rrs {
+               rr := rr.(*dnsRR_SRV)
+               srvs[i] = &SRV{Target: rr.Target, Port: rr.Port, Priority: rr.Priority, Weight: rr.Weight}
        }
-       byPriorityWeight(addrs).sort()
-       return
+       byPriorityWeight(srvs).sort()
+       return cname, srvs, nil
 }
 
-func lookupMX(name string) (mx []*MX, err error) {
-       _, records, err := lookup(name, dnsTypeMX)
+func lookupMX(name string) ([]*MX, error) {
+       _, rrs, err := lookup(name, dnsTypeMX)
        if err != nil {
-               return
+               return nil, err
        }
-       mx = make([]*MX, len(records))
-       for i, rr := range records {
-               r := rr.(*dnsRR_MX)
-               mx[i] = &MX{r.Mx, r.Pref}
+       mxs := make([]*MX, len(rrs))
+       for i, rr := range rrs {
+               rr := rr.(*dnsRR_MX)
+               mxs[i] = &MX{Host: rr.Mx, Pref: rr.Pref}
        }
-       byPref(mx).sort()
-       return
+       byPref(mxs).sort()
+       return mxs, nil
 }
 
-func lookupNS(name string) (ns []*NS, err error) {
-       _, records, err := lookup(name, dnsTypeNS)
+func lookupNS(name string) ([]*NS, error) {
+       _, rrs, err := lookup(name, dnsTypeNS)
        if err != nil {
-               return
+               return nil, err
        }
-       ns = make([]*NS, len(records))
-       for i, r := range records {
-               r := r.(*dnsRR_NS)
-               ns[i] = &NS{r.Ns}
+       nss := make([]*NS, len(rrs))
+       for i, rr := range rrs {
+               nss[i] = &NS{Host: rr.(*dnsRR_NS).Ns}
        }
-       return
+       return nss, nil
 }
 
-func lookupTXT(name string) (txt []string, err error) {
-       _, records, err := lookup(name, dnsTypeTXT)
+func lookupTXT(name string) ([]string, error) {
+       _, rrs, err := lookup(name, dnsTypeTXT)
        if err != nil {
-               return
+               return nil, err
        }
-       txt = make([]string, len(records))
-       for i, r := range records {
-               txt[i] = r.(*dnsRR_TXT).Txt
+       txts := make([]string, len(rrs))
+       for i, rr := range rrs {
+               txts[i] = rr.(*dnsRR_TXT).Txt
        }
-       return
+       return txts, nil
 }
 
-func lookupAddr(addr string) (name []string, err error) {
-       name = lookupStaticAddr(addr)
-       if len(name) > 0 {
-               return
+func lookupAddr(addr string) ([]string, error) {
+       names := lookupStaticAddr(addr)
+       if len(names) > 0 {
+               return names, nil
        }
-       var arpa string
-       arpa, err = reverseaddr(addr)
+       arpa, err := reverseaddr(addr)
        if err != nil {
-               return
+               return nil, err
        }
-       var records []dnsRR
-       _, records, err = lookup(arpa, dnsTypePTR)
+       _, rrs, err := lookup(arpa, dnsTypePTR)
        if err != nil {
-               return
+               return nil, err
        }
-       name = make([]string, len(records))
-       for i := range records {
-               r := records[i].(*dnsRR_PTR)
-               name[i] = r.Ptr
+       ptrs := make([]string, len(rrs))
+       for i, rr := range rrs {
+               ptrs[i] = rr.(*dnsRR_PTR).Ptr
        }
-       return
+       return ptrs, nil
 }
index 6a8d9181ba053c1eead21764919bb118c4838d91..7ad393ab690b2e8854c960d1d4cb2ca5a11b91f4 100644 (file)
@@ -5,7 +5,6 @@
 package net
 
 import (
-       "os"
        "runtime"
        "syscall"
        "unsafe"
@@ -19,13 +18,13 @@ var (
 func getprotobyname(name string) (proto int, err error) {
        p, err := syscall.GetProtoByName(name)
        if err != nil {
-               return 0, os.NewSyscallError("GetProtoByName", err)
+               return 0, err
        }
        return int(p.Proto), nil
 }
 
 // lookupProtocol looks up IP protocol name and returns correspondent protocol number.
-func lookupProtocol(name string) (proto int, err error) {
+func lookupProtocol(name string) (int, error) {
        // GetProtoByName return value is stored in thread local storage.
        // Start new os thread before the call to prevent races.
        type result struct {
@@ -46,27 +45,28 @@ func lookupProtocol(name string) (proto int, err error) {
                if proto, ok := protocols[name]; ok {
                        return proto, nil
                }
+               r.err = &DNSError{Err: r.err.Error(), Name: name}
        }
        return r.proto, r.err
 }
 
-func lookupHost(name string) (addrs []string, err error) {
+func lookupHost(name string) ([]string, error) {
        ips, err := LookupIP(name)
        if err != nil {
-               return
+               return nil, err
        }
-       addrs = make([]string, 0, len(ips))
+       addrs := make([]string, 0, len(ips))
        for _, ip := range ips {
                addrs = append(addrs, ip.String())
        }
-       return
+       return addrs, nil
 }
 
 func gethostbyname(name string) (addrs []IPAddr, err error) {
        // caller already acquired thread
        h, err := syscall.GetHostByName(name)
        if err != nil {
-               return nil, os.NewSyscallError("GetHostByName", err)
+               return nil, err
        }
        switch h.AddrType {
        case syscall.AF_INET:
@@ -77,12 +77,12 @@ func gethostbyname(name string) (addrs []IPAddr, err error) {
                }
                addrs = addrs[0:i]
        default: // TODO(vcc): Implement non IPv4 address lookups.
-               return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
+               return nil, syscall.EWINDOWS
        }
        return addrs, nil
 }
 
-func oldLookupIP(name string) (addrs []IPAddr, err error) {
+func oldLookupIP(name string) ([]IPAddr, error) {
        // GetHostByName return value is stored in thread local storage.
        // Start new os thread before the call to prevent races.
        type result struct {
@@ -99,10 +99,13 @@ func oldLookupIP(name string) (addrs []IPAddr, err error) {
                ch <- result{addrs: addrs, err: err}
        }()
        r := <-ch
-       return addrs, r.err
+       if r.err != nil {
+               r.err = &DNSError{Err: r.err.Error(), Name: name}
+       }
+       return r.addrs, r.err
 }
 
-func newLookupIP(name string) (addrs []IPAddr, err error) {
+func newLookupIP(name string) ([]IPAddr, error) {
        acquireThread()
        defer releaseThread()
        hints := syscall.AddrinfoW{
@@ -113,10 +116,10 @@ func newLookupIP(name string) (addrs []IPAddr, err error) {
        var result *syscall.AddrinfoW
        e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
        if e != nil {
-               return nil, os.NewSyscallError("GetAddrInfoW", e)
+               return nil, &DNSError{Err: e.Error(), Name: name}
        }
        defer syscall.FreeAddrInfoW(result)
-       addrs = make([]IPAddr, 0, 5)
+       addrs := make([]IPAddr, 0, 5)
        for ; result != nil; result = result.Next {
                addr := unsafe.Pointer(result.Addr)
                switch result.Family {
@@ -128,13 +131,13 @@ func newLookupIP(name string) (addrs []IPAddr, err error) {
                        zone := zoneToString(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
                        addrs = append(addrs, IPAddr{IP: IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]}, Zone: zone})
                default:
-                       return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
+                       return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}
                }
        }
        return addrs, nil
 }
 
-func getservbyname(network, service string) (port int, err error) {
+func getservbyname(network, service string) (int, error) {
        acquireThread()
        defer releaseThread()
        switch network {
@@ -145,12 +148,12 @@ func getservbyname(network, service string) (port int, err error) {
        }
        s, err := syscall.GetServByName(service, network)
        if err != nil {
-               return 0, os.NewSyscallError("GetServByName", err)
+               return 0, err
        }
        return int(syscall.Ntohs(s.Port)), nil
 }
 
-func oldLookupPort(network, service string) (port int, err error) {
+func oldLookupPort(network, service string) (int, error) {
        // GetServByName return value is stored in thread local storage.
        // Start new os thread before the call to prevent races.
        type result struct {
@@ -167,10 +170,13 @@ func oldLookupPort(network, service string) (port int, err error) {
                ch <- result{port: port, err: err}
        }()
        r := <-ch
+       if r.err != nil {
+               r.err = &DNSError{Err: r.err.Error(), Name: network + "/" + service}
+       }
        return r.port, r.err
 }
 
-func newLookupPort(network, service string) (port int, err error) {
+func newLookupPort(network, service string) (int, error) {
        acquireThread()
        defer releaseThread()
        var stype int32
@@ -188,11 +194,11 @@ func newLookupPort(network, service string) (port int, err error) {
        var result *syscall.AddrinfoW
        e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
        if e != nil {
-               return 0, os.NewSyscallError("GetAddrInfoW", e)
+               return 0, &DNSError{Err: e.Error(), Name: network + "/" + service}
        }
        defer syscall.FreeAddrInfoW(result)
        if result == nil {
-               return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
+               return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
        }
        addr := unsafe.Pointer(result.Addr)
        switch result.Family {
@@ -203,10 +209,10 @@ func newLookupPort(network, service string) (port int, err error) {
                a := (*syscall.RawSockaddrInet6)(addr)
                return int(syscall.Ntohs(a.Port)), nil
        }
-       return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
+       return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
 }
 
-func lookupCNAME(name string) (cname string, err error) {
+func lookupCNAME(name string) (string, error) {
        acquireThread()
        defer releaseThread()
        var r *syscall.DNSRecord
@@ -220,16 +226,16 @@ func lookupCNAME(name string) (cname string, err error) {
                return name, nil
        }
        if e != nil {
-               return "", os.NewSyscallError("LookupCNAME", e)
+               return "", &DNSError{Err: e.Error(), Name: name}
        }
        defer syscall.DnsRecordListFree(r, 1)
 
        resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
-       cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
-       return
+       cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
+       return cname, nil
 }
 
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func lookupSRV(service, proto, name string) (string, []*SRV, error) {
        acquireThread()
        defer releaseThread()
        var target string
@@ -241,78 +247,78 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
        var r *syscall.DNSRecord
        e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
        if e != nil {
-               return "", nil, os.NewSyscallError("LookupSRV", e)
+               return "", nil, &DNSError{Err: e.Error(), Name: target}
        }
        defer syscall.DnsRecordListFree(r, 1)
 
-       addrs = make([]*SRV, 0, 10)
+       srvs := make([]*SRV, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) {
                v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
-               addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
+               srvs = append(srvs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
        }
-       byPriorityWeight(addrs).sort()
-       return name, addrs, nil
+       byPriorityWeight(srvs).sort()
+       return name, srvs, nil
 }
 
-func lookupMX(name string) (mx []*MX, err error) {
+func lookupMX(name string) ([]*MX, error) {
        acquireThread()
        defer releaseThread()
        var r *syscall.DNSRecord
        e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
        if e != nil {
-               return nil, os.NewSyscallError("LookupMX", e)
+               return nil, &DNSError{Err: e.Error(), Name: name}
        }
        defer syscall.DnsRecordListFree(r, 1)
 
-       mx = make([]*MX, 0, 10)
+       mxs := make([]*MX, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) {
                v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
-               mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
+               mxs = append(mxs, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
        }
-       byPref(mx).sort()
-       return mx, nil
+       byPref(mxs).sort()
+       return mxs, nil
 }
 
-func lookupNS(name string) (ns []*NS, err error) {
+func lookupNS(name string) ([]*NS, error) {
        acquireThread()
        defer releaseThread()
        var r *syscall.DNSRecord
        e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
        if e != nil {
-               return nil, os.NewSyscallError("LookupNS", e)
+               return nil, &DNSError{Err: e.Error(), Name: name}
        }
        defer syscall.DnsRecordListFree(r, 1)
 
-       ns = make([]*NS, 0, 10)
+       nss := make([]*NS, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) {
                v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-               ns = append(ns, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
+               nss = append(nss, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
        }
-       return ns, nil
+       return nss, nil
 }
 
-func lookupTXT(name string) (txt []string, err error) {
+func lookupTXT(name string) ([]string, error) {
        acquireThread()
        defer releaseThread()
        var r *syscall.DNSRecord
        e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
        if e != nil {
-               return nil, os.NewSyscallError("LookupTXT", e)
+               return nil, &DNSError{Err: e.Error(), Name: name}
        }
        defer syscall.DnsRecordListFree(r, 1)
 
-       txt = make([]string, 0, 10)
+       txts := make([]string, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) {
                d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0]))
                for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] {
                        s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:])
-                       txt = append(txt, s)
+                       txts = append(txts, s)
                }
        }
-       return
+       return txts, nil
 }
 
-func lookupAddr(addr string) (name []string, err error) {
+func lookupAddr(addr string) ([]string, error) {
        acquireThread()
        defer releaseThread()
        arpa, err := reverseaddr(addr)
@@ -322,16 +328,16 @@ func lookupAddr(addr string) (name []string, err error) {
        var r *syscall.DNSRecord
        e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
        if e != nil {
-               return nil, os.NewSyscallError("LookupAddr", e)
+               return nil, &DNSError{Err: e.Error(), Name: addr}
        }
        defer syscall.DnsRecordListFree(r, 1)
 
-       name = make([]string, 0, 10)
+       ptrs := make([]string, 0, 10)
        for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) {
                v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-               name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+               ptrs = append(ptrs, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
        }
-       return name, nil
+       return ptrs, nil
 }
 
 const dnsSectionMask = 0x0003
index f38aed6919714efc05b9bb4075350fc0e1d20517..41fc0815dee5905c4071554826b02e0cad87bf21 100644 (file)
@@ -416,13 +416,8 @@ func (e *AddrError) Error() string {
        return s
 }
 
-func (e *AddrError) Temporary() bool {
-       return false
-}
-
-func (e *AddrError) Timeout() bool {
-       return false
-}
+func (e *AddrError) Temporary() bool { return false }
+func (e *AddrError) Timeout() bool   { return false }
 
 type UnknownNetworkError string
 
@@ -441,13 +436,45 @@ type DNSConfigError struct {
        Err error
 }
 
-func (e *DNSConfigError) Error() string {
-       return "error reading DNS config: " + e.Err.Error()
-}
-
+func (e *DNSConfigError) Error() string   { return "error reading DNS config: " + e.Err.Error() }
 func (e *DNSConfigError) Timeout() bool   { return false }
 func (e *DNSConfigError) Temporary() bool { return false }
 
+// Various errors contained in DNSError.
+var (
+       errNoSuchHost = errors.New("no such host")
+)
+
+// DNSError represents a DNS lookup error.
+type DNSError struct {
+       Err       string // description of the error
+       Name      string // name looked for
+       Server    string // server used
+       IsTimeout bool   // if true, timed out; not all timeouts set this
+}
+
+func (e *DNSError) Error() string {
+       if e == nil {
+               return "<nil>"
+       }
+       s := "lookup " + e.Name
+       if e.Server != "" {
+               s += " on " + e.Server
+       }
+       s += ": " + e.Err
+       return s
+}
+
+// Timeout reports whether the DNS lookup is known to have timed out.
+// This is not always known; a DNS lookup may fail due to a timeout
+// and return a DNSError for which Timeout returns false.
+func (e *DNSError) Timeout() bool { return e.IsTimeout }
+
+// Temporary reports whether the DNS error is known to be temporary.
+// This is not always known; a DNS lookup may fail due to a temporary
+// error and return a DNSError for which Temporary returns false.
+func (e *DNSError) Temporary() bool { return e.IsTimeout }
+
 type writerOnly struct {
        io.Writer
 }
index c24f4ed5b17733da84c7a34e61f909b6ae5309d6..a2a538789e136f793c0f824b6e5184189066efd9 100644 (file)
@@ -18,7 +18,7 @@ func parsePort(net, port string) (int, error) {
                }
        }
        if p < 0 || p > 0xFFFF {
-               return 0, &AddrError{"invalid port", port}
+               return 0, &AddrError{Err: "invalid port", Addr: port}
        }
        return p, nil
 }
index 348c771c3511ad0776c5690e4a90e1e1c95d5fec..badf8abc79baaaf11b66037eadac06ff50d28259 100644 (file)
@@ -69,5 +69,5 @@ func goLookupPort(network, service string) (port int, err error) {
                        return
                }
        }
-       return 0, &AddrError{"unknown port", network + "/" + service}
+       return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
 }