Fix incorrect empty answer handling per RFC4074

This commit is contained in:
Daniel 2021-04-16 17:47:13 +02:00
parent 4c5461a788
commit ccefcd6b3b
2 changed files with 15 additions and 12 deletions

View file

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"github.com/miekg/dns"
"github.com/safing/portbase/log"
@ -73,10 +74,8 @@ func ZeroIP(msgs ...string) ResponderFunc {
}
switch {
case hasErr && len(reply.Answer) == 0:
case hasErr || len(reply.Answer) == 0:
reply.SetRcode(request, dns.RcodeServerFailure)
case len(reply.Answer) == 0:
reply.SetRcode(request, dns.RcodeNameError)
default:
reply.SetRcode(request, dns.RcodeSuccess)
}
@ -115,10 +114,8 @@ func Localhost(msgs ...string) ResponderFunc {
}
switch {
case hasErr && len(reply.Answer) == 0:
case hasErr || len(reply.Answer) == 0:
reply.SetRcode(request, dns.RcodeServerFailure)
case len(reply.Answer) == 0:
reply.SetRcode(request, dns.RcodeNameError)
default:
reply.SetRcode(request, dns.RcodeSuccess)
}
@ -134,6 +131,15 @@ func NxDomain(msgs ...string) ResponderFunc {
return func(ctx context.Context, request *dns.Msg) *dns.Msg {
reply := new(dns.Msg).SetRcode(request, dns.RcodeNameError)
AddMessagesToReply(ctx, reply, log.InfoLevel, msgs...)
// According to RFC4074 (https://tools.ietf.org/html/rfc4074), there are
// nameservers that incorrectly respond with NXDomain instead of an empty
// SUCCESS response when there are other RRs for the queried domain name.
// This can lead to the software thinking that no RRs exist for that
// domain. In order to mitigate this a bit, we slightly delay NXDomain
// responses.
time.Sleep(500 * time.Millisecond)
return reply
}
}

View file

@ -82,12 +82,6 @@ func (rrCache *RRCache) Clean(minExpires uint32) {
lowestTTL = maxTTL
}
// Adjust return code if there are no answers
if rrCache.RCode == dns.RcodeSuccess &&
len(rrCache.Answer) == 0 {
rrCache.RCode = dns.RcodeNameError
}
// shorten caching
switch {
case rrCache.RCode != dns.RcodeSuccess:
@ -96,6 +90,9 @@ func (rrCache *RRCache) Clean(minExpires uint32) {
case netenv.IsConnectivityDomain(rrCache.Domain):
// Responses from these domains might change very quickly depending on the environment.
lowestTTL = 3
case len(rrCache.Answer) == 0:
// Empty answer section: Domain exists, but not the queried RR.
lowestTTL = 60
case !netenv.Online():
// Not being fully online could mean that we get funny responses.
lowestTTL = 60