]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Only remove NSEC3 pairs when removing ENT if there are no other records.
authorMiod Vallat <miod.vallat@powerdns.com>
Fri, 4 Jul 2025 07:26:22 +0000 (09:26 +0200)
committerMiod Vallat <miod.vallat@powerdns.com>
Fri, 4 Jul 2025 07:26:22 +0000 (09:26 +0200)
This logic was added in 2a8a5c7629984e51b717494a23c0c6651de0b030 but is
too aggressive.

Signed-off-by: Miod Vallat <miod.vallat@powerdns.com>
modules/lmdbbackend/lmdbbackend.cc
modules/lmdbbackend/lmdbbackend.hh

index a8d768715b7d27ceb26c3165e22f80648a49bbd8..6982323b4be0917a7a22781bbd891ba2b6c5e144 100644 (file)
@@ -1247,6 +1247,33 @@ void LMDBBackend::writeNSEC3RecordPair(const std::shared_ptr<RecordsRWTransactio
   txn->txn->put(txn->db->dbi, co(domain_id, qname, QType::NSEC3), ser);
 }
 
+// Check if the only records found for this particular name are a single NSEC3
+// record. (in which case there is no actual data for than qname and that
+// record needs to be deleted)
+bool LMDBBackend::hasOrphanedNSEC3Record(MDBRWCursor& cursor, domainid_t domain_id, const DNSName& qname)
+{
+  compoundOrdername co; // NOLINT(readability-identifier-length)
+  bool seenNSEC3{false};
+  bool seenOther{false};
+  MDBOutVal key{};
+  MDBOutVal val{};
+
+  if (cursor.prefix(co(domain_id, qname), key, val) == 0) {
+    do {
+      if (compoundOrdername::getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
+        seenNSEC3 = true;
+      }
+      else {
+        seenOther = true;
+      }
+      if (seenNSEC3 && seenOther) {
+        break;
+      }
+    } while (cursor.next(key, val) == 0);
+  }
+  return seenNSEC3 && !seenOther;
+}
+
 // d_rwtxn must be set here
 bool LMDBBackend::feedRecord(const DNSResourceRecord& r, const DNSName& ordername, bool ordernameIsNSEC3)
 {
@@ -1365,22 +1392,7 @@ bool LMDBBackend::replaceRRSet(domainid_t domain_id, const DNSName& qname, const
       // there aren't any, yet there is an NSEC3 record, delete the NSEC3 chain
       // pair as well.
       if (rrset.empty()) {
-        bool seenNSEC3{false};
-        bool seenOther{false};
-        if (cursor.prefix(co(domain_id, relative), key, val) == 0) {
-          do {
-            if (compoundOrdername::getQType(key.getNoStripHeader<StringView>()) == QType::NSEC3) {
-              seenNSEC3 = true;
-            }
-            else {
-              seenOther = true;
-            }
-            if (seenNSEC3 && seenOther) {
-              break;
-            }
-          } while (cursor.next(key, val) == 0);
-        }
-        if (!seenOther && seenNSEC3) {
+        if (hasOrphanedNSEC3Record(cursor, domain_id, relative)) {
           deleteNSEC3RecordPair(txn, domain_id, relative);
         }
       }
@@ -2815,9 +2827,12 @@ bool LMDBBackend::updateEmptyNonTerminals(domainid_t domain_id, set<DNSName>& in
     for (auto n : erase) {
       // cout <<" -"<<n<<endl;
       n.makeUsRelative(di.zone);
-      // Remove possible NSEC3 record pair tied to that ENT.
-      deleteNSEC3RecordPair(txn, domain_id, n);
       txn->txn->del(txn->db->dbi, co(domain_id, n, QType::ENT));
+      // Remove possible orphaned NSEC3 record pair tied to that ENT.
+      auto cursor = txn->txn->getCursor(txn->db->dbi);
+      if (hasOrphanedNSEC3Record(cursor, domain_id, n)) {
+        deleteNSEC3RecordPair(txn, domain_id, n);
+      }
     }
   }
   if (needCommit)
index fa92eb64e325be05c3dd47f743e9236882838a42..fe2a5a87b44d78f90cf23c1a901d9bb16a3589e8 100644 (file)
@@ -342,6 +342,7 @@ private:
   static bool getAfterForwardFromStart(MDBROCursor& cursor, MDBOutVal& key, MDBOutVal& val, domainid_t id, DNSName& after);
   static bool isNSEC3BackRecord(LMDBResourceRecord& lrr, const MDBOutVal& key, const MDBOutVal& val);
   static bool isValidAuthRecord(const MDBOutVal& key, const MDBOutVal& val);
+  static bool hasOrphanedNSEC3Record(MDBRWCursor& cursor, domainid_t domain_id, const DNSName& qname);
   static void deleteNSEC3RecordPair(const std::shared_ptr<RecordsRWTransaction>& txn, domainid_t domain_id, const DNSName& qname);
   void writeNSEC3RecordPair(const std::shared_ptr<RecordsRWTransaction>& txn, domainid_t domain_id, const DNSName& qname, const DNSName& ordername);