]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Allow backends to report a coarse-grained capabilities mask.
authorMiod Vallat <miod.vallat@powerdns.com>
Mon, 31 Mar 2025 14:08:40 +0000 (16:08 +0200)
committerMiod Vallat <miod.vallat@powerdns.com>
Mon, 7 Apr 2025 09:59:55 +0000 (11:59 +0200)
The current capabilities are DNSSEC supports, comments, direct backend
commands, and zone listing (AXFR) ability.

doesDNSSEC() is rewritten as a trivial wrapper around this.

15 files changed:
docs/appendices/backend-writers-guide.rst
modules/bindbackend/bindbackend2.hh
modules/bindbackend/binddnssec.cc
modules/geoipbackend/geoipbackend.hh
modules/ldapbackend/ldapbackend.hh
modules/lmdbbackend/lmdbbackend.hh
modules/lua2backend/lua2api2.hh
modules/pipebackend/pipebackend.hh
modules/remotebackend/remotebackend.cc
modules/remotebackend/remotebackend.hh
modules/tinydnsbackend/tinydnsbackend.hh
pdns/backends/gsql/gsqlbackend.cc
pdns/backends/gsql/gsqlbackend.hh
pdns/dnsbackend.hh
pdns/test-ueberbackend_cc.cc

index d67a2ac4a96a173996df0fd15933a2b415dbef63..7fd50f2a2580442b8369bf55d8daf3ca8326ff88 100644 (file)
@@ -66,14 +66,14 @@ following methods are relevant:
         class DNSBackend
         {
         public:
-
+        virtual unsigned int getCapabilities()=0;
         virtual void lookup(const QType &qtype, const string &qdomain, int zoneId=-1, DNSPacket *pkt_p=nullptr)=0;
         virtual bool list(const string &target, int domain_id)=0;
         virtual bool get(DNSResourceRecord &r)=0;
         virtual bool getSOA(const string &name, SOAData &soadata);
         };
 
-Note that the first three methods must be implemented. ``getSOA()`` has
+Note that the first four methods must be implemented. ``getSOA()`` has
 a useful default implementation.
 
 The semantics are simple. Each instance of your class only handles one
@@ -162,9 +162,11 @@ furthermore, only about its A record:
     class RandomBackend : public DNSBackend
     {
     public:
+      unsigned int getCapabilities() override { return 0; }
+
       bool list(const string &target, int id)
       {
-        return false; // we don't support AXFR
+        return false; // we don't support pdnsutil list-zone or AXFR
       }
 
       void lookup(const QType &type, const string &qdomain, int zoneId, DNSPacket *p)
@@ -234,7 +236,7 @@ and such.
   as 'overlay', makes the zone incompatible with some operations that
   assume that a single zone is always entirely stored in the same backend.
   Such operations include zone transfers, listing and editing zone content via
-  the API or :doc:`pdnsutil <pdnsutil>`.
+  the API or :doc:`pdnsutil <../manpages/pdnsutil.1>`.
 
 .. warning::
   When the content of a zone is spread across multiple backends, all the types
@@ -345,6 +347,14 @@ Classes
 Methods
 ~~~~~~~
 
+.. cpp:function:: unsigned int getCapabilities()
+
+  This function returns a bitmask representing various capabilities of
+  the backend. The currently used capabilities are:
+
+* `CAP_DNSSEC`     Backend implements :ref:`backend-dnssec`.
+* `CAP_LIST`       Backend implements `list`, for AXFR or `pdnsutil list-zone`
+
 .. cpp:function:: void DNSBackend::lookup(const QType &qtype, const string &qdomain, int zoneId=-1, DNSPacket *pkt=nullptr)
 
   This function is used to initiate a straight lookup for a record of name
@@ -855,6 +865,8 @@ In order for a backend to support the storage of TSIG keys, the following operat
       /* ... */
     }
 
+.. _backend-dnssec:
+
 DNSSEC support
 --------------
 
@@ -872,8 +884,9 @@ In order for a backend to support DNSSEC, quite a few number of additional opera
 
     class DNSBackend {
     public:
+      virtual unsigned int getCapabilities();
+
       /* ... */
-      virtual bool doesDNSSEC();
       virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after);
 
       /* update operations */
@@ -894,9 +907,8 @@ In order for a backend to support DNSSEC, quite a few number of additional opera
       /* ... */
     }
 
-.. cpp:function:: virtual bool doesDNSSEC()
-
-  Returns true if that backend supports DNSSEC.
+In addition to these methods, the return value of `getCapabilities` must
+contain `CAP_DNSSEC` if that backend supports DNSSEC.
 
 .. cpp:function:: virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after)
 
index 118151d66986c4b4a14be437d30fe5f5420f4433..9fee22400488e59ed499f10d8fe94a05dc4f394e 100644 (file)
@@ -181,6 +181,7 @@ class Bind2Backend : public DNSBackend
 public:
   Bind2Backend(const string& suffix = "", bool loadZones = true);
   ~Bind2Backend() override;
+  unsigned int getCapabilities() override;
   void getUnfreshSecondaryInfos(vector<DomainInfo>* unfreshDomains) override;
   void getUpdatedPrimaries(vector<DomainInfo>& changedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
   bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getSerial = true) override;
@@ -220,7 +221,6 @@ public:
   bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) override;
   bool deleteTSIGKey(const DNSName& name) override;
   bool getTSIGKeys(std::vector<struct TSIGKey>& keys) override;
-  bool doesDNSSEC() override;
   // end of DNSSEC
 
   typedef multi_index_container<BB2DomainInfo,
index f378bf2ffbc696ac57b12f55c461bb41fe091571..130417d17c85160ae774861f4ca99bcb91a7238c 100644 (file)
@@ -36,9 +36,14 @@ void Bind2Backend::setupDNSSEC()
   }
 }
 
-bool Bind2Backend::doesDNSSEC()
+unsigned int Bind2Backend::getCapabilities()
 {
-  return d_hybrid;
+  if (d_hybrid) {
+    return CAP_DNSSEC | CAP_LIST;
+  }
+  else {
+    return CAP_LIST;
+  }
 }
 
 bool Bind2Backend::getNSEC3PARAM(const DNSName& /* name */, NSEC3PARAMRecordContent* /* ns3p */)
@@ -197,9 +202,12 @@ void Bind2Backend::freeStatements()
   d_getTSIGKeysQuery_stmt.reset();
 }
 
-bool Bind2Backend::doesDNSSEC()
+unsigned int Bind2Backend::getCapabilities()
 {
-  return d_dnssecdb || d_hybrid;
+  if (d_dnssecdb || d_hybrid) {
+    return CAP_DNSSEC | CAP_LIST;
+  }
+  return CAP_LIST;
 }
 
 bool Bind2Backend::getNSEC3PARAM(const DNSName& name, NSEC3PARAMRecordContent* ns3p)
index 4fe284d3a1cf7cffb6bd3117144aa70c45ecd9d6..baff3ec2aace78108d81d90ebc9dba5d836c87a6 100644 (file)
@@ -55,6 +55,16 @@ public:
   GeoIPBackend(const std::string& suffix = "");
   ~GeoIPBackend() override;
 
+  unsigned int getCapabilities() override
+  {
+    if (d_dnssec) {
+      return CAP_DNSSEC;
+    }
+    else {
+      return 0;
+    }
+  }
+
   void lookup(const QType& qtype, const DNSName& qdomain, int zoneId, DNSPacket* pkt_p = nullptr) override;
   bool list(const DNSName& /* target */, int /* domain_id */, bool /* include_disabled */ = false) override { return false; } // not supported
   bool get(DNSResourceRecord& r) override;
@@ -64,7 +74,6 @@ public:
   void getAllDomains(vector<DomainInfo>* domains, bool getSerial, bool include_disabled) override;
 
   // dnssec support
-  bool doesDNSSEC() override { return d_dnssec; };
   bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta) override;
   bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override;
   bool getDomainKeys(const DNSName& name, std::vector<DNSBackend::KeyData>& keys) override;
index 830cae7c7e8610fae7cacebf56b4246b148a9680..77cab28fc299b91ad9b4fa0960ec7a5ceb5906d6 100644 (file)
@@ -170,6 +170,7 @@ public:
   ~LdapBackend() override;
 
   // Native backend
+  unsigned int getCapabilities() override { return CAP_LIST; }
   bool list(const DNSName& target, int domain_id, bool include_disabled = false) override;
   void lookup(const QType& qtype, const DNSName& qdomain, int zoneid, DNSPacket* p = nullptr) override;
   bool get(DNSResourceRecord& rr) override;
index 523f24871186d3ac081d181ce209d4c997507320..40c046b32ab9ba288638e5301d4a28a5c1773926 100644 (file)
@@ -62,6 +62,7 @@ public:
   explicit LMDBBackend(const string& suffix = "");
   ~LMDBBackend();
 
+  unsigned int getCapabilities() override { return CAP_DNSSEC | CAP_DIRECT | CAP_LIST; }
   bool list(const DNSName& target, int id, bool include_disabled) override;
 
   bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getserial = true) override;
@@ -143,11 +144,6 @@ public:
 
   bool updateEmptyNonTerminals(uint32_t domain_id, set<DNSName>& insert, set<DNSName>& erase, bool remove) override;
 
-  bool doesDNSSEC() override
-  {
-    return true;
-  }
-
   // other
   string directBackendCmd(const string& query) override;
 
index ba744da99a20f1f8dec6378decdae7a03e673143..02727689030fa5066aca70c3224c28cfdb456d9f 100644 (file)
@@ -129,9 +129,14 @@ public:
     }
   }
 
-  bool doesDNSSEC() override
+  unsigned int getCapabilities() override
   {
-    return d_dnssec;
+    if (d_dnssec) {
+      return CAP_DNSSEC | CAP_DIRECT | CAP_LIST;
+    }
+    else {
+      return CAP_DIRECT | CAP_LIST;
+    }
   }
 
   void parseLookup(const lookup_result_t& result)
index 776533a5a2bc686468f3d16cabcbbea02ca9c3cd..64b4b3477e08fe420a12d84c89d056d5f8e0fff5 100644 (file)
@@ -50,6 +50,8 @@ class PipeBackend : public DNSBackend
 public:
   PipeBackend(const string& suffix = "");
   ~PipeBackend() override;
+
+  unsigned int getCapabilities() override { return CAP_DIRECT | CAP_LIST; }
   void lookup(const QType&, const DNSName& qdomain, int zoneId, DNSPacket* p = nullptr) override;
   bool list(const DNSName& target, int domain_id, bool include_disabled = false) override;
   bool get(DNSResourceRecord& r) override;
index d4d68c97bf5b11218dcdd8fd0494b9cf4d43047d..1639c237d83cea85d9bce93a5989dd84e2cded1e 100644 (file)
@@ -506,9 +506,12 @@ bool RemoteBackend::unpublishDomainKey(const DNSName& name, unsigned int id)
   return this->send(query) && this->recv(answer);
 }
 
-bool RemoteBackend::doesDNSSEC()
+unsigned int RemoteBackend::getCapabilities()
 {
-  return d_dnssec;
+  if (d_dnssec) {
+    return CAP_DNSSEC | CAP_DIRECT | CAP_LIST;
+  }
+  return CAP_DIRECT | CAP_LIST;
 }
 
 bool RemoteBackend::getTSIGKey(const DNSName& name, DNSName& algorithm, std::string& content)
index 69c80b102011bb3447064f0eec9e59c9707a320f..0949150872339f05834a61bf550fb0bbe5c5eb90 100644 (file)
@@ -167,6 +167,7 @@ public:
   RemoteBackend(const std::string& suffix = "");
   ~RemoteBackend() override;
 
+  unsigned int getCapabilities() override;
   void lookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr) override;
   bool get(DNSResourceRecord& rr) override;
   bool list(const DNSName& target, int domain_id, bool include_disabled = false) override;
@@ -185,7 +186,6 @@ public:
   bool unpublishDomainKey(const DNSName& name, unsigned int id) override;
   bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getSerial = true) override;
   void setNotified(uint32_t id, uint32_t serial) override;
-  bool doesDNSSEC() override;
   bool autoPrimaryBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** ddb) override;
   bool createSecondaryDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
   bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset) override;
index 26bce0784f8bb43df6da4f3071d1f2ac35229a57..d227f51bd52eb438b15f6c52925d9ebe69089e16 100644 (file)
@@ -67,6 +67,8 @@ class TinyDNSBackend : public DNSBackend
 public:
   // Methods for simple operation
   TinyDNSBackend(const string& suffix);
+
+  unsigned int getCapabilities() override { return CAP_LIST; }
   void lookup(const QType& qtype, const DNSName& qdomain, int zoneId, DNSPacket* pkt_p = nullptr) override;
   bool list(const DNSName& target, int domain_id, bool include_disabled = false) override;
   bool get(DNSResourceRecord& rr) override;
index 80668e61c54c1d67d42585d204a94b99ededdfc4..d943cf7c4a1e20c8176a3c9f66cf6190c95b251f 100644 (file)
@@ -866,9 +866,12 @@ bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id, set<DNSName>& inse
   return true;
 }
 
-bool GSQLBackend::doesDNSSEC()
+unsigned int GSQLBackend::getCapabilities()
 {
-    return d_dnssecQueries;
+  if (d_dnssecQueries) {
+    return CAP_DNSSEC | CAP_COMMENTS | CAP_DIRECT | CAP_LIST;
+  }
+  return CAP_COMMENTS | CAP_DIRECT | CAP_LIST;
 }
 
 bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after)
index e54e5b2a3bbcc38fcfcc137a03f13029a592bb3e..f0633d4da012b8eb3eac0c9f81670cfc40457408 100644 (file)
@@ -194,6 +194,7 @@ protected:
   }
 
 public:
+  unsigned int getCapabilities() override;
   void lookup(const QType &, const DNSName &qdomain, int zoneId, DNSPacket *p=nullptr) override;
   bool list(const DNSName &target, int domain_id, bool include_disabled=false) override;
   bool get(DNSResourceRecord &r) override;
@@ -228,7 +229,6 @@ public:
   bool updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t=QType::ANY) override;
 
   bool updateEmptyNonTerminals(uint32_t domain_id, set<DNSName>& insert ,set<DNSName>& erase, bool remove) override;
-  bool doesDNSSEC() override;
 
   bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset) override;
   bool listSubZone(const DNSName &zone, int domain_id) override;
index 496b80ec5826f3f27b1d7cbb1d725a29ea9030e9..ed7b0c491e3f077180a9cf59f891a685574cabff 100644 (file)
@@ -156,6 +156,16 @@ class DNSPacket;
 class DNSBackend
 {
 public:
+  enum Capabilities : unsigned int
+  {
+    CAP_DNSSEC = 1 << 0, // Backend supports DNSSEC
+    CAP_COMMENTS = 1 << 1, // Backend supports comments
+    CAP_DIRECT = 1 << 2, // Backend supports direct commands
+    CAP_LIST = 1 << 3, // Backend supports record enumeration
+  };
+
+  virtual unsigned int getCapabilities() = 0;
+
   //! lookup() initiates a lookup. A lookup without results should not throw!
   virtual void lookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr) = 0;
   virtual bool get(DNSResourceRecord&) = 0; //!< retrieves one DNSResource record, returns false if no more were available
@@ -255,9 +265,9 @@ public:
     return false;
   }
 
-  virtual bool doesDNSSEC()
+  bool doesDNSSEC()
   {
-    return false;
+    return (getCapabilities() & CAP_DNSSEC) != 0;
   }
 
   // end DNSSEC
index 5fc7d0d48ab9a74260b31baa2ccb215da0ab4d88..2627e58f3066f89f233afd54189d274b202378d3 100644 (file)
@@ -107,6 +107,8 @@ public:
   {
   }
 
+  unsigned int getCapabilities() override { return CAP_LIST; }
+
   bool findZone(const DNSName& qdomain, int zoneId, std::shared_ptr<RecordStorage>& records, uint64_t& currentZoneId) const
   {
     currentZoneId = -1;