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>
This commit is contained in:
Sebastiaan van Stijn 2018-05-29 16:14:45 +02:00
parent a72bff0da3
commit 6dd3f45248
1 changed files with 25 additions and 3 deletions

View File

@ -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()