]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Initial code to Probe nameservers for DoT.
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 9 Mar 2022 13:37:16 +0000 (14:37 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 12 Apr 2022 11:39:42 +0000 (13:39 +0200)
The ratelmiting code sure need so extra attention.
Missing: pruning, stats, tests, docs.

pdns/recursordist/docs/manpages/rec_control.1.rst
pdns/recursordist/rec-main.cc
pdns/recursordist/taskqueue.hh
pdns/syncres.cc
pdns/syncres.hh

index 38f826a63e2fcba3cfeefb530f57c99c440e313a..0b2c22215041f761311ba2c2d082d7b28be93b8d 100644 (file)
@@ -92,6 +92,9 @@ dump-cache *FILENAME*
     also dumped to the same file. The per-thread positive and negative cache
     dumps are separated with an appropriate comment.
 
+dump-dot-probe-map *FILENAME*
+    Dump the contents of the DoT probe map to the *FILENAME* mentioned.
+
 dump-edns *FILENAME*
     Dumps the EDNS status to the filename mentioned. This file should not exist
     already, PowerDNS will refuse to overwrite it. While dumping, the recursor
index 6fe927e4281c669f0b824e302cc65b24f0749363..5e1a377bb727069b50d4873453bd370ce4599b4c 100644 (file)
@@ -1319,6 +1319,7 @@ static int serviceMain(int argc, char* argv[])
   SyncRes::s_dot_to_port_853 = ::arg().mustDo("dot-to-port-853");
   SyncRes::s_event_trace_enabled = ::arg().asNum("event-trace-enabled");
   SyncRes::s_save_parent_ns_set = ::arg().mustDo("save-parent-ns-set");
+  SyncRes::s_max_busy_dot_probes = ::arg().asNum("max-busy-dot-probes");
 
   if (SyncRes::s_tcp_fast_open_connect) {
     checkFastOpenSysctl(true);
@@ -2521,6 +2522,7 @@ int main(int argc, char** argv)
     ::arg().set("tcp-out-max-idle-per-thread", "Maximum number of idle TCP/DoT connections per thread") = "100";
     ::arg().setSwitch("structured-logging", "Prefer structured logging") = "yes";
     ::arg().setSwitch("save-parent-ns-set", "Save parent NS set to be used if child NS set fails") = "yes";
+    ::arg().set("max-busy-dot-probes", "Maximum number of concurrent DoT probes") = "0";
 
     ::arg().setCmd("help", "Provide a helpful message");
     ::arg().setCmd("version", "Print version string");
index a57a81fe6b91f94408a7cbf94aa98086a317723b..5c55f4ae0e94331ca8b0aea1d7fb6d95fd46345b 100644 (file)
@@ -27,7 +27,7 @@
 union ComboAddress;
 namespace boost
 {
-  size_t hash_value(const ComboAddress&);
+size_t hash_value(const ComboAddress&);
 }
 
 #include <boost/multi_index_container.hpp>
@@ -41,7 +41,6 @@ namespace boost
 #include "iputils.hh"
 #include "qtype.hh"
 
-
 namespace pdns
 {
 using namespace ::boost::multi_index;
@@ -129,4 +128,3 @@ private:
 };
 
 }
-
index 935c129b3177dcb6a678a243b967781e27af38b4..9e5e65c2b67e36fc6f5e26aeeacbdc2baf3ce32f 100644 (file)
@@ -290,7 +290,7 @@ struct DoTStatus
 {
   enum Status : uint8_t { Unknown, Busy, Bad, Good };
   DNSName d_auth;
-  time_t d_last;
+  time_t d_ttd;
   Status d_status{Unknown};
   std::string toString() const
   {
@@ -300,15 +300,16 @@ struct DoTStatus
   }
 };
 
+// FIXME: Pruning NYI
 class DotMap: public map<ComboAddress, DoTStatus>
 {
 public:
   uint64_t d_numBusy{0};
 };
-LockGuarded<DotMap> s_dotMap;
+static LockGuarded<DotMap> s_dotMap;
 
-const time_t dotFailWait = 24 * 3600;
-const time_t dotSuccessWait = 3 * 24 * 3600;
+static const time_t dotFailWait = 24 * 3600;
+static const time_t dotSuccessWait = 3 * 24 * 3600;
 
 unsigned int SyncRes::s_maxnegttl;
 unsigned int SyncRes::s_maxbogusttl;
@@ -362,6 +363,7 @@ bool SyncRes::s_tcp_fast_open_connect;
 bool SyncRes::s_dot_to_port_853;
 int SyncRes::s_event_trace_enabled;
 bool SyncRes::s_save_parent_ns_set;
+unsigned int SyncRes::s_max_busy_dot_probes;
 
 #define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
 
@@ -1186,17 +1188,21 @@ uint64_t SyncRes::doDumpDoTProbeMap(int fd)
     close(newfd);
     return 0;
   }
-  fprintf(fp.get(), "; DoT probing map follows\n");
-  fprintf(fp.get(), "; ip\tstatus\ttimestamp\n");
+  fprintf(fp.get(), "; DoT probing map follows");
+  fprintf(fp.get(), "; ip\tstatus\tttd\n");
   uint64_t count=0;
 
   // We get a copy, so the I/O does not need to happen while holding the lock
-  for (const auto& i : *s_dotMap.lock()) {
+  DotMap copy;
+  {
+    copy = *s_dotMap.lock();
+  }
+  fprintf(fp.get(), "; %" PRIu64 " Busy entries\n", copy.d_numBusy);
+  for (const auto& i : copy) {
     count++;
     char tmp[26];
-    fprintf(fp.get(), "%s\t%s\t%s\t%s", i.first.toString().c_str(), i.second.d_auth.toString().c_str(), i.second.toString().c_str(), ctime_r(&i.second.d_last, tmp));
+    fprintf(fp.get(), "%s\t%s\t%s\t%s", i.first.toString().c_str(), i.second.d_auth.toString().c_str(), i.second.toString().c_str(), ctime_r(&i.second.d_ttd, tmp));
   }
-
   return count;
 }
 
@@ -4703,27 +4709,26 @@ static void submitTryDotTask(ComboAddress address, const DNSName& auth, time_t n
   }
   address.setPort(853);
   auto lock = s_dotMap.lock();
-  auto it = lock->emplace(address, DoTStatus{auth, now}).first;
-  if (it->second.d_status == DoTStatus::Busy) {
-    cerr << "Already probing DoT for " << address.toString() << endl << endl;
+  if (lock->d_numBusy >= SyncRes::s_max_busy_dot_probes) {
     return;
   }
-  if (it->second.d_status == DoTStatus::Bad && it->second.d_last + dotFailWait > now) {
-    cerr << "Bad DoT for " << address.toString()<< endl << endl;
+  auto it = lock->emplace(address, DoTStatus{auth, now + dotFailWait}).first;
+  if (it->second.d_status == DoTStatus::Busy) {
     return;
   }
-  if (it->second.d_status == DoTStatus::Good && it->second.d_last + dotSuccessWait > now) {
-    cerr << "Good DoT for " << address.toString() << endl << endl;
-    return;
+  if (it->second.d_ttd > now) {
+    if (it->second.d_status == DoTStatus::Bad) {
+      return;
+    }
+    if (it->second.d_status == DoTStatus::Good) {
+      return;
+    }
   }
-  it->second.d_last = now;
+  it->second.d_ttd = now + dotFailWait;
   bool pushed = pushTryDoTTask(auth, QType::SOA, address, std::numeric_limits<time_t>::max());
   if (pushed) {
-    cerr << "Probing DoT for " << address.toString() << endl << endl;
     it->second.d_status = DoTStatus::Busy;
     ++lock->d_numBusy;
-  } else {
-    cerr << "NOT Probing DoT for " << address.toString() << endl << endl;
   }
 }
 
@@ -4731,16 +4736,12 @@ static bool shouldDoDoT(ComboAddress address, time_t now)
 {
   address.setPort(853);
   auto lock = s_dotMap.lock();
-  if (lock->d_numBusy > 1) {
-    cerr << "Busy DoT for " << address.toString() << endl << endl;
-    return false;
-  }
   auto it = lock->find(address);
   if (it == lock->end()) {
+    // Pruned...
     return false;
   }
-  if (it->second.d_status == DoTStatus::Good && it->second.d_last + dotSuccessWait > now) {
-    cerr << "Doing DoT for " << address.toString() << endl << endl;
+  if (it->second.d_status == DoTStatus::Good && it->second.d_ttd > now) {
     return true;
   }
   return false;
@@ -4757,12 +4758,14 @@ bool SyncRes::tryDoT(const DNSName& qname, const QType qtype, const DNSName& aut
   ok = ok && lwr.d_rcode == RCode::NoError && lwr.d_records.size() > 0;
 
   auto lock = s_dotMap.lock();
-  --lock->d_numBusy;
   auto it = lock->find(address);
+  // If an entry was removed by pruning, we do not adjust d_numBusy; it's the job of the pruning code to do that
   if (it != lock->end()) {
-    cerr << "DoT for " << address.toString() << ": " << ok << endl << endl;
     it->second.d_status = ok ? DoTStatus::Good : DoTStatus::Bad;
+    it->second.d_ttd = now + (ok ? dotSuccessWait : dotFailWait);
+    --lock->d_numBusy;
   }
+
   return ok;
 }
 
index 98ca15025623e7f3aab72252400522ba850fe03e..2823f983c3f3bbd3ed94c775bb9d2c1648e23562 100644 (file)
@@ -598,6 +598,7 @@ public:
   static int s_tcp_fast_open;
   static bool s_tcp_fast_open_connect;
   static bool s_dot_to_port_853;
+  static unsigned int s_max_busy_dot_probes;
 
   static const int event_trace_to_pb = 1;
   static const int event_trace_to_log = 2;