diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go index 38c3d70d55699..7f7b6000034c2 100644 --- a/src/net/cgo_unix.go +++ b/src/net/cgo_unix.go @@ -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) diff --git a/src/net/dnsclient.go b/src/net/dnsclient.go index 121cd9d21dc5f..e5d0ae039b866 100644 --- a/src/net/dnsclient.go +++ b/src/net/dnsclient.go @@ -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 "" - } - 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() { diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index 30c7ada5baa33..3dd22f2804c2d 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -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 } diff --git a/src/net/lookup.go b/src/net/lookup.go index 5adcd8bb68916..e2becc5a90cfa 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -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) } diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go index 473adf87f6ded..f9c23938511ba 100644 --- a/src/net/lookup_unix.go +++ b/src/net/lookup_unix.go @@ -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 } diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go index 6a8d9181ba053..7ad393ab690b2 100644 --- a/src/net/lookup_windows.go +++ b/src/net/lookup_windows.go @@ -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 diff --git a/src/net/net.go b/src/net/net.go index f38aed6919714..41fc0815dee59 100644 --- a/src/net/net.go +++ b/src/net/net.go @@ -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 "" + } + 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 } diff --git a/src/net/port.go b/src/net/port.go index c24f4ed5b1773..a2a538789e136 100644 --- a/src/net/port.go +++ b/src/net/port.go @@ -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 } diff --git a/src/net/port_unix.go b/src/net/port_unix.go index 348c771c3511a..badf8abc79baa 100644 --- a/src/net/port_unix.go +++ b/src/net/port_unix.go @@ -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} }