]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
auth LUA: new dblookup() function
authorPeter van Dijk <peter.van.dijk@powerdns.com>
Fri, 23 Dec 2022 11:07:47 +0000 (12:07 +0100)
committerPeter van Dijk <peter.van.dijk@powerdns.com>
Tue, 23 Jan 2024 12:48:12 +0000 (13:48 +0100)
.github/actions/spell-check/expect.txt
docs/lua-records/functions.rst
pdns/lua-record.cc
regression-tests.auth-py/test_LuaRecords.py

index 0465e6d06b0d3e839cc83c25edcd0dd276467478..5a1b4066e0f7d5c40358c078a7bfa2b0787431cb 100644 (file)
@@ -257,6 +257,7 @@ Davids
 Dayneko
 dbfile
 dblfilename
+dblookup
 dbpf
 dbr
 dcobject
index 6902d761ad2c2e8c2782301f04894f96091228f9..7c6a22fec8b40c9f90780875148eb89a19871f4e 100644 (file)
@@ -454,3 +454,20 @@ Helper functions
   Returns true if ``bestwho`` is within any of the listed subnets.
 
   :param [string] netmasks: The list of IP addresses to check against
+
+.. function:: dblookup(name, type)
+
+  Does a database lookup for name and type, and returns a (possibly empty) array of string results.
+
+  Please keep the following in mind:
+
+  * it does not evaluate any LUA code found
+  * if you needed just one string, perhaps you want ``dblookup('www.example.org', 'A')[1]`` to take the first item from the array
+  * some things, like ifurlup, don't like empty tables, so be careful not to accidentally look up a name that does not have any records of that type, if you are going to use the result in ``ifurlup``
+
+  Example usage: ::
+
+    www IN LUA A "ifurlup('https://www.example.com/', {dblookup('www1.example.com', 'A'), dblookup('www2.example.com', 'A'), dblookup('www3.example.com', 'A')})"
+
+  :param string name: Name to look up in the database
+  :param string type: DNS type to look for
index a9786ad950a176f49e5a85ee3dcd6e77fe04ded1..920c0ccf4ce4538216f582deb5eee9217ad821da 100644 (file)
@@ -4,6 +4,7 @@
 #include <utility>
 #include <algorithm>
 #include <random>
+#include "qtype.hh"
 #include "version.hh"
 #include "ext/luawrapper/include/LuaContext.hpp"
 #include "lock.hh"
@@ -503,6 +504,17 @@ static std::vector<DNSZoneRecord> lookup(const DNSName& name, uint16_t qtype, in
   return ret;
 }
 
+static bool getAuth(const DNSName& name, uint16_t qtype, SOAData* soaData)
+{
+  static LockGuarded<UeberBackend> s_ub;
+
+  vector<DNSZoneRecord> ret;
+  {
+    auto ueback = s_ub.lock();
+    return ueback->getAuth(name, qtype, soaData);
+  }
+}
+
 static std::string getOptionValue(const boost::optional<std::unordered_map<string, string>>& options, const std::string &name, const std::string &defaultValue)
 {
   string selector=defaultValue;
@@ -1103,6 +1115,36 @@ static void setupLuaRecords(LuaContext& lua)
       return result;
     });
 
+  lua.writeFunction("dblookup", [](const string& record, const string& type) {
+    DNSName rec;
+    QType qtype;
+    vector<string> ret;
+    try {
+      rec = DNSName(record);
+      qtype = type;
+    }
+    catch (const std::exception& e) {
+      g_log << Logger::Error << "DB lookup cannot be performed, the name (" << record << ") or type (" << type << ") is malformed: " << e.what() << endl;
+      return ret;
+    }
+    try {
+      SOAData soaData;
+
+      if (!getAuth(rec, qtype, &soaData)) {
+        return ret;
+      }
+
+      vector<DNSZoneRecord> drs = lookup(rec, qtype, soaData.domain_id);
+      for (const auto& drec : drs) {
+        ret.push_back(drec.dr.getContent()->getZoneRepresentation());
+      }
+    }
+    catch (std::exception& e) {
+      g_log << Logger::Error << "Failed to do DB lookup for " << rec << "/" << type << ": " << e.what() << endl;
+    }
+    return ret;
+  });
+
   lua.writeFunction("include", [&lua](string record) {
       DNSName rec;
       try {
index e9df7c8ba7f4ffb0798c27f9cff2c9c11f25642e..0d6a3d725f4254cbb5350255c9821d5be70fe2bf 100644 (file)
@@ -149,6 +149,9 @@ newcafromraw     IN    LUA    A    "newCAFromRaw('ABCD'):toString()"
 newcafromraw     IN    LUA    AAAA "newCAFromRaw('ABCD020340506070'):toString()"
 
 counter          IN    LUA    TXT  ";counter = counter or 0 counter=counter+1 return tostring(counter)"
+
+lookmeup         IN           A  192.0.2.5
+dblookup         IN    LUA    A  "dblookup('lookmeup.example.org', 'A')[1]"
         """,
         'createforward6.example.org': """
 createforward6.example.org.                 3600 IN SOA  {soa}
@@ -1025,6 +1028,24 @@ createforward6.example.org.                 3600 IN NS   ns2.example.org.
         self.assertEqual(len(resUDP), 1)
         self.assertEqual(len(resTCP), 1)
 
+    def testDblookup(self):
+        """
+        Test dblookup() function
+        """
+
+        name = 'dblookup.example.org.'
+
+        query = dns.message.make_query(name, 'A')
+
+        response = dns.message.make_response(query)
+
+        response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.5'))
+
+        res = self.sendUDPQuery(query)
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertEqual(self.sortRRsets(res.answer), self.sortRRsets(response.answer))
+
+
 class TestLuaRecordsShared(TestLuaRecords):
     _config_template = """
 geoip-database-files=../modules/geoipbackend/regression-tests/GeoLiteCity.mmdb