From: Miod Vallat Date: Fri, 4 Jul 2025 07:26:22 +0000 (+0200) Subject: Only remove NSEC3 pairs when removing ENT if there are no other records. X-Git-Tag: rec-5.3.0-alpha2~7^2~1 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=34b4a343dd1f66e5174822bc0784c3bb5974f223;p=thirdparty%2Fpdns.git Only remove NSEC3 pairs when removing ENT if there are no other records. This logic was added in 2a8a5c7629984e51b717494a23c0c6651de0b030 but is too aggressive. Signed-off-by: Miod Vallat --- diff --git a/modules/lmdbbackend/lmdbbackend.cc b/modules/lmdbbackend/lmdbbackend.cc index a8d768715b..6982323b4b 100644 --- a/modules/lmdbbackend/lmdbbackend.cc +++ b/modules/lmdbbackend/lmdbbackend.cc @@ -1247,6 +1247,33 @@ void LMDBBackend::writeNSEC3RecordPair(const std::shared_ptrtxn->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()) == 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()) == 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& in for (auto n : erase) { // cout <<" -"<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) diff --git a/modules/lmdbbackend/lmdbbackend.hh b/modules/lmdbbackend/lmdbbackend.hh index fa92eb64e3..fe2a5a87b4 100644 --- a/modules/lmdbbackend/lmdbbackend.hh +++ b/modules/lmdbbackend/lmdbbackend.hh @@ -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& txn, domainid_t domain_id, const DNSName& qname); void writeNSEC3RecordPair(const std::shared_ptr& txn, domainid_t domain_id, const DNSName& qname, const DNSName& ordername);