]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Implement listSubZone in LMDB backend.
authorMiod Vallat <miod.vallat@powerdns.com>
Thu, 10 Jul 2025 07:12:47 +0000 (09:12 +0200)
committerMiod Vallat <miod.vallat@powerdns.com>
Fri, 11 Jul 2025 07:29:28 +0000 (09:29 +0200)
Signed-off-by: Miod Vallat <miod.vallat@powerdns.com>
modules/lmdbbackend/lmdbbackend.cc
modules/lmdbbackend/lmdbbackend.hh

index 0501902ab0bb5b3412f3a9eca5eac4a881cb4bfb..8dc749ed48ffe17cfbf805d6e081f689bf983f2a 100644 (file)
@@ -1722,6 +1722,7 @@ bool LMDBBackend::deleteDomain(const ZoneName& domain)
  *
  * d_lookupdomain: current domain being processed (appended to the
  *                 results' names)
+ * d_lookupsubmatch: relative name used for submatching (for listSubZone)
  * d_currentrrset: temporary vector of results (records found at the same
  *                 cursor, i.e. same qname but possibly different qtype)
  * d_currentrrsetpos: position in the above when returning its elements one
@@ -1734,6 +1735,7 @@ bool LMDBBackend::deleteDomain(const ZoneName& domain)
 bool LMDBBackend::list(const ZoneName& target, domainid_t domain_id, bool include_disabled)
 {
   d_lookupdomain = target;
+  d_lookupsubmatch.clear();
   d_includedisabled = include_disabled;
 
   compoundOrdername order;
@@ -1743,6 +1745,33 @@ bool LMDBBackend::list(const ZoneName& target, domainid_t domain_id, bool includ
   return true;
 }
 
+bool LMDBBackend::listSubZone(const ZoneName& target, domainid_t domain_id)
+{
+  // 1. from domain_id get base domain name
+  DomainInfo info;
+  if (!d_tdomains->getROTransaction().get(domain_id, info)) {
+    return false;
+  }
+
+  // 2. make target relative to it
+  DNSName relqname = target.operator const DNSName&().makeRelative(info.zone);
+  if (relqname.empty()) {
+    return false;
+  }
+
+  // 3. enumerate complete domain, but tell get() to ignore entries which are
+  //    not subsets of target
+  d_lookupdomain = std::move(info.zone);
+  d_lookupsubmatch = std::move(relqname);
+  d_includedisabled = true;
+
+  compoundOrdername order;
+  std::string match = order(domain_id);
+
+  lookupStart(domain_id, match, false);
+  return true;
+}
+
 void LMDBBackend::lookupInternal(const QType& type, const DNSName& qdomain, domainid_t zoneId, DNSPacket* /* p */, bool include_disabled)
 {
   if (d_dolog) {
@@ -1780,6 +1809,7 @@ void LMDBBackend::lookupInternal(const QType& type, const DNSName& qdomain, doma
   // cout<<"get will look for "<<relqname<< " in zone "<<info.zone<<" with id "<<info.id<<" and type "<<type.toString()<<endl;
 
   d_lookupdomain = std::move(info.zone);
+  d_lookupsubmatch.clear();
   d_includedisabled = include_disabled;
 
   compoundOrdername order;
@@ -1804,7 +1834,8 @@ void LMDBBackend::lookupStart(domainid_t domain_id, const std::string& match, bo
   d_currentrrset.clear();
   d_currentrrsetpos = 0;
 
-  MDBOutVal key, val;
+  MDBOutVal key{};
+  MDBOutVal val{};
   if (d_getcursor->prefix(match, key, val) != 0) {
     d_getcursor.reset(); // will cause get() to fail
     if (dolog) {
@@ -1852,15 +1883,24 @@ bool LMDBBackend::get(DNSZoneRecord& zr)
     }
     try {
       const auto& lrr = d_currentrrset.at(d_currentrrsetpos++);
+      DNSName basename;
+      bool validRecord = d_includedisabled || !lrr.disabled;
+
+      if (validRecord) {
+        basename = compoundOrdername::getQName(key);
+        if (!d_lookupsubmatch.empty()) {
+          validRecord = basename.isPartOf(d_lookupsubmatch);
+        }
+      }
 
-      zr.disabled = lrr.disabled;
-      if (!zr.disabled || d_includedisabled) {
-        zr.dr.d_name = compoundOrdername::getQName(key) + d_lookupdomain.operator const DNSName&();
+      if (validRecord) {
+        zr.dr.d_name = basename + d_lookupdomain.operator const DNSName&();
         zr.domain_id = compoundOrdername::getDomainID(key);
         zr.dr.d_type = compoundOrdername::getQType(key).getCode();
         zr.dr.d_ttl = lrr.ttl;
         zr.dr.setContent(deserializeContentZR(zr.dr.d_type, zr.dr.d_name, lrr.content));
         zr.auth = lrr.auth;
+        zr.disabled = lrr.disabled;
       }
 
       if (d_currentrrsetpos >= d_currentrrset.size()) {
@@ -1871,7 +1911,7 @@ bool LMDBBackend::get(DNSZoneRecord& zr)
         }
       }
 
-      if (zr.disabled && !d_includedisabled) {
+      if (!validRecord) {
         continue;
       }
     }
index 94c535d96d7e10a5c5b091b581b7cb67988bb493..86b1cc96707e3db892ed300653d9e4a8027e5598 100644 (file)
@@ -75,6 +75,7 @@ public:
 
   unsigned int getCapabilities() override;
   bool list(const ZoneName& target, domainid_t domain_id, bool include_disabled) override;
+  bool listSubZone(const ZoneName& target, domainid_t domain_id) override;
 
   bool getDomainInfo(const ZoneName& domain, DomainInfo& info, bool getserial = true) override;
   bool createDomain(const ZoneName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& primaries, const string& account) override;
@@ -350,6 +351,7 @@ private:
   void writeNSEC3RecordPair(const std::shared_ptr<RecordsRWTransaction>& txn, domainid_t domain_id, const DNSName& qname, const DNSName& ordername);
 
   ZoneName d_lookupdomain;
+  DNSName d_lookupsubmatch;
   vector<LMDBResourceRecord> d_currentrrset;
   size_t d_currentrrsetpos;
   MDBOutVal d_currentKey;