diff options
author | Ian Lance Taylor <iant@golang.org> | 2017-09-14 17:11:35 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-09-14 17:11:35 +0000 |
commit | bc998d034f45d1828a8663b2eed928faf22a7d01 (patch) | |
tree | 8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/net/dnsclient_unix.go | |
parent | a41a6142df74219f596e612d3a7775f68ca6e96f (diff) |
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753
From-SVN: r252767
Diffstat (limited to 'libgo/go/net/dnsclient_unix.go')
-rw-r--r-- | libgo/go/net/dnsclient_unix.go | 118 |
1 files changed, 54 insertions, 64 deletions
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index 0647b9c3052..ff6a4f69dcd 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -25,13 +25,6 @@ import ( "time" ) -// A dnsDialer provides dialing suitable for DNS queries. -type dnsDialer interface { - dialDNS(ctx context.Context, network, addr string) (dnsConn, error) -} - -var testHookDNSDialer = func() dnsDialer { return &Dialer{} } - // A dnsConn represents a DNS transport endpoint. type dnsConn interface { io.Closer @@ -43,14 +36,14 @@ type dnsConn interface { dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) } -func (c *UDPConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) { - return dnsRoundTripUDP(c, query) +// dnsPacketConn implements the dnsConn interface for RFC 1035's +// "UDP usage" transport mechanism. Conn is a packet-oriented connection, +// such as a *UDPConn. +type dnsPacketConn struct { + Conn } -// dnsRoundTripUDP implements the dnsRoundTrip interface for RFC 1035's -// "UDP usage" transport mechanism. c should be a packet-oriented connection, -// such as a *UDPConn. -func dnsRoundTripUDP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) { +func (c *dnsPacketConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) { b, ok := query.Pack() if !ok { return nil, errors.New("cannot marshal DNS message") @@ -76,14 +69,14 @@ func dnsRoundTripUDP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) { } } -func (c *TCPConn) dnsRoundTrip(out *dnsMsg) (*dnsMsg, error) { - return dnsRoundTripTCP(c, out) +// dnsStreamConn implements the dnsConn interface for RFC 1035's +// "TCP usage" transport mechanism. Conn is a stream-oriented connection, +// such as a *TCPConn. +type dnsStreamConn struct { + Conn } -// dnsRoundTripTCP implements the dnsRoundTrip interface for RFC 1035's -// "TCP usage" transport mechanism. c should be a stream-oriented connection, -// such as a *TCPConn. -func dnsRoundTripTCP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) { +func (c *dnsStreamConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) { b, ok := query.Pack() if !ok { return nil, errors.New("cannot marshal DNS message") @@ -116,33 +109,8 @@ func dnsRoundTripTCP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) { return resp, nil } -func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn, error) { - switch network { - case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": - default: - return nil, UnknownNetworkError(network) - } - // Calling Dial here is scary -- we have to be sure not to - // dial a name that will require a DNS lookup, or Dial will - // call back here to translate it. The DNS config parser has - // already checked that all the cfg.servers are IP - // addresses, which Dial will use without a DNS lookup. - c, err := d.DialContext(ctx, network, server) - if err != nil { - return nil, mapErr(err) - } - switch network { - case "tcp", "tcp4", "tcp6": - return c.(*TCPConn), nil - case "udp", "udp4", "udp6": - return c.(*UDPConn), nil - } - panic("unreachable") -} - // exchange sends a query on the connection and hopes for a response. -func exchange(ctx context.Context, server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) { - d := testHookDNSDialer() +func (r *Resolver) exchange(ctx context.Context, server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) { out := dnsMsg{ dnsMsgHdr: dnsMsgHdr{ recursion_desired: true, @@ -158,7 +126,7 @@ func exchange(ctx context.Context, server, name string, qtype uint16, timeout ti ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) defer cancel() - c, err := d.dialDNS(ctx, network, server) + c, err := r.dial(ctx, network, server) if err != nil { return nil, err } @@ -181,7 +149,7 @@ func exchange(ctx context.Context, server, name string, qtype uint16, timeout ti // Do a lookup for a single name, which must be rooted // (otherwise answer will not find the answers). -func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) { +func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) { var lastErr error serverOffset := cfg.serverOffset() sLen := uint32(len(cfg.servers)) @@ -190,7 +158,7 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) for j := uint32(0); j < sLen; j++ { server := cfg.servers[(serverOffset+j)%sLen] - msg, err := exchange(ctx, server, name, qtype, cfg.timeout) + msg, err := r.exchange(ctx, server, name, qtype, cfg.timeout) if err != nil { lastErr = &DNSError{ Err: err.Error(), @@ -200,6 +168,11 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) if nerr, ok := err.(Error); ok && nerr.Timeout() { lastErr.(*DNSError).IsTimeout = true } + // Set IsTemporary for socket-level errors. Note that this flag + // may also be used to indicate a SERVFAIL response. + if _, ok := err.(*OpError); ok { + lastErr.(*DNSError).IsTemporary = true + } continue } // libresolv continues to the next server when it receives @@ -314,7 +287,7 @@ func (conf *resolverConfig) releaseSema() { <-conf.ch } -func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs []dnsRR, err error) { +func (r *Resolver) lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs []dnsRR, err error) { if !isDomainName(name) { // We used to use "invalid domain name" as the error, // but that is a detail of the specific lookup mechanism. @@ -328,10 +301,15 @@ func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs [ conf := resolvConf.dnsConfig resolvConf.mu.RUnlock() for _, fqdn := range conf.nameList(name) { - cname, rrs, err = tryOneName(ctx, conf, fqdn, qtype) + cname, rrs, err = r.tryOneName(ctx, conf, fqdn, qtype) if err == nil { break } + if nerr, ok := err.(Error); ok && nerr.Temporary() && r.StrictErrors { + // If we hit a temporary error with StrictErrors enabled, + // stop immediately instead of trying more names. + break + } } if err, ok := err.(*DNSError); ok { // Show original name passed to lookup, not suffixed one. @@ -432,11 +410,11 @@ func (o hostLookupOrder) String() string { // Normally we let cgo use the C library resolver instead of // depending on our lookup code, so that Go and C get the same // answers. -func goLookupHost(ctx context.Context, name string) (addrs []string, err error) { - return goLookupHostOrder(ctx, name, hostLookupFilesDNS) +func (r *Resolver) goLookupHost(ctx context.Context, name string) (addrs []string, err error) { + return r.goLookupHostOrder(ctx, name, hostLookupFilesDNS) } -func goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) { +func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) { if order == hostLookupFilesDNS || order == hostLookupFiles { // Use entries from /etc/hosts if they match. addrs = lookupStaticHost(name) @@ -444,7 +422,7 @@ func goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) return } } - ips, _, err := goLookupIPCNAMEOrder(ctx, name, order) + ips, _, err := r.goLookupIPCNAMEOrder(ctx, name, order) if err != nil { return } @@ -470,13 +448,13 @@ func goLookupIPFiles(name string) (addrs []IPAddr) { // goLookupIP is the native Go implementation of LookupIP. // The libc versions are in cgo_*.go. -func goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) { +func (r *Resolver) goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) { order := systemConf().hostLookupOrder(host) - addrs, _, err = goLookupIPCNAMEOrder(ctx, host, order) + addrs, _, err = r.goLookupIPCNAMEOrder(ctx, host, order) return } -func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname string, err error) { +func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, cname string, err error) { if order == hostLookupFilesDNS || order == hostLookupFiles { addrs = goLookupIPFiles(name) if len(addrs) > 0 || order == hostLookupFiles { @@ -502,15 +480,20 @@ func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrde for _, fqdn := range conf.nameList(name) { for _, qtype := range qtypes { go func(qtype uint16) { - cname, rrs, err := tryOneName(ctx, conf, fqdn, qtype) + cname, rrs, err := r.tryOneName(ctx, conf, fqdn, qtype) lane <- racer{cname, rrs, err} }(qtype) } + hitStrictError := false for range qtypes { racer := <-lane if racer.error != nil { - // Prefer error for original name. - if lastErr == nil || fqdn == name+"." { + if nerr, ok := racer.error.(Error); ok && nerr.Temporary() && r.StrictErrors { + // This error will abort the nameList loop. + hitStrictError = true + lastErr = racer.error + } else if lastErr == nil || fqdn == name+"." { + // Prefer error for original name. lastErr = racer.error } continue @@ -520,6 +503,13 @@ func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrde cname = racer.cname } } + if hitStrictError { + // If either family hit an error with StrictErrors enabled, + // discard all addresses. This ensures that network flakiness + // cannot turn a dualstack hostname IPv4/IPv6-only. + addrs = nil + break + } if len(addrs) > 0 { break } @@ -543,9 +533,9 @@ func goLookupIPCNAMEOrder(ctx context.Context, name string, order hostLookupOrde } // goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME. -func goLookupCNAME(ctx context.Context, host string) (cname string, err error) { +func (r *Resolver) goLookupCNAME(ctx context.Context, host string) (cname string, err error) { order := systemConf().hostLookupOrder(host) - _, cname, err = goLookupIPCNAMEOrder(ctx, host, order) + _, cname, err = r.goLookupIPCNAMEOrder(ctx, host, order) return } @@ -554,7 +544,7 @@ func goLookupCNAME(ctx context.Context, host string) (cname string, err error) { // only if cgoLookupPTR is the stub in cgo_stub.go). // Normally we let cgo use the C library resolver instead of depending // on our lookup code, so that Go and C get the same answers. -func goLookupPTR(ctx context.Context, addr string) ([]string, error) { +func (r *Resolver) goLookupPTR(ctx context.Context, addr string) ([]string, error) { names := lookupStaticAddr(addr) if len(names) > 0 { return names, nil @@ -563,7 +553,7 @@ func goLookupPTR(ctx context.Context, addr string) ([]string, error) { if err != nil { return nil, err } - _, rrs, err := lookup(ctx, arpa, dnsTypePTR) + _, rrs, err := r.lookup(ctx, arpa, dnsTypePTR) if err != nil { return nil, err } |