From: Otto Moerbeek Date: Wed, 13 Sep 2023 14:13:30 +0000 (+0200) Subject: If we receive an answer from a nameserver, unthrottle it. X-Git-Tag: rec-5.0.0-alpha2~44^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=314600f6b33658b3e4dc39ab222cebb232684082;p=thirdparty%2Fpdns.git If we receive an answer from a nameserver, unthrottle it. Also throw a dice to use a fully throttled NS anyway once in a while. --- diff --git a/pdns/recursordist/syncres.cc b/pdns/recursordist/syncres.cc index 2a5b46ae4e..7b7f2b96fc 100644 --- a/pdns/recursordist/syncres.cc +++ b/pdns/recursordist/syncres.cc @@ -309,6 +309,10 @@ public: d_cont.clear(); } + void clear(const Thing& thing) + { + d_cont.erase(thing); + } void prune(time_t now) { auto& ind = d_cont.template get(); @@ -1235,9 +1239,20 @@ bool SyncRes::isThrottled(time_t now, const ComboAddress& server, const DNSName& bool SyncRes::isThrottled(time_t now, const ComboAddress& server) { + // Give fully throttled servers a chance to be used, to avoid having one bad domain spoil the NS record for others + // If the NS answers, it will be unThrottled + if ((dns_random_uint32() & 0x7f) == 0) { + return false; + } return s_throttle.lock()->shouldThrottle(now, std::tuple(server, g_rootdnsname, 0)); } +void SyncRes::unThrottle(const ComboAddress& server, const DNSName& name, QType qtype) +{ + s_throttle.lock()->clear(std::tuple(server, g_rootdnsname, 0)); + s_throttle.lock()->clear(std::tuple(server, name, qtype)); +} + void SyncRes::doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries) { s_throttle.lock()->throttle(now, std::tuple(server, g_rootdnsname, 0), duration, tries); @@ -5263,13 +5278,13 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, LOG(prefix << qname << ": Error resolving from " << remoteIP.toString() << (doTCP ? " over TCP" : "") << ", possible error: " << stringerror() << endl); } + // don't account for resource limits, they are our own fault + // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames if (resolveret != LWResult::Result::OSLimitError && !chained && !dontThrottle) { - // don't account for resource limits, they are our own fault - // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames s_nsSpeeds.lock()->find_or_enter(nsName.empty() ? DNSName(remoteIP.toStringWithPort()) : nsName, d_now).submit(remoteIP, 1000000, d_now); // 1 sec - // code below makes sure we don't filter COM or the root - if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && s_fails.lock()->incr(remoteIP, d_now) >= s_serverdownmaxfails) { + // make sure we don't throttle the root + if (s_serverdownmaxfails > 0 && auth != g_rootdnsname && s_fails.lock()->incr(remoteIP, d_now) >= s_serverdownmaxfails) { LOG(prefix << qname << ": Max fails reached resolving on " << remoteIP.toString() << ". Going full throttle for " << s_serverdownthrottletime << " seconds" << endl); // mark server as down doThrottle(d_now.tv_sec, remoteIP, s_serverdownthrottletime, 10000); @@ -5327,6 +5342,8 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, if (s_serverdownmaxfails > 0) { s_fails.lock()->clear(remoteIP); } + // Clear all throttles for this IP, both general and specific throttles for qname-qtype + unThrottle(remoteIP, qname, qtype); if (lwr.d_tcbit) { truncated = true; diff --git a/pdns/recursordist/syncres.hh b/pdns/recursordist/syncres.hh index 9d40aa52fb..5688466401 100644 --- a/pdns/recursordist/syncres.hh +++ b/pdns/recursordist/syncres.hh @@ -264,6 +264,7 @@ public: static bool isThrottled(time_t now, const ComboAddress& server); static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries); static void doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries); + static void unThrottle(const ComboAddress& server, const DNSName& qname, QType qtype); static uint64_t getFailedServersSize(); static void clearFailedServers();