]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add LuaRule(), the non-FFI equivalent of LuaFFIRule()
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 29 Jan 2020 16:59:02 +0000 (17:59 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 11 Feb 2020 10:55:40 +0000 (11:55 +0100)
pdns/dnsdist-console.cc
pdns/dnsdist-lua-rules.cc
pdns/dnsdistdist/dnsdist-rules.hh
pdns/dnsdistdist/docs/rules-actions.rst
regression-tests.dnsdist/test_Advanced.py

index 61193e7432e842bbdfb58e62c3f8a4742f3eaad6..6c0dc6b7963ad2a1b6a7d15979f9df9f23d4b59d 100644 (file)
@@ -428,6 +428,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "LuaFFIResponseAction", true, "function", "Invoke a Lua FFI function that accepts a DNSResponse" },
   { "LuaFFIRule", true, "function", "Invoke a Lua FFI function that filters DNS questions" },
   { "LuaResponseAction", true, "function", "Invoke a Lua function that accepts a DNSResponse" },
+  { "LuaRule", true, "function", "Invoke a Lua function that filters DNS questions" },
   { "MacAddrAction", true, "option", "Add the source MAC address to the query as EDNS0 option option. This action is currently only supported on Linux. Subsequent rules are processed after this action" },
   { "makeIPCipherKey", true, "password", "generates a 16-byte key that can be used to pseudonymize IP addresses with IP cipher" },
   { "makeKey", true, "", "generate a new server access key, emit configuration line ready for pasting" },
index d49b819a46a75b4d5ca142a3238935691b1c267e..c33af0d7f166f6307de838b5f9b72f223f13d530 100644 (file)
@@ -487,6 +487,10 @@ void setupLuaRules()
       return std::shared_ptr<DNSRule>(new KeyValueStoreLookupRule(kvs, lookupKey));
     });
 
+  g_lua.writeFunction("LuaRule", [](LuaRule::func_t func) {
+      return std::shared_ptr<DNSRule>(new LuaRule(func));
+    });
+
   g_lua.writeFunction("LuaFFIRule", [](LuaFFIRule::func_t func) {
       return std::shared_ptr<DNSRule>(new LuaFFIRule(func));
     });
index 0d0f8727451324515d95f99fcce7637c3507baea..0474a1e1504b8d3c9acee069d7ee8426b40141ee 100644 (file)
@@ -1127,6 +1127,34 @@ private:
   std::shared_ptr<KeyValueLookupKey> d_key;
 };
 
+class LuaRule : public DNSRule
+{
+public:
+  typedef std::function<bool(const DNSQuestion* dq)> func_t;
+  LuaRule(const func_t& func): d_func(func)
+  {}
+
+  bool matches(const DNSQuestion* dq) const override
+  {
+    try {
+      std::lock_guard<std::mutex> lock(g_luamutex);
+      return d_func(dq);
+    } catch (const std::exception &e) {
+      warnlog("LuaRule failed inside Lua: %s", e.what());
+    } catch (...) {
+      warnlog("LuaRule failed inside Lua: [unknown exception]");
+    }
+    return false;
+  }
+
+  string toString() const override
+  {
+    return "Lua script";
+  }
+private:
+  func_t d_func;
+};
+
 class LuaFFIRule : public DNSRule
 {
 public:
@@ -1141,16 +1169,16 @@ public:
       std::lock_guard<std::mutex> lock(g_luamutex);
       return d_func(&dqffi);
     } catch (const std::exception &e) {
-      warnlog("LuaRule failed inside Lua: %s", e.what());
+      warnlog("LuaFFIRule failed inside Lua: %s", e.what());
     } catch (...) {
-      warnlog("LuaRule failed inside Lua: [unknown exception]");
+      warnlog("LuaFFIRule failed inside Lua: [unknown exception]");
     }
     return false;
   }
 
   string toString() const override
   {
-    return "Lua script";
+    return "Lua FFI script";
   }
 private:
   func_t d_func;
index b59b6542bcc07bde7afd357bcc3e7cf24f8165ae..13e4ac7b8dc61b418b3ca911ec10b9310d2d1f1d 100644 (file)
@@ -626,6 +626,16 @@ These ``DNSRule``\ s be one of the following items:
 
   :param string function: the name of a Lua function
 
+.. function:: LuaRule(function)
+
+  .. versionadded:: 1.5.0
+
+  Invoke a Lua function that accepts a :class:`DNSQuestion` object.
+
+  The ``function`` should return true if the query matches, or false otherwise. If the Lua code fails, false is returned.
+
+  :param string function: the name of a Lua function
+
 .. function:: MaxQPSIPRule(qps[, v4Mask[, v6Mask[, burst[, expiration[, cleanupDelay[, scanFraction]]]]]])
 
   .. versionchanged:: 1.3.1
index f0fb92bdce50344c0309fa0a808c4c92ab3a5e9d..e1b9f21aa1062a195dce2c15999cb567a1510972 100644 (file)
@@ -1893,33 +1893,55 @@ class TestAdvancedSetNegativeAndSOA(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEquals(receivedResponse, expectedResponse)
 
+class TestAdvancedLuaRule(DNSDistTest):
+
+    _config_template = """
+
+    function luarulefunction(dq)
+      if dq.qname:toString() == 'lua-rule.advanced.tests.powerdns.com.' then
+        return true
+      end
+      return false
+    end
+
+    addAction(LuaRule(luarulefunction), RCodeAction(DNSRCode.NOTIMP))
+    addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
+    -- newServer{address="127.0.0.1:%s"}
+    """
+
+    def testAdvancedLuaRule(self):
+        """
+        Advanced: Test the LuaRule rule
+        """
+        name = 'lua-rule.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+        notimplResponse = dns.message.make_response(query)
+        notimplResponse.set_rcode(dns.rcode.NOTIMP)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.assertEquals(receivedResponse, notimplResponse)
+
+        name = 'not-lua-rule.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+        refusedResponse = dns.message.make_response(query)
+        refusedResponse.set_rcode(dns.rcode.REFUSED)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.assertEquals(receivedResponse, refusedResponse)
+
 class TestAdvancedLuaFFI(DNSDistTest):
 
     _config_template = """
     local ffi = require("ffi")
 
-    ffi.cdef[[
-  typedef struct dnsdist_ffi_dnsquestion_t dnsdist_ffi_dnsquestion_t;
-
-  void dnsdist_ffi_dnsquestion_get_localaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
-  void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
-  void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize) __attribute__ ((visibility ("default")));
-  uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  uint16_t dnsdist_ffi_dnsquestion_get_qclass(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-  const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t* dq, const char* label) __attribute__ ((visibility ("default")));
-
-  void dnsdist_ffi_dnsquestion_set_result(dnsdist_ffi_dnsquestion_t* dq, const char* str, size_t strSize) __attribute__ ((visibility ("default")));
-  void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode) __attribute__ ((visibility ("default")));
-  void dnsdist_ffi_dnsquestion_set_tag(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value) __attribute__ ((visibility ("default")));
-
-  ]]
     local expectingUDP = true
 
     function luaffirulefunction(dq)