diff options
Diffstat (limited to 'libgo/go/net/dnsclient_unix.go')
-rw-r--r-- | libgo/go/net/dnsclient_unix.go | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index c03c1b1..17188f0 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -20,14 +20,22 @@ import ( "io" "math/rand" "os" - "strconv" "sync" "time" ) +// A dnsDialer provides dialing suitable for DNS queries. +type dnsDialer interface { + dialDNS(string, string) (dnsConn, error) +} + +var testHookDNSDialer = func(d time.Duration) dnsDialer { return &Dialer{Timeout: d} } + // A dnsConn represents a DNS transport endpoint. type dnsConn interface { - Conn + io.Closer + + SetDeadline(time.Time) error // readDNSResponse reads a DNS response message from the DNS // transport endpoint and returns the received DNS response @@ -122,7 +130,7 @@ func (d *Dialer) dialDNS(network, server string) (dnsConn, error) { // exchange sends a query on the connection and hopes for a response. func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) { - d := Dialer{Timeout: timeout} + d := testHookDNSDialer(timeout) out := dnsMsg{ dnsMsgHdr: dnsMsgHdr{ recursion_desired: true, @@ -165,9 +173,6 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err if len(cfg.servers) == 0 { return "", nil, &DNSError{Err: "no DNS servers", Name: name} } - if len(name) >= 256 { - return "", nil, &DNSError{Err: "DNS name too long", Name: name} - } timeout := time.Duration(cfg.timeout) * time.Second var lastErr error for i := 0; i < cfg.attempts; i++ { @@ -186,7 +191,11 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err continue } cname, rrs, err := answer(name, server, msg, qtype) - if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError && msg.recursion_available { + // If answer errored for rcodes dnsRcodeSuccess or dnsRcodeNameError, + // it means the response in msg was not useful and trying another + // server probably won't help. Return now in those cases. + // TODO: indicate this in a more obvious way, such as a field on DNSError? + if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError { return cname, rrs, err } lastErr = err @@ -374,7 +383,7 @@ func (o hostLookupOrder) String() string { if s, ok := lookupOrderName[o]; ok { return s } - return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??" + return "hostLookupOrder=" + itoa(int(o)) + "??" } // goLookupHost is the native Go implementation of LookupHost. @@ -440,7 +449,8 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er conf := resolvConf.dnsConfig resolvConf.mu.RUnlock() type racer struct { - rrs []dnsRR + fqdn string + rrs []dnsRR error } lane := make(chan racer, 1) @@ -450,13 +460,16 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er for _, qtype := range qtypes { go func(qtype uint16) { _, rrs, err := tryOneName(conf, fqdn, qtype) - lane <- racer{rrs, err} + lane <- racer{fqdn, rrs, err} }(qtype) } for range qtypes { racer := <-lane if racer.error != nil { - lastErr = racer.error + // Prefer error for original name. + if lastErr == nil || racer.fqdn == name+"." { + lastErr = racer.error + } continue } addrs = append(addrs, addrRecordList(racer.rrs)...) @@ -473,12 +486,12 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er } sortByRFC6724(addrs) if len(addrs) == 0 { - if lastErr != nil { - return nil, lastErr - } if order == hostLookupDNSFiles { addrs = goLookupIPFiles(name) } + if len(addrs) == 0 && lastErr != nil { + return nil, lastErr + } } return addrs, nil } |