]> granicus.if.org Git - pdns/commitdiff
rec: Add the possibility to dump RPZ updates to a file
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 16 Apr 2018 16:57:35 +0000 (18:57 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 18 Apr 2018 08:51:10 +0000 (10:51 +0200)
pdns/rec-lua-conf.cc
pdns/rpzloader.cc
pdns/rpzloader.hh

index 65a63f94d01d42a820701ad63b45ed849198d529..b6f843820758d9110be2d38e581d1a129eab0124 100644 (file)
@@ -149,6 +149,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
       ComboAddress localAddress;
       ComboAddress master(master_, 53);
       size_t zoneIdx;
+      std::string dumpFile;
       std::shared_ptr<SOARecordContent> sr = nullptr;
 
       try {
@@ -189,6 +190,10 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
           if(have.count("seedFile")) {
             seedFile = boost::get<std::string>(constGet(have, "seedFile"));
           }
+
+          if(have.count("dumpFile")) {
+            dumpFile = boost::get<std::string>(constGet(have, "dumpFile"));
+          }
         }
 
         if (localAddress != ComboAddress() && localAddress.sin4.sin_family != master.sin4.sin_family) {
@@ -203,13 +208,20 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
         zoneIdx = lci.dfe.addZone(zone);
 
         if (!seedFile.empty()) {
-          sr = loadRPZFromFile(seedFile, zone, defpol, maxTTL);
-          if (zone->getDomain() != domain) {
-            throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") does not match the one passed in parameter (" + domain.toString() + ")");
-          }
+          g_log<<Logger::Info<<"Pre-loading RPZ zone "<<zoneName<<" from seed file '"<<seedFile<<"'"<<endl;
+          try {
+            sr = loadRPZFromFile(seedFile, zone, defpol, maxTTL);
 
-          if (sr == nullptr) {
-            throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") has no SOA record");
+            if (zone->getDomain() != domain) {
+              throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") does not match the one passed in parameter (" + domain.toString() + ")");
+            }
+
+            if (sr == nullptr) {
+              throw PDNSException("The RPZ zone " + zoneName + " loaded from the seed file (" + zone->getDomain().toString() + ") has no SOA record");
+            }
+          }
+          catch(const std::exception& e) {
+            g_log<<Logger::Warning<<"Unable to pre-load RPZ zone "<<zoneName<<" from seed file '"<<seedFile<<"': "<<e.what()<<endl;
           }
         }
       }
@@ -224,7 +236,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
 
       try {
           if (!checkOnly) {
-            std::thread t(RPZIXFRTracker, master, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes * 1024 * 1024, localAddress, zone, axfrTimeout, sr, lci.generation);
+            std::thread t(RPZIXFRTracker, master, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes * 1024 * 1024, localAddress, zone, axfrTimeout, sr, dumpFile, lci.generation);
             t.detach();
           }
       }
index 73a6dae3d8e6c51893f07957e5cf1439b29d4a78..8466b8da193210da0fe28495aa5ba828c4992fde 100644 (file)
@@ -287,7 +287,57 @@ static void setRPZZoneNewState(const std::string& zone, uint32_t serial, uint64_
   stats->d_numberOfRecords = numberOfRecords;
 }
 
-void RPZIXFRTracker(const ComboAddress& master, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, std::shared_ptr<DNSFilterEngine::Zone> zone, const uint16_t axfrTimeout, std::shared_ptr<SOARecordContent> sr, uint64_t configGeneration)
+static bool dumpZoneToDisk(const DNSName& zoneName, const std::shared_ptr<DNSFilterEngine::Zone>& newZone, const std::string& dumpZoneFileName)
+{
+  std::string temp = dumpZoneFileName + "XXXXXX";
+  int fd = mkstemp(&temp.at(0));
+  if (fd < 0) {
+    g_log<<Logger::Warning<<"Unable to open a file to dump the content of the RPZ zone "<<zoneName.toLogString()<<endl;
+    return false;
+  }
+
+  FILE * fp = fdopen(fd, "w+");
+  if (fp == nullptr) {
+    close(fd);
+    g_log<<Logger::Warning<<"Unable to open a file pointer to dump the content of the RPZ zone "<<zoneName.toLogString()<<endl;
+    return false;
+  }
+
+  fd = -1;
+
+  try {
+    newZone->dump(fp);
+  }
+  catch(const std::exception& e) {
+    g_log<<Logger::Warning<<"Error while dumping the content of the RPZ zone "<<zoneName.toLogString()<<": "<<e.what()<<endl;
+    fclose(fp);
+    return false;
+  }
+
+  if (fflush(fp) != 0) {
+    g_log<<Logger::Warning<<"Error while flushing the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
+    return false;
+  }
+
+  if (fsync(fileno(fp)) != 0) {
+    g_log<<Logger::Warning<<"Error while syncing the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
+    return false;
+  }
+
+  if (fclose(fp) != 0) {
+    g_log<<Logger::Warning<<"Error while writing the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
+    return false;
+  }
+
+  if (rename(temp.c_str(), dumpZoneFileName.c_str()) != 0) {
+    g_log<<Logger::Warning<<"Error while moving the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
+    return false;
+  }
+
+  return true;
+}
+
+void RPZIXFRTracker(const ComboAddress& master, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, std::shared_ptr<DNSFilterEngine::Zone> zone, const uint16_t axfrTimeout, std::shared_ptr<SOARecordContent> sr, std::string dumpZoneFileName, uint64_t configGeneration)
 {
   bool isPreloaded = sr != nullptr;
   uint32_t refresh = zone->getRefresh();
@@ -304,6 +354,10 @@ void RPZIXFRTracker(const ComboAddress& master, boost::optional<DNSFilterEngine:
       }
       zone->setSerial(sr->d_st.serial);
       setRPZZoneNewState(polName, sr->d_st.serial, zone->size(), true);
+
+      if (!dumpZoneFileName.empty()) {
+        dumpZoneToDisk(zoneName, zone, dumpZoneFileName);
+      }
     }
     catch(const std::exception& e) {
       g_log<<Logger::Warning<<"Unable to load RPZ zone '"<<zoneName<<"' from '"<<master<<"': '"<<e.what()<<"'. (Will try again in "<<(refresh > 0 ? refresh : 10)<<" seconds...)"<<endl;
@@ -423,5 +477,9 @@ void RPZIXFRTracker(const ComboAddress& master, boost::optional<DNSFilterEngine:
     g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) {
                         lci.dfe.setZone(zoneIdx, newZone);
                       });
+
+    if (!dumpZoneFileName.empty()) {
+      dumpZoneToDisk(zoneName, newZone, dumpZoneFileName);
+    }
   }
 }
index 347084fef1a69e2f7d1b622e41409a807231c785..f3b43128c677a0803590b68d6a85fa9f4acdf7f4 100644 (file)
@@ -29,7 +29,7 @@ extern bool g_logRPZChanges;
 std::shared_ptr<SOARecordContent> loadRPZFromFile(const std::string& fname, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL);
 std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout);
 void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr<DNSFilterEngine::Zone> zone, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL);
-void RPZIXFRTracker(const ComboAddress& master, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, std::shared_ptr<DNSFilterEngine::Zone> zone, const uint16_t axfrTimeout, shared_ptr<SOARecordContent> sr, uint64_t configGeneration);
+void RPZIXFRTracker(const ComboAddress& master, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, std::shared_ptr<DNSFilterEngine::Zone> zone, const uint16_t axfrTimeout, shared_ptr<SOARecordContent> sr, std::string dumpZoneFileName, uint64_t configGeneration);
 
 struct rpzStats
 {