From: Remi Gacogne Date: Tue, 6 Feb 2024 14:44:35 +0000 (+0100) Subject: dnsdist: Add a Lua maintenance hook X-Git-Tag: dnsdist-1.9.0~9^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5798dc9b0b22c068f93633b638435a3c930a6505;p=thirdparty%2Fpdns.git dnsdist: Add a Lua maintenance hook Having a hook that can accept multiple callbacks makes it a lot easier to manage the execution of several, independant tasks that needs to be called regularly. --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index 0f9e085735..704db5d362 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -491,6 +491,7 @@ const std::vector g_consoleKeywords{ { "addLocal", true, R"(addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface="", cpus={}}])", "add `addr` to the list of addresses we listen on" }, { "addCacheHitResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a cache hit response rule" }, { "addCacheInsertedResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a cache inserted response rule" }, + { "addMaintenanceCallback", true, "callback", "register a function to be called as part of the maintenance hook, every second" }, { "addResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a response rule" }, { "addSelfAnsweredResponseAction", true, R"(DNS rule, DNS response action [, {uuid="UUID", name="name"}}])", "add a self-answered response rule" }, { "addTLSLocal", true, "addr, certFile(s), keyFile(s) [,params]", "listen to incoming DNS over TLS queries on the specified address using the specified certificate (or list of) and key (or list of). The last parameter is a table" }, diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 50112a3730..b241742675 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -46,6 +46,7 @@ #include "dnsdist-ecs.hh" #include "dnsdist-healthchecks.hh" #include "dnsdist-lua.hh" +#include "dnsdist-lua-hooks.hh" #include "xsk.hh" #ifdef LUAJIT_VERSION #include "dnsdist-lua-ffi.hh" @@ -3405,6 +3406,7 @@ vector> setupLua(LuaContext& luaCtx, bool client, bool setupLuaBindingsPacketCache(luaCtx, client); setupLuaBindingsProtoBuf(luaCtx, client, configCheck); setupLuaBindingsRings(luaCtx, client); + dnsdist::lua::hooks::setupLuaHooks(luaCtx); setupLuaInspection(luaCtx); setupLuaRules(luaCtx); setupLuaVars(luaCtx); diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index d83066e954..086765d182 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -61,6 +61,7 @@ #include "dnsdist-edns.hh" #include "dnsdist-healthchecks.hh" #include "dnsdist-lua.hh" +#include "dnsdist-lua-hooks.hh" #include "dnsdist-nghttp2.hh" #include "dnsdist-proxy-protocol.hh" #include "dnsdist-random.hh" @@ -2236,19 +2237,20 @@ static void maintThread() { auto lua = g_lua.lock(); - auto f = lua->readVariable > >("maintenance"); - if (f) { - try { + try { + auto f = lua->readVariable > >("maintenance"); + if (f) { (*f)(); - secondsToWaitLog = 0; } - catch (const std::exception &e) { - if (secondsToWaitLog <= 0) { - warnlog("Error during execution of maintenance function: %s", e.what()); - secondsToWaitLog = 61; - } - secondsToWaitLog -= interval; + dnsdist::lua::hooks::runMaintenanceHook(*lua); + secondsToWaitLog = 0; + } + catch (const std::exception &e) { + if (secondsToWaitLog <= 0) { + warnlog("Error during execution of maintenance function(s): %s", e.what()); + secondsToWaitLog = 61; } + secondsToWaitLog -= interval; } } diff --git a/pdns/dnsdistdist/Makefile.am b/pdns/dnsdistdist/Makefile.am index 60e76e0ff8..68ab167dcf 100644 --- a/pdns/dnsdistdist/Makefile.am +++ b/pdns/dnsdistdist/Makefile.am @@ -178,6 +178,7 @@ dnsdist_SOURCES = \ dnsdist-lua-bindings.cc \ dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \ dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh \ + dnsdist-lua-hooks.cc dnsdist-lua-hooks.hh \ dnsdist-lua-inspection-ffi.cc dnsdist-lua-inspection-ffi.h \ dnsdist-lua-inspection.cc \ dnsdist-lua-network.cc dnsdist-lua-network.hh \ diff --git a/pdns/dnsdistdist/dnsdist-lua-hooks.cc b/pdns/dnsdistdist/dnsdist-lua-hooks.cc new file mode 100644 index 0000000000..2b1814a4c5 --- /dev/null +++ b/pdns/dnsdistdist/dnsdist-lua-hooks.cc @@ -0,0 +1,32 @@ + +#include "dnsdist-lua-hooks.hh" +#include "dnsdist-lua.hh" +#include "lock.hh" + +namespace dnsdist::lua::hooks +{ +static LockGuarded> s_maintenanceHook; + +void runMaintenanceHook(const LuaContext& context) +{ + (void)context; + for (const auto& callback : *(s_maintenanceHook.lock())) { + callback(); + } +} + +void addMaintenanceCallback(const LuaContext& context, MaintenanceCallback callback) +{ + (void)context; + s_maintenanceHook.lock()->push_back(std::move(callback)); +} + +void setupLuaHooks(LuaContext& luaCtx) +{ + luaCtx.writeFunction("addMaintenanceCallback", [&luaCtx](const MaintenanceCallback& callback) { + setLuaSideEffect(); + addMaintenanceCallback(luaCtx, callback); + }); +} + +} diff --git a/pdns/dnsdistdist/dnsdist-lua-hooks.hh b/pdns/dnsdistdist/dnsdist-lua-hooks.hh new file mode 100644 index 0000000000..573ab95b89 --- /dev/null +++ b/pdns/dnsdistdist/dnsdist-lua-hooks.hh @@ -0,0 +1,34 @@ +/* + * This file is part of PowerDNS or dnsdist. + * Copyright -- PowerDNS.COM B.V. and its contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * In addition, for the avoidance of any doubt, permission is granted to + * link this program with OpenSSL and to (re)distribute the binaries + * produced as the result of such linking. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#pragma once + +#include + +class LuaContext; + +namespace dnsdist::lua::hooks +{ +using MaintenanceCallback = std::function; +void runMaintenanceHook(const LuaContext& context); +void addMaintenanceCallback(MaintenanceCallback callback); +void setupLuaHooks(LuaContext& luaCtx); +} diff --git a/pdns/dnsdistdist/docs/reference/config.rst b/pdns/dnsdistdist/docs/reference/config.rst index b3e2f5c2db..a252a5e150 100644 --- a/pdns/dnsdistdist/docs/reference/config.rst +++ b/pdns/dnsdistdist/docs/reference/config.rst @@ -1982,6 +1982,23 @@ These values can be set at configuration time via: Other functions --------------- +.. function:: addMaintenanceCallback(callback) + + .. versionadded:: 1.10.0 + + Register a Lua function to be called as part of the ``maintenance`` hook, which is executed roughly every second. + The function should not block for a long period of time, as it would otherwise delay the execution of the other functions registered for this hook, as well as the execution of the :func:`maintenance` function. + + :param function callback: The function to be called. It takes no parameter and returns no value. + + .. code-block:: lua + + function myCallback(hostname, ips) + print('called') + end + addMaintenanceCallback(myCallback) + + .. function:: getAddressInfo(hostname, callback) .. versionadded:: 1.9.0 @@ -2026,6 +2043,7 @@ Other functions If this function exists, it is called every second to do regular tasks. This can be used for e.g. :doc:`Dynamic Blocks <../guides/dynblocks>`. + See also :func:`addMaintenanceCallback`. .. function:: threadmessage(cmd, dict) diff --git a/regression-tests.dnsdist/test_DNSCrypt.py b/regression-tests.dnsdist/test_DNSCrypt.py index 6f8df586ec..c5e150e8d9 100644 --- a/regression-tests.dnsdist/test_DNSCrypt.py +++ b/regression-tests.dnsdist/test_DNSCrypt.py @@ -332,7 +332,7 @@ class TestDNSCryptAutomaticRotation(DNSCryptTest): local last = 0 serial = %d - function maintenance() + function reloadCallback() local now = os.time() if ((now - last) > 2) then serial = serial + 1 @@ -340,6 +340,7 @@ class TestDNSCryptAutomaticRotation(DNSCryptTest): last = now end end + addMaintenanceCallback(reloadCallback) """ _config_params = ['_consoleKeyB64', '_consolePort', '_resolverCertificateSerial', '_resolverCertificateValidFrom', '_resolverCertificateValidUntil', '_dnsDistPortDNSCrypt', '_providerName', '_testServerPort', '_resolverCertificateSerial']