]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
If we receive an answer from a nameserver, unthrottle it.
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 13 Sep 2023 14:13:30 +0000 (16:13 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Mon, 25 Sep 2023 08:39:15 +0000 (10:39 +0200)
Also throw a dice to use a fully throttled NS anyway once in a while.

pdns/recursordist/syncres.cc
pdns/recursordist/syncres.hh

index 2a5b46ae4eb395a13b28b2774a55518936b4ced6..7b7f2b96fccb9021caa372dc5884d20979f341d4 100644 (file)
@@ -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<time_t>();
@@ -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;
index 9d40aa52fb75257bdaec20ef5ee3d9e5350fa766..568846640186566534e02cc12e39adea77e4d839 100644 (file)
@@ -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();