From a72bff0da31ff3394d5bced836116c232ab4255a Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 29 May 2018 14:39:35 +0200 Subject: [PATCH 1/2] Remove if/else and redundant brackets in resolver Signed-off-by: Sebastiaan van Stijn --- libnetwork/resolver.go | 59 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/libnetwork/resolver.go b/libnetwork/resolver.go index f5f89e9a1e..a82a9150bc 100644 --- a/libnetwork/resolver.go +++ b/libnetwork/resolver.go @@ -111,7 +111,7 @@ func NewResolver(address string, proxyDNS bool, resolverKey string, backend DNSB } func (r *resolver) SetupFunc(port int) func() { - return (func() { + return func() { var err error // DNS operates primarily on UDP @@ -138,7 +138,7 @@ func (r *resolver) SetupFunc(port int) func() { return } r.err = nil - }) + } } func (r *resolver) Start() error { @@ -490,35 +490,36 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { continue } r.forwardQueryEnd() - if resp != nil { - if resp.Rcode == dns.RcodeServerFailure { - // for Server Failure response, continue to the next external DNS server - logrus.Debugf("[resolver] external DNS %s:%s responded with ServFail for %q", proto, extDNS.IPStr, name) - continue - } - answers := 0 - for _, rr := range resp.Answer { - h := rr.Header() - switch h.Rrtype { - case dns.TypeA: - answers++ - ip := rr.(*dns.A).A - logrus.Debugf("[resolver] received A record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr) - r.backend.HandleQueryResp(h.Name, ip) - case dns.TypeAAAA: - answers++ - ip := rr.(*dns.AAAA).AAAA - logrus.Debugf("[resolver] received AAAA record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr) - r.backend.HandleQueryResp(h.Name, ip) - } - } - if resp.Answer == nil || answers == 0 { - logrus.Debugf("[resolver] external DNS %s:%s did not return any %s records for %q", proto, extDNS.IPStr, queryType, name) - } - resp.Compress = true - } else { + + if resp == nil { logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, name) + break } + if resp.Rcode == dns.RcodeServerFailure { + // for Server Failure response, continue to the next external DNS server + logrus.Debugf("[resolver] external DNS %s:%s responded with ServFail for %q", proto, extDNS.IPStr, name) + continue + } + answers := 0 + for _, rr := range resp.Answer { + h := rr.Header() + switch h.Rrtype { + case dns.TypeA: + answers++ + ip := rr.(*dns.A).A + logrus.Debugf("[resolver] received A record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr) + r.backend.HandleQueryResp(h.Name, ip) + case dns.TypeAAAA: + answers++ + ip := rr.(*dns.AAAA).AAAA + logrus.Debugf("[resolver] received AAAA record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr) + r.backend.HandleQueryResp(h.Name, ip) + } + } + if resp.Answer == nil || answers == 0 { + logrus.Debugf("[resolver] external DNS %s:%s did not return any %s records for %q", proto, extDNS.IPStr, queryType, name) + } + resp.Compress = true break } if resp == nil { From 6dd3f452482c5487cea3f0643d0c70c5215ba1f0 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 29 May 2018 16:14:45 +0200 Subject: [PATCH 2/2] Handle NXDOMAIN, REFUSED and log errors - NXDOMAIN is an authoritive answer, so when receiving an NXDOMAIN, we're done. From RFC 1035: Name Error - Meaningful only for responses from an authoritative name server, this code signifies that the domain name referenced in the query does not exist. FROM RFC 8020: When an iterative caching DNS resolver receives an NXDOMAIN response, it SHOULD store it in its cache and then all names and resource record sets (RRsets) at or below that node SHOULD be considered unreachable. Subsequent queries for such names SHOULD elicit an NXDOMAIN response. - REFUSED can be a transitional status: (https://www.ietf.org/rfc/rfc1035.txt) The name server refuses to perform the specified operation for policy reasons. For example, a name server may not wish to provide the information to the particular requester, or a name server may not wish to perform a particular operation (e.g., zone) Other errors are now logged as debug-message, which can be useful for troubleshooting. Signed-off-by: Sebastiaan van Stijn --- libnetwork/resolver.go | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/libnetwork/resolver.go b/libnetwork/resolver.go index a82a9150bc..4f5f71897c 100644 --- a/libnetwork/resolver.go +++ b/libnetwork/resolver.go @@ -495,9 +495,24 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, name) break } - if resp.Rcode == dns.RcodeServerFailure { - // for Server Failure response, continue to the next external DNS server - logrus.Debugf("[resolver] external DNS %s:%s responded with ServFail for %q", proto, extDNS.IPStr, name) + switch resp.Rcode { + case dns.RcodeServerFailure, dns.RcodeRefused: + // Server returned FAILURE: continue with the next external DNS server + // Server returned REFUSED: this can be a transitional status, so continue with the next external DNS server + logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), name) + continue + case dns.RcodeNameError: + // Server returned NXDOMAIN. Stop resolution if it's an authoritative answer (see RFC 8020: https://tools.ietf.org/html/rfc8020#section-2) + logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), name) + if resp.Authoritative { + break + } + continue + case dns.RcodeSuccess: + // All is well + default: + // Server gave some error. Log the error, and continue with the next external DNS server + logrus.Debugf("[resolver] external DNS %s:%s responded with %s (code %d) for %q", proto, extDNS.IPStr, statusString(resp.Rcode), resp.Rcode, name) continue } answers := 0 @@ -532,6 +547,13 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { } } +func statusString(responseCode int) string { + if s, ok := dns.RcodeToString[responseCode]; ok { + return s + } + return "UNKNOWN" +} + func (r *resolver) forwardQueryStart() bool { r.queryLock.Lock() defer r.queryLock.Unlock()