diff --git a/nameserver/nsutil/nsutil.go b/nameserver/nsutil/nsutil.go index 53372b75..e563b6c7 100644 --- a/nameserver/nsutil/nsutil.go +++ b/nameserver/nsutil/nsutil.go @@ -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 } } diff --git a/resolver/rrcache.go b/resolver/rrcache.go index 8c901131..cb6b71e5 100644 --- a/resolver/rrcache.go +++ b/resolver/rrcache.go @@ -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