summaryrefslogtreecommitdiff
path: root/libgo/go/net/dnsclient_unix.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-09-14 17:11:35 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-09-14 17:11:35 +0000
commitbc998d034f45d1828a8663b2eed928faf22a7d01 (patch)
tree8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/net/dnsclient_unix.go
parenta41a6142df74219f596e612d3a7775f68ca6e96f (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.go118
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
}