]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Give backends the ability to perform extra actions during zone rectify. 16512/head
authorMiod Vallat <miod.vallat@powerdns.com>
Wed, 23 Jul 2025 12:26:09 +0000 (14:26 +0200)
committerMiod Vallat <miod.vallat@powerdns.com>
Mon, 17 Nov 2025 10:57:50 +0000 (11:57 +0100)
Use this is the LMDB backend to purge possibly orphaned (dangling) NSEC3
records created by 4.x servers.

Signed-off-by: Miod Vallat <miod.vallat@powerdns.com>
(cherry picked from commit be43b2e70193b13c01a268381b654dce8b6cc7ec)

modules/lmdbbackend/lmdbbackend.cc
modules/lmdbbackend/lmdbbackend.hh
pdns/dbdnsseckeeper.cc
pdns/dnsbackend.hh

index 020b8d0ef4e998f83524daa44ae287cad5343f32..b623caa9ce1632f53652915e08356ff49d554d2b 100644 (file)
@@ -1150,7 +1150,7 @@ static std::shared_ptr<DNSRecordContent> deserializeContentZR(uint16_t qtype, co
 #define StringView string
 #endif
 
-void LMDBBackend::deleteDomainRecords(RecordsRWTransaction& txn, const std::string& match)
+void LMDBBackend::deleteDomainRecords(RecordsRWTransaction& txn, const std::string& match, QType qtype)
 {
   auto cursor = txn.txn->getCursor(txn.db->dbi);
   MDBOutVal key{};
@@ -1158,7 +1158,9 @@ void LMDBBackend::deleteDomainRecords(RecordsRWTransaction& txn, const std::stri
 
   if (cursor.prefix(match, key, val) == 0) {
     do {
-      cursor.del(key);
+      if (qtype == QType::ANY || compoundOrdername::getQType(key.getNoStripHeader<StringView>()) == qtype) {
+        cursor.del(key);
+      }
     } while (cursor.next(key, val) == 0);
   }
 }
@@ -3278,6 +3280,25 @@ bool LMDBBackend::hasCreatedLocalFiles() const
   return MDBDbi::d_creationCount != 0;
 }
 
+// Hook for rectifyZone operation.
+// Before the operation starts, we forcibly remove all NSEC3 records from the
+// domain, since logic flaws in older versions may have left us with dangling
+// records. The appropriate records will be regenerated with
+// updateDNSSECOrderNameAndAuth() calls anyway.
+void LMDBBackend::rectifyZoneHook(domainid_t domain_id, bool before) const
+{
+  if (!before) {
+    return;
+  }
+
+  if (!d_rwtxn) {
+    throw DBException("rectifyZoneHook invoked outside of a transaction");
+  }
+
+  compoundOrdername order;
+  LMDBBackend::deleteDomainRecords(*d_rwtxn, order(domain_id), QType::NSEC3);
+}
+
 class LMDBFactory : public BackendFactory
 {
 public:
index f7cf912cecb889d45854cae69f85c1ef3fa49685..c1ef7df5cd014aafc16c88d410e6c28ec96f5e72 100644 (file)
@@ -171,6 +171,8 @@ public:
 
   bool hasCreatedLocalFiles() const override;
 
+  void rectifyZoneHook(domainid_t domain_id, bool before) const override;
+
   // functions to use without constructing a backend object
   static std::pair<uint32_t, uint32_t> getSchemaVersionAndShards(std::string& filename);
   static bool upgradeToSchemav5(std::string& filename);
@@ -335,7 +337,7 @@ private:
   std::shared_ptr<RecordsROTransaction> getRecordsROTransaction(domainid_t id, const std::shared_ptr<LMDBBackend::RecordsRWTransaction>& rwtxn = nullptr);
   int genChangeDomain(const ZoneName& domain, const std::function<void(DomainInfo&)>& func);
   int genChangeDomain(domainid_t id, const std::function<void(DomainInfo&)>& func);
-  static void deleteDomainRecords(RecordsRWTransaction& txn, const std::string& match);
+  static void deleteDomainRecords(RecordsRWTransaction& txn, const std::string& match, QType qtype = QType::ANY);
 
   bool findDomain(const ZoneName& domain, DomainInfo& info) const;
   bool findDomain(domainid_t domainid, DomainInfo& info) const;
index 2e834fc4c44c891718150ca388f334c02d98a5a5..32ee65256cb397b95fe20eb1d56ef5d3176706dc 100644 (file)
@@ -855,6 +855,8 @@ bool DNSSECKeeper::rectifyZone(const ZoneName& zone, string& error, string& info
   if (doTransaction)
     sd.db->startTransaction(zone, UnknownDomainID);
 
+  sd.db->rectifyZoneHook(sd.domain_id, true);
+
   bool realrr=true;
   bool doent=true;
   int updates=0;
@@ -967,6 +969,8 @@ bool DNSSECKeeper::rectifyZone(const ZoneName& zone, string& error, string& info
     }
   }
 
+  sd.db->rectifyZoneHook(sd.domain_id, false);
+
   if (doTransaction)
     sd.db->commitTransaction();
 
index f87391e63cdb4ca31e4681a49a4c8559b0e8ee14..6807461cd7fb10f713f67be9fd44bdb661abe564 100644 (file)
@@ -513,6 +513,10 @@ public:
     return false;
   }
 
+  virtual void rectifyZoneHook(domainid_t /*domain_id*/, bool /*before*/) const
+  {
+  }
+
   const string& getPrefix() { return d_prefix; };
 
 protected: