From: Remi Gacogne Date: Wed, 29 Jan 2020 16:59:02 +0000 (+0100) Subject: dnsdist: Add LuaRule(), the non-FFI equivalent of LuaFFIRule() X-Git-Tag: auth-4.3.0-beta2~1^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8eb84a561de9b238679007af83656f3c87c5f072;p=thirdparty%2Fpdns.git dnsdist: Add LuaRule(), the non-FFI equivalent of LuaFFIRule() --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index 61193e7432..6c0dc6b796 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -428,6 +428,7 @@ const std::vector 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" }, diff --git a/pdns/dnsdist-lua-rules.cc b/pdns/dnsdist-lua-rules.cc index d49b819a46..c33af0d7f1 100644 --- a/pdns/dnsdist-lua-rules.cc +++ b/pdns/dnsdist-lua-rules.cc @@ -487,6 +487,10 @@ void setupLuaRules() return std::shared_ptr(new KeyValueStoreLookupRule(kvs, lookupKey)); }); + g_lua.writeFunction("LuaRule", [](LuaRule::func_t func) { + return std::shared_ptr(new LuaRule(func)); + }); + g_lua.writeFunction("LuaFFIRule", [](LuaFFIRule::func_t func) { return std::shared_ptr(new LuaFFIRule(func)); }); diff --git a/pdns/dnsdistdist/dnsdist-rules.hh b/pdns/dnsdistdist/dnsdist-rules.hh index 0d0f872745..0474a1e150 100644 --- a/pdns/dnsdistdist/dnsdist-rules.hh +++ b/pdns/dnsdistdist/dnsdist-rules.hh @@ -1127,6 +1127,34 @@ private: std::shared_ptr d_key; }; +class LuaRule : public DNSRule +{ +public: + typedef std::function func_t; + LuaRule(const func_t& func): d_func(func) + {} + + bool matches(const DNSQuestion* dq) const override + { + try { + std::lock_guard 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 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; diff --git a/pdns/dnsdistdist/docs/rules-actions.rst b/pdns/dnsdistdist/docs/rules-actions.rst index b59b6542bc..13e4ac7b8d 100644 --- a/pdns/dnsdistdist/docs/rules-actions.rst +++ b/pdns/dnsdistdist/docs/rules-actions.rst @@ -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 diff --git a/regression-tests.dnsdist/test_Advanced.py b/regression-tests.dnsdist/test_Advanced.py index f0fb92bdce..e1b9f21aa1 100644 --- a/regression-tests.dnsdist/test_Advanced.py +++ b/regression-tests.dnsdist/test_Advanced.py @@ -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)