]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Refactor RPZ download thread code
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 9 Jan 2024 14:33:30 +0000 (15:33 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 9 Jan 2024 14:33:30 +0000 (15:33 +0100)
pdns/recursordist/rec-lua-conf.cc
pdns/recursordist/rec-lua-conf.hh
pdns/recursordist/rpzloader.cc
pdns/recursordist/rpzloader.hh

index 071271f61a627934ea80568ac43342934aead0a9..615f8b9621ceb0d2854f2df5a4f01f08a3ae792b 100644 (file)
@@ -387,7 +387,7 @@ static void rpzPrimary(LuaConfigItems& lci, luaConfigDelayedThreads& delayedThre
          lci.d_slog->error(Logr::Error, e.reason, "Exception configuring 'rpzPrimary'", Logging::Loggable("PDNSException")));
   }
 
-  delayedThreads.rpzPrimaryThreads.emplace_back(primaries, defpol, defpolOverrideLocal, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, refresh, sr, dumpFile);
+  delayedThreads.rpzPrimaryThreads.emplace_back(RPZTrackerParams{primaries, defpol, defpolOverrideLocal, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, refresh, sr, dumpFile});
 }
 
 // A wrapper class that loads the standard Lua defintions into the context, so that we can use things like pdns.A
@@ -904,8 +904,8 @@ void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads,
     try {
       // The get calls all return a value object here. That is essential, since we want copies so that RPZIXFRTracker gets values
       // with the proper lifetime.
-      std::thread t(RPZIXFRTracker, std::get<0>(rpzPrimary), std::get<1>(rpzPrimary), std::get<2>(rpzPrimary), std::get<3>(rpzPrimary), std::get<4>(rpzPrimary), std::get<5>(rpzPrimary), std::get<6>(rpzPrimary) * 1024 * 1024, std::get<7>(rpzPrimary), std::get<8>(rpzPrimary), std::get<9>(rpzPrimary), std::get<10>(rpzPrimary), std::get<11>(rpzPrimary), generation);
-      t.detach();
+      std::thread theThread(RPZIXFRTracker, rpzPrimary, generation);
+      theThread.detach();
     }
     catch (const std::exception& e) {
       SLOG(g_log << Logger::Error << "Problem starting RPZIXFRTracker thread: " << e.what() << endl,
index 29a18b00f61a452625d2ac5070f7fb8b130dcc1b..440068ec6ea61c358d43d9c46e6c596854f7055e 100644 (file)
@@ -29,6 +29,7 @@
 #include "rec-zonetocache.hh"
 #include "logging.hh"
 #include "fstrm_logger.hh"
+#include "rpzloader.hh"
 
 struct ProtobufExportConfig
 {
@@ -125,8 +126,7 @@ extern GlobalStateHolder<LuaConfigItems> g_luaconfs;
 
 struct luaConfigDelayedThreads
 {
-  // Please make sure that the tuple below only contains value types since they are used as parameters in a thread ct
-  std::vector<std::tuple<std::vector<ComboAddress>, boost::optional<DNSFilterEngine::Policy>, bool, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t, uint32_t, std::shared_ptr<const SOARecordContent>, std::string>> rpzPrimaryThreads;
+  std::vector<RPZTrackerParams> rpzPrimaryThreads;
 };
 
 void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads, ProxyMapping&);
index 549902c0586db126ddd0dc84e5b6a2dafe5b1114..45c3576fae932e9366b9de4023c53f7e40fa3af8 100644 (file)
@@ -386,47 +386,27 @@ static bool dumpZoneToDisk(Logr::log_t logger, const DNSName& zoneName, const st
   return true;
 }
 
-void RPZIXFRTracker(const std::vector<ComboAddress>& primaries, const boost::optional<DNSFilterEngine::Policy>& defpol, bool defpolOverrideLocal, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t xfrTimeout, const uint32_t refreshFromConf, std::shared_ptr<const SOARecordContent> sr, const std::string& dumpZoneFileName, uint64_t configGeneration)
+static void preloadRPZFIle(RPZTrackerParams& params, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone>& oldZone, uint32_t& refresh, const string& polName, Logr::log_t logger)
 {
-  setThreadName("rec/rpzixfr");
-  bool isPreloaded = sr != nullptr;
-  auto logger = g_slog->withName("rpz");
-
-  /* we can _never_ modify this zone directly, we need to do a full copy then replace the existing zone */
-  std::shared_ptr<DNSFilterEngine::Zone> oldZone = g_luaconfs.getLocal()->dfe.getZone(zoneIdx);
-  if (!oldZone) {
-    SLOG(g_log << Logger::Error << "Unable to retrieve RPZ zone with index " << zoneIdx << " from the configuration, exiting" << endl,
-         logger->error(Logr::Error, "Unable to retrieve RPZ zone from configuration", "index", Logging::Loggable(zoneIdx)));
-    return;
-  }
-
-  // If oldZone failed to load its getRefresh() returns 0, protect against that
-  uint32_t refresh = std::max(refreshFromConf ? refreshFromConf : oldZone->getRefresh(), 10U);
-  DNSName zoneName = oldZone->getDomain();
-  std::string polName = !oldZone->getName().empty() ? oldZone->getName() : zoneName.toStringNoDot();
-
-  // Now that we know the name, set it in the logger
-  logger = logger->withValues("zone", Logging::Loggable(zoneName));
-
-  while (!sr) {
+  while (!params.soaRecordContent) {
     /* if we received an empty sr, the zone was not really preloaded */
 
     /* full copy, as promised */
     std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
-    for (const auto& primary : primaries) {
+    for (const auto& primary : params.primaries) {
       try {
-        sr = loadRPZFromServer(logger, primary, zoneName, newZone, defpol, defpolOverrideLocal, maxTTL, tt, maxReceivedBytes, localAddress, xfrTimeout);
-        newZone->setSerial(sr->d_st.serial);
-        newZone->setRefresh(sr->d_st.refresh);
-        refresh = std::max(refreshFromConf ? refreshFromConf : newZone->getRefresh(), 1U);
-        setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), false, true);
+        params.soaRecordContent = loadRPZFromServer(logger, primary, zoneName, newZone, params.defpol, params.defpolOverrideLocal, params.maxTTL, params.tsigtriplet, params.maxReceivedBytes, params.localAddress, params.xfrTimeout);
+        newZone->setSerial(params.soaRecordContent->d_st.serial);
+        newZone->setRefresh(params.soaRecordContent->d_st.refresh);
+        refresh = std::max(params.refreshFromConf != 0 ? params.refreshFromConf : newZone->getRefresh(), 1U);
+        setRPZZoneNewState(polName, params.soaRecordContent->d_st.serial, newZone->size(), false, true);
 
-        g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) {
+        g_luaconfs.modify([zoneIdx = params.zoneIdx, &newZone](LuaConfigItems& lci) {
           lci.dfe.setZone(zoneIdx, newZone);
         });
 
-        if (!dumpZoneFileName.empty()) {
-          dumpZoneToDisk(logger, zoneName, newZone, dumpZoneFileName);
+        if (!params.dumpZoneFileName.empty()) {
+          dumpZoneToDisk(logger, zoneName, newZone, params.dumpZoneFileName);
         }
 
         /* no need to try another primary */
@@ -445,176 +425,207 @@ void RPZIXFRTracker(const std::vector<ComboAddress>& primaries, const boost::opt
     }
     // Release newZone before (long) sleep to reduce memory usage
     newZone = nullptr;
-    if (!sr) {
+    if (!params.soaRecordContent) {
       sleep(refresh);
     }
   }
+}
 
-  bool skipRefreshDelay = isPreloaded;
-
-  for (;;) {
-    // Don't hold on to oldZone, it well be re-assigned after sleep in the try block
-    oldZone = nullptr;
-    DNSRecord dr;
-    dr.setContent(sr);
+static void RPZTrackerIteration(RPZTrackerParams& params, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone>& oldZone, uint32_t& refresh, const string& polName, bool skipRefreshDelay, uint64_t configGeneration, Logr::log_t logger)
+{
+  // Don't hold on to oldZone, it well be re-assigned after sleep in the try block
+  oldZone = nullptr;
+  DNSRecord dr;
+  dr.setContent(params.soaRecordContent);
 
-    if (skipRefreshDelay) {
-      skipRefreshDelay = false;
-    }
-    else {
-      sleep(refresh);
-    }
-    auto luaconfsLocal = g_luaconfs.getLocal();
+  if (skipRefreshDelay) {
+    skipRefreshDelay = false;
+  }
+  else {
+    sleep(refresh);
+  }
+  auto luaconfsLocal = g_luaconfs.getLocal();
 
-    if (luaconfsLocal->generation != configGeneration) {
-      /* the configuration has been reloaded, meaning that a new thread
-         has been started to handle that zone and we are now obsolete.
-      */
-      SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl,
-           logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"));
-      return;
-    }
+  if (luaconfsLocal->generation != configGeneration) {
+    /* the configuration has been reloaded, meaning that a new thread
+       has been started to handle that zone and we are now obsolete.
+    */
+    SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl,
+         logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"));
+    return;
+  }
 
-    vector<pair<vector<DNSRecord>, vector<DNSRecord>>> deltas;
-    for (const auto& primary : primaries) {
-      auto soa = getRR<SOARecordContent>(dr);
-      auto serial = soa ? soa->d_st.serial : 0;
-      SLOG(g_log << Logger::Info << "Getting IXFR deltas for " << zoneName << " from " << primary.toStringWithPort() << ", our serial: " << serial << endl,
-           logger->info(Logr::Info, "Getting IXFR deltas", "address", Logging::Loggable(primary), "ourserial", Logging::Loggable(serial)));
+  vector<pair<vector<DNSRecord>, vector<DNSRecord>>> deltas;
+  for (const auto& primary : params.primaries) {
+    auto soa = getRR<SOARecordContent>(dr);
+    auto serial = soa ? soa->d_st.serial : 0;
+    SLOG(g_log << Logger::Info << "Getting IXFR deltas for " << zoneName << " from " << primary.toStringWithPort() << ", our serial: " << serial << endl,
+         logger->info(Logr::Info, "Getting IXFR deltas", "address", Logging::Loggable(primary), "ourserial", Logging::Loggable(serial)));
 
-      ComboAddress local(localAddress);
-      if (local == ComboAddress()) {
-        local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0);
-      }
+    ComboAddress local(params.localAddress);
+    if (local == ComboAddress()) {
+      local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0);
+    }
 
-      try {
-        deltas = getIXFRDeltas(primary, zoneName, dr, xfrTimeout, true, tt, &local, maxReceivedBytes);
+    try {
+      deltas = getIXFRDeltas(primary, zoneName, dr, params.xfrTimeout, true, params.tsigtriplet, &local, params.maxReceivedBytes);
 
-        /* no need to try another primary */
-        break;
-      }
-      catch (const std::runtime_error& e) {
-        SLOG(g_log << Logger::Warning << e.what() << endl,
-             logger->error(Logr::Warning, e.what(), "Exception during retrieval of delta", "exception", Logging::Loggable("std::runtime_error")));
-        incRPZFailedTransfers(polName);
-        continue;
-      }
+      /* no need to try another primary */
+      break;
     }
-
-    if (deltas.empty()) {
+    catch (const std::runtime_error& e) {
+      SLOG(g_log << Logger::Warning << e.what() << endl,
+           logger->error(Logr::Warning, e.what(), "Exception during retrieval of delta", "exception", Logging::Loggable("std::runtime_error")));
+      incRPZFailedTransfers(polName);
       continue;
     }
+  }
 
-    try {
-      SLOG(g_log << Logger::Info << "Processing " << deltas.size() << " delta" << addS(deltas) << " for RPZ " << zoneName << endl,
-           logger->info(Logr::Info, "Processing deltas", "size", Logging::Loggable(deltas.size())));
+  if (deltas.empty()) {
+    return;
+  }
 
-      if (luaconfsLocal->generation != configGeneration) {
-        SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl,
-             logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"));
-        return;
-      }
-      oldZone = luaconfsLocal->dfe.getZone(zoneIdx);
-      if (!oldZone || oldZone->getDomain() != zoneName) {
-        SLOG(g_log << Logger::Info << "This policy is no more, stopping the existing RPZ update thread for " << zoneName << endl,
-             logger->info(Logr::Info, "This policy is no more, stopping the existing RPZ update thread"));
-        return;
+  try {
+    SLOG(g_log << Logger::Info << "Processing " << deltas.size() << " delta" << addS(deltas) << " for RPZ " << zoneName << endl,
+         logger->info(Logr::Info, "Processing deltas", "size", Logging::Loggable(deltas.size())));
+
+    if (luaconfsLocal->generation != configGeneration) {
+      SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl,
+           logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"));
+      return;
+    }
+    oldZone = luaconfsLocal->dfe.getZone(params.zoneIdx);
+    if (!oldZone || oldZone->getDomain() != zoneName) {
+      SLOG(g_log << Logger::Info << "This policy is no more, stopping the existing RPZ update thread for " << zoneName << endl,
+           logger->info(Logr::Info, "This policy is no more, stopping the existing RPZ update thread"));
+      return;
+    }
+    /* we need to make a _full copy_ of the zone we are going to work on */
+    std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
+    /* initialize the current serial to the last one */
+    std::shared_ptr<const SOARecordContent> currentSR = params.soaRecordContent;
+
+    int totremove = 0;
+    int totadd = 0;
+    bool fullUpdate = false;
+    for (const auto& delta : deltas) {
+      const auto& remove = delta.first;
+      const auto& add = delta.second;
+      if (remove.empty()) {
+        SLOG(g_log << Logger::Warning << "IXFR update is a whole new zone" << endl,
+             logger->info(Logr::Warning, "IXFR update is a whole new zone"));
+        newZone->clear();
+        fullUpdate = true;
       }
-      /* we need to make a _full copy_ of the zone we are going to work on */
-      std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
-      /* initialize the current serial to the last one */
-      std::shared_ptr<const SOARecordContent> currentSR = sr;
-
-      int totremove = 0, totadd = 0;
-      bool fullUpdate = false;
-      for (const auto& delta : deltas) {
-        const auto& remove = delta.first;
-        const auto& add = delta.second;
-        if (remove.empty()) {
-          SLOG(g_log << Logger::Warning << "IXFR update is a whole new zone" << endl,
-               logger->info(Logr::Warning, "IXFR update is a whole new zone"));
-          newZone->clear();
-          fullUpdate = true;
+      for (const auto& resourceRecord : remove) { // should always contain the SOA
+        if (resourceRecord.d_type == QType::NS) {
+          continue;
         }
-        for (const auto& rr : remove) { // should always contain the SOA
-          if (rr.d_type == QType::NS)
-            continue;
-          if (rr.d_type == QType::SOA) {
-            auto oldsr = getRR<SOARecordContent>(rr);
-            if (oldsr && oldsr->d_st.serial == currentSR->d_st.serial) {
-              //           cout<<"Got good removal of SOA serial "<<oldsr->d_st.serial<<endl;
-            }
-            else {
-              if (!oldsr) {
-                throw std::runtime_error("Unable to extract serial from SOA record while processing the removal part of an update");
-              }
-              else {
-                throw std::runtime_error("Received an unexpected serial (" + std::to_string(oldsr->d_st.serial) + ", expecting " + std::to_string(currentSR->d_st.serial) + ") from SOA record while processing the removal part of an update");
-              }
-            }
+        if (resourceRecord.d_type == QType::SOA) {
+          auto oldsr = getRR<SOARecordContent>(resourceRecord);
+          if (oldsr && oldsr->d_st.serial == currentSR->d_st.serial) {
+            //     cout<<"Got good removal of SOA serial "<<oldsr->d_st.serial<<endl;
           }
           else {
-            totremove++;
-            SLOG(g_log << (g_logRPZChanges ? Logger::Info : Logger::Debug) << "Had removal of " << rr.d_name << " from RPZ zone " << zoneName << endl,
-                 logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Remove from RPZ zone", "name", Logging::Loggable(rr.d_name)));
-            RPZRecordToPolicy(rr, newZone, false, defpol, defpolOverrideLocal, maxTTL, logger);
-          }
-        }
-
-        for (const auto& rr : add) { // should always contain the new SOA
-          if (rr.d_type == QType::NS)
-            continue;
-          if (rr.d_type == QType::SOA) {
-            auto tempSR = getRR<SOARecordContent>(rr);
-            //   g_log<<Logger::Info<<"New SOA serial for "<<zoneName<<": "<<currentSR->d_st.serial<<endl;
-            if (tempSR) {
-              currentSR = std::move(tempSR);
+            if (!oldsr) {
+              throw std::runtime_error("Unable to extract serial from SOA record while processing the removal part of an update");
             }
-          }
-          else {
-            totadd++;
-            SLOG(g_log << (g_logRPZChanges ? Logger::Info : Logger::Debug) << "Had addition of " << rr.d_name << " to RPZ zone " << zoneName << endl,
-                 logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Addition to RPZ zone", "name", Logging::Loggable(rr.d_name)));
-            RPZRecordToPolicy(rr, newZone, true, defpol, defpolOverrideLocal, maxTTL, logger);
+            throw std::runtime_error("Received an unexpected serial (" + std::to_string(oldsr->d_st.serial) + ", expecting " + std::to_string(currentSR->d_st.serial) + ") from SOA record while processing the removal part of an update");
           }
         }
+        else {
+          totremove++;
+          SLOG(g_log << (g_logRPZChanges ? Logger::Info : Logger::Debug) << "Had removal of " << resourceRecord.d_name << " from RPZ zone " << zoneName << endl,
+               logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Remove from RPZ zone", "name", Logging::Loggable(resourceRecord.d_name)));
+          RPZRecordToPolicy(resourceRecord, newZone, false, params.defpol, params.defpolOverrideLocal, params.maxTTL, logger);
+        }
       }
 
-      /* only update sr now that all changes have been converted */
-      if (currentSR) {
-        sr = std::move(currentSR);
-      }
-      SLOG(g_log << Logger::Info << "Had " << totremove << " RPZ removal" << addS(totremove) << ", " << totadd << " addition" << addS(totadd) << " for " << zoneName << " New serial: " << sr->d_st.serial << endl,
-           logger->info(Logr::Info, "RPZ mutations", "removals", Logging::Loggable(totremove), "additions", Logging::Loggable(totadd), "newserial", Logging::Loggable(sr->d_st.serial)));
-      newZone->setSerial(sr->d_st.serial);
-      newZone->setRefresh(sr->d_st.refresh);
-      setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), false, fullUpdate);
-
-      /* we need to replace the existing zone with the new one,
-         but we don't want to touch anything else, especially other zones,
-         since they might have been updated by another RPZ IXFR tracker thread.
-      */
-      if (luaconfsLocal->generation != configGeneration) {
-        SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl,
-             logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"));
-        return;
+      for (const auto& resourceRecord : add) { // should always contain the new SOA
+        if (resourceRecord.d_type == QType::NS) {
+          continue;
+        }
+        if (resourceRecord.d_type == QType::SOA) {
+          auto tempSR = getRR<SOARecordContent>(resourceRecord);
+          //     g_log<<Logger::Info<<"New SOA serial for "<<zoneName<<": "<<currentSR->d_st.serial<<endl;
+          if (tempSR) {
+            currentSR = std::move(tempSR);
+          }
+        }
+        else {
+          totadd++;
+          SLOG(g_log << (g_logRPZChanges ? Logger::Info : Logger::Debug) << "Had addition of " << resourceRecord.d_name << " to RPZ zone " << zoneName << endl,
+               logger->info(g_logRPZChanges ? Logr::Info : Logr::Debug, "Addition to RPZ zone", "name", Logging::Loggable(resourceRecord.d_name)));
+          RPZRecordToPolicy(resourceRecord, newZone, true, params.defpol, params.defpolOverrideLocal, params.maxTTL, logger);
+        }
       }
-      g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) {
-        lci.dfe.setZone(zoneIdx, newZone);
-      });
+    }
 
-      if (!dumpZoneFileName.empty()) {
-        dumpZoneToDisk(logger, zoneName, newZone, dumpZoneFileName);
-      }
-      refresh = std::max(refreshFromConf ? refreshFromConf : newZone->getRefresh(), 1U);
+    /* only update sr now that all changes have been converted */
+    if (currentSR) {
+      params.soaRecordContent = std::move(currentSR);
     }
-    catch (const std::exception& e) {
-      SLOG(g_log << Logger::Error << "Error while applying the update received over XFR for " << zoneName << ", skipping the update: " << e.what() << endl,
-           logger->error(Logr::Error, e.what(), "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("std::exception")));
+    SLOG(g_log << Logger::Info << "Had " << totremove << " RPZ removal" << addS(totremove) << ", " << totadd << " addition" << addS(totadd) << " for " << zoneName << " New serial: " << params.soaRecordContent->d_st.serial << endl,
+         logger->info(Logr::Info, "RPZ mutations", "removals", Logging::Loggable(totremove), "additions", Logging::Loggable(totadd), "newserial", Logging::Loggable(params.soaRecordContent->d_st.serial)));
+    newZone->setSerial(params.soaRecordContent->d_st.serial);
+    newZone->setRefresh(params.soaRecordContent->d_st.refresh);
+    setRPZZoneNewState(polName, params.soaRecordContent->d_st.serial, newZone->size(), false, fullUpdate);
+
+    /* we need to replace the existing zone with the new one,
+       but we don't want to touch anything else, especially other zones,
+       since they might have been updated by another RPZ IXFR tracker thread.
+    */
+    if (luaconfsLocal->generation != configGeneration) {
+      SLOG(g_log << Logger::Info << "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName << endl,
+           logger->info(Logr::Info, "A more recent configuration has been found, stopping the existing RPZ update thread"));
+      return;
     }
-    catch (const PDNSException& e) {
-      SLOG(g_log << Logger::Error << "Error while applying the update received over XFR for " << zoneName << ", skipping the update: " << e.reason << endl,
-           logger->error(Logr::Error, e.reason, "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("PDNSException")));
+    g_luaconfs.modify([zoneIdx = params.zoneIdx, &newZone](LuaConfigItems& lci) {
+      lci.dfe.setZone(zoneIdx, newZone);
+    });
+
+    if (!params.dumpZoneFileName.empty()) {
+      dumpZoneToDisk(logger, zoneName, newZone, params.dumpZoneFileName);
     }
+    refresh = std::max(params.refreshFromConf != 0 ? params.refreshFromConf : newZone->getRefresh(), 1U);
+  }
+  catch (const std::exception& e) {
+    SLOG(g_log << Logger::Error << "Error while applying the update received over XFR for " << zoneName << ", skipping the update: " << e.what() << endl,
+         logger->error(Logr::Error, e.what(), "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("std::exception")));
+  }
+  catch (const PDNSException& e) {
+    SLOG(g_log << Logger::Error << "Error while applying the update received over XFR for " << zoneName << ", skipping the update: " << e.reason << endl,
+         logger->error(Logr::Error, e.reason, "Exception while applying the update received over XFR, skipping", "exception", Logging::Loggable("PDNSException")));
+  }
+}
+
+void RPZIXFRTracker(RPZTrackerParams params, uint64_t configGeneration)
+{
+  setThreadName("rec/rpzixfr");
+  bool isPreloaded = params.soaRecordContent != nullptr;
+  auto logger = g_slog->withName("rpz");
+
+  /* we can _never_ modify this zone directly, we need to do a full copy then replace the existing zone */
+  std::shared_ptr<DNSFilterEngine::Zone> oldZone = g_luaconfs.getLocal()->dfe.getZone(params.zoneIdx);
+  if (!oldZone) {
+    SLOG(g_log << Logger::Error << "Unable to retrieve RPZ zone with index " << params.zoneIdx << " from the configuration, exiting" << endl,
+         logger->error(Logr::Error, "Unable to retrieve RPZ zone from configuration", "index", Logging::Loggable(params.zoneIdx)));
+    return;
+  }
+
+  // If oldZone failed to load its getRefresh() returns 0, protect against that
+  uint32_t refresh = std::max(params.refreshFromConf != 0 ? params.refreshFromConf : oldZone->getRefresh(), 10U);
+  DNSName zoneName = oldZone->getDomain();
+  std::string polName = !oldZone->getName().empty() ? oldZone->getName() : zoneName.toStringNoDot();
+
+  // Now that we know the name, set it in the logger
+  logger = logger->withValues("zone", Logging::Loggable(zoneName));
+
+  preloadRPZFIle(params, zoneName, oldZone, refresh, polName, logger);
+
+  bool skipRefreshDelay = isPreloaded;
+
+  for (;;) {
+    RPZTrackerIteration(params, zoneName, oldZone, refresh, polName, skipRefreshDelay, configGeneration, logger);
   }
 }
index 8f37a0b4c0f7613ec3770ca1a0be5b17a904a6ad..c8811ee0b3d9f90fa91b64430ffe266197bc430d 100644 (file)
 
 extern bool g_logRPZChanges;
 
+// Please make sure that the struct below only contains value types since they are used as parameters in a thread ct
+struct RPZTrackerParams {
+  std::vector<ComboAddress> primaries;
+  boost::optional<DNSFilterEngine::Policy> defpol;
+  bool defpolOverrideLocal;
+  uint32_t maxTTL;
+  size_t zoneIdx;
+  TSIGTriplet tsigtriplet;
+  size_t maxReceivedBytes;
+  ComboAddress localAddress;
+  uint16_t xfrTimeout;
+  uint32_t refreshFromConf;
+  std::shared_ptr<const SOARecordContent> soaRecordContent;
+  std::string dumpZoneFileName;
+};
+
 std::shared_ptr<const SOARecordContent> loadRPZFromFile(const std::string& fname, std::shared_ptr<DNSFilterEngine::Zone> zone, const boost::optional<DNSFilterEngine::Policy>& defpol, bool defpolOverrideLocal, uint32_t maxTTL);
-void RPZIXFRTracker(const std::vector<ComboAddress>& primaries, const boost::optional<DNSFilterEngine::Policy>& defpol, bool defpolOverrideLocal, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t xfrTimeout, const uint32_t reloadFromConf, shared_ptr<const SOARecordContent> sr, const std::string& dumpZoneFileName, uint64_t configGeneration);
+void RPZIXFRTracker(RPZTrackerParams params, uint64_t configGeneration);
 
 struct rpzStats
 {