浏览代码

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 <github@gone.nl>
Sebastiaan van Stijn 7 年之前
父节点
当前提交
6dd3f45248
共有 1 个文件被更改,包括 25 次插入3 次删除
  1. 25 3
      libnetwork/resolver.go

+ 25 - 3
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)
 				logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, name)
 				break
 				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
 				continue
 			}
 			}
 			answers := 0
 			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 {
 func (r *resolver) forwardQueryStart() bool {
 	r.queryLock.Lock()
 	r.queryLock.Lock()
 	defer r.queryLock.Unlock()
 	defer r.queryLock.Unlock()