From: Miod Vallat Date: Thu, 17 Jul 2025 15:24:42 +0000 (+0200) Subject: Provide a default searchRecords implementation. X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=549a0869dfc53ed2a78163b62d06894cd5a47493;p=thirdparty%2Fpdns.git Provide a default searchRecords implementation. This is the LMDB searchRecords being promoted to backend-agnostic, as it only depends on list() and getAllDomains() to work (and get(), obviously). A new capability, CAP_SEARCH, is added to advertize these requirements are fulfilled; search will return failure if they are not. Signed-off-by: Miod Vallat --- diff --git a/docs/backends/lua2.rst b/docs/backends/lua2.rst index eec138431f..99dba66bba 100644 --- a/docs/backends/lua2.rst +++ b/docs/backends/lua2.rst @@ -11,7 +11,7 @@ Lua2 Backend * DNSSEC: Yes * Disabled data: No * Comments: No -* Search: No +* Search: Yes\* * Views: No * API: Read-Write * Multiple instances: Yes @@ -123,7 +123,8 @@ OUTPUT: domaininfo. See :ref:`dns_get_domaininfo() `. NOTES: - This function is **optional**, except if you need primary functionality. + This function is **optional**, except if you need primary functionality. It + is required if you want to be able to search records. ``dns_get_domain_metadata(domain, kind)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/backends/tinydns.rst b/docs/backends/tinydns.rst index 933d58855c..ba56c2c0df 100644 --- a/docs/backends/tinydns.rst +++ b/docs/backends/tinydns.rst @@ -11,7 +11,7 @@ TinyDNS Backend * DNSSEC: No * Disabled data: No * Comments: No -* Search: No +* Search: since version 5.1.0 * Views: No * API: Read-only * Multiple Instances: Yes diff --git a/modules/bindbackend/binddnssec.cc b/modules/bindbackend/binddnssec.cc index 20f00691cd..ee06af285b 100644 --- a/modules/bindbackend/binddnssec.cc +++ b/modules/bindbackend/binddnssec.cc @@ -38,7 +38,7 @@ void Bind2Backend::setupDNSSEC() unsigned int Bind2Backend::getCapabilities() { - unsigned int caps = CAP_LIST; + unsigned int caps = CAP_LIST | CAP_SEARCH; if (d_hybrid) { caps |= CAP_DNSSEC; } @@ -203,7 +203,7 @@ void Bind2Backend::freeStatements() unsigned int Bind2Backend::getCapabilities() { - unsigned int caps = CAP_LIST; + unsigned int caps = CAP_LIST | CAP_SEARCH; if (d_dnssecdb || d_hybrid) { caps |= CAP_DNSSEC; } diff --git a/modules/lmdbbackend/lmdbbackend.cc b/modules/lmdbbackend/lmdbbackend.cc index 7da2de0b0e..376433c429 100644 --- a/modules/lmdbbackend/lmdbbackend.cc +++ b/modules/lmdbbackend/lmdbbackend.cc @@ -846,7 +846,7 @@ void LMDBBackend::openAllTheDatabases() unsigned int LMDBBackend::getCapabilities() { - unsigned int caps = CAP_DNSSEC | CAP_DIRECT | CAP_LIST | CAP_CREATE; + unsigned int caps = CAP_DNSSEC | CAP_DIRECT | CAP_LIST | CAP_CREATE | CAP_SEARCH; if (d_views) { caps |= CAP_VIEWS; } @@ -1426,32 +1426,6 @@ bool LMDBBackend::replaceComments([[maybe_unused]] domainid_t domain_id, [[maybe return comments.empty(); } -bool LMDBBackend::searchRecords(const string& pattern, size_t maxResults, vector& result) -{ - SimpleMatch simpleMatch(pattern, true); - std::vector domains; - getAllDomains(&domains, false, true); - for (const auto& info : domains) { - if (!list(info.zone, info.id, true)) { - return false; - } - DNSResourceRecord rec; - while (get(rec)) { - if (maxResults == 0) { - continue; - } - if (simpleMatch.match(rec.qname.toStringNoDot()) || simpleMatch.match(rec.content)) { - result.emplace_back(rec); - --maxResults; - } - } - if (maxResults == 0) { - break; - } - } - return true; -} - // FIXME: this is not very efficient static DNSName keyUnconv(std::string& instr) { diff --git a/modules/lmdbbackend/lmdbbackend.hh b/modules/lmdbbackend/lmdbbackend.hh index 3665533a0a..7d4260033e 100644 --- a/modules/lmdbbackend/lmdbbackend.hh +++ b/modules/lmdbbackend/lmdbbackend.hh @@ -88,7 +88,6 @@ public: bool feedEnts3(domainid_t domain_id, const DNSName& domain, map& nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) override; bool replaceRRSet(domainid_t domain_id, const DNSName& qname, const QType& qt, const vector& rrset) override; bool replaceComments(domainid_t domain_id, const DNSName& qname, const QType& qt, const vector& comments) override; - bool searchRecords(const string& pattern, size_t maxResults, vector& result) override; void viewList(vector& /* result */) override; void viewListZones(const string& /* view */, vector& /* result */) override; diff --git a/modules/lua2backend/lua2api2.hh b/modules/lua2backend/lua2api2.hh index 660f117b8a..7e31f0d066 100644 --- a/modules/lua2backend/lua2api2.hh +++ b/modules/lua2backend/lua2api2.hh @@ -135,6 +135,9 @@ public: if (d_dnssec) { caps |= CAP_DNSSEC; } + if (f_get_all_domains != nullptr) { + caps |= CAP_SEARCH; + } return caps; } diff --git a/modules/remotebackend/remotebackend.cc b/modules/remotebackend/remotebackend.cc index 8493973110..6e11267a48 100644 --- a/modules/remotebackend/remotebackend.cc +++ b/modules/remotebackend/remotebackend.cc @@ -544,7 +544,7 @@ bool RemoteBackend::unpublishDomainKey(const ZoneName& name, unsigned int keyId) unsigned int RemoteBackend::getCapabilities() { - unsigned int caps = CAP_DIRECT | CAP_LIST; + unsigned int caps = CAP_DIRECT | CAP_LIST | CAP_SEARCH; if (d_dnssec) { caps |= CAP_DNSSEC; } diff --git a/modules/tinydnsbackend/tinydnsbackend.hh b/modules/tinydnsbackend/tinydnsbackend.hh index d2fe0789ea..c7b9cff4e1 100644 --- a/modules/tinydnsbackend/tinydnsbackend.hh +++ b/modules/tinydnsbackend/tinydnsbackend.hh @@ -68,7 +68,7 @@ public: // Methods for simple operation TinyDNSBackend(const string& suffix); - unsigned int getCapabilities() override { return CAP_LIST; } + unsigned int getCapabilities() override { return CAP_LIST | CAP_SEARCH; } void lookup(const QType& qtype, const DNSName& qdomain, domainid_t zoneId, DNSPacket* pkt_p = nullptr) override; bool list(const ZoneName& target, domainid_t domain_id, bool include_disabled = false) override; bool get(DNSResourceRecord& rr) override; diff --git a/pdns/backends/gsql/gsqlbackend.cc b/pdns/backends/gsql/gsqlbackend.cc index 24cebbb6b1..0d7160487d 100644 --- a/pdns/backends/gsql/gsqlbackend.cc +++ b/pdns/backends/gsql/gsqlbackend.cc @@ -874,7 +874,7 @@ bool GSQLBackend::updateEmptyNonTerminals(domainid_t domain_id, set& in unsigned int GSQLBackend::getCapabilities() { - unsigned int caps = CAP_COMMENTS | CAP_DIRECT | CAP_LIST | CAP_CREATE; + unsigned int caps = CAP_COMMENTS | CAP_DIRECT | CAP_LIST | CAP_CREATE | CAP_SEARCH; if (d_dnssecQueries) { caps |= CAP_DNSSEC; } diff --git a/pdns/dnsbackend.cc b/pdns/dnsbackend.cc index 90901e91a8..8e1d436eac 100644 --- a/pdns/dnsbackend.cc +++ b/pdns/dnsbackend.cc @@ -73,6 +73,40 @@ void DNSBackend::APILookup(const QType& qtype, const DNSName& qdomain, domainid_ lookup(qtype, qdomain, zoneId, nullptr); } +// Default search logic, for backends which can enumerate their records. +bool DNSBackend::searchRecords(const string& pattern, size_t maxResults, vector& result) +{ + // We depend upon working list(), but also getAllDomains(), which is why we + // are checking explicitly for CAP_SEARCH in addition to CAP_LIST - the + // default getAllDomains() implementation below is not safe to use here. + if ((getCapabilities() & (CAP_LIST | CAP_SEARCH)) != (CAP_LIST | CAP_SEARCH)) { + return false; + } + + SimpleMatch simpleMatch(pattern, true); + std::vector domains; + getAllDomains(&domains, false, true); + for (const auto& info : domains) { + if (!list(info.zone, info.id, true)) { + return false; + } + DNSResourceRecord rec; + while (get(rec)) { + if (maxResults == 0) { + continue; + } + if (simpleMatch.match(rec.qname) || simpleMatch.match(rec.content)) { + result.emplace_back(rec); + --maxResults; + } + } + if (maxResults == 0) { + break; + } + } + return true; +} + void BackendFactory::declare(const string& suffix, const string& param, const string& explanation, const string& value) { string fullname = d_name + suffix + "-" + param; diff --git a/pdns/dnsbackend.hh b/pdns/dnsbackend.hh index f87391e63c..ec1532c30e 100644 --- a/pdns/dnsbackend.hh +++ b/pdns/dnsbackend.hh @@ -164,6 +164,7 @@ public: CAP_LIST = 1 << 3, // Backend supports record enumeration CAP_CREATE = 1 << 4, // Backend supports domain creation CAP_VIEWS = 1 << 5, // Backend supports views + CAP_SEARCH = 1 << 6, // Backend supports record search }; virtual unsigned int getCapabilities() = 0; @@ -468,10 +469,7 @@ public: } //! Search for records, returns true if search was done successfully. - virtual bool searchRecords(const string& /* pattern */, size_t /* maxResults */, vector& /* result */) - { - return false; - } + virtual bool searchRecords(const string& pattern, size_t maxResults, vector& result); //! Search for comments, returns true if search was done successfully. virtual bool searchComments(const string& /* pattern */, size_t /* maxResults */, vector& /* result */)