From: Remi Gacogne Date: Tue, 4 Nov 2025 10:07:46 +0000 (+0100) Subject: dnsdist: Expose selectors and actions to YAML-originated Lua contexts X-Git-Tag: rec-5.4.0-alpha1~54^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=02e501211bf4f1c7811ee50ca676ec645297c3d9;p=thirdparty%2Fpdns.git dnsdist: Expose selectors and actions to YAML-originated Lua contexts Making it possible to use selectors and actions in Lua code declared in the YAML configuration (inline or not). Signed-off-by: Remi Gacogne --- diff --git a/pdns/dnsdistdist/dnsdist-lua-actions.cc b/pdns/dnsdistdist/dnsdist-lua-actions.cc index 506ad0bf9b..3a15cd2fe2 100644 --- a/pdns/dnsdistdist/dnsdist-lua-actions.cc +++ b/pdns/dnsdistdist/dnsdist-lua-actions.cc @@ -31,23 +31,6 @@ #include "remote_logger.hh" #include -template -static void addAction(IdentifierT identifier, const luadnsrule_t& var, const std::shared_ptr& action, boost::optional& params) -{ - setLuaSideEffect(); - - std::string name; - boost::uuids::uuid uuid{}; - uint64_t creationOrder = 0; - parseRuleParams(params, uuid, name, creationOrder); - checkAllParametersConsumed("addAction", params); - - auto rule = makeRule(var, "addAction"); - dnsdist::configuration::updateRuntimeConfiguration([identifier, &rule, &action, &name, &uuid, creationOrder](dnsdist::configuration::RuntimeConfiguration& config) { - dnsdist::rules::add(config.d_ruleChains, identifier, std::move(rule), action, std::move(name), uuid, creationOrder); - }); -} - using responseParams_t = std::unordered_map>; static dnsdist::ResponseConfig parseResponseConfig(boost::optional& vars) @@ -92,39 +75,6 @@ void setupLuaActions(LuaContext& luaCtx) return std::make_shared(ruleaction); }); - for (const auto& chain : dnsdist::rules::getRuleChainDescriptions()) { - auto fullName = std::string("add") + chain.prefix + std::string("Action"); - luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { - if (era.type() != typeid(std::shared_ptr)) { - throw std::runtime_error(fullName + "() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); - } - - addAction(chain.identifier, var, boost::get>(era), params); - }); - fullName = std::string("get") + chain.prefix + std::string("Action"); - luaCtx.writeFunction(fullName, [&chain](unsigned int num) { - setLuaNoSideEffect(); - boost::optional> ret; - const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains; - const auto& ruleactions = dnsdist::rules::getRuleChain(chains, chain.identifier); - if (num < ruleactions.size()) { - ret = ruleactions[num].d_action; - } - return ret; - }); - } - - for (const auto& chain : dnsdist::rules::getResponseRuleChainDescriptions()) { - const auto fullName = std::string("add") + chain.prefix + std::string("ResponseAction"); - luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { - if (era.type() != typeid(std::shared_ptr)) { - throw std::runtime_error(fullName + "() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); - } - - addAction(chain.identifier, var, boost::get>(era), params); - }); - } - luaCtx.registerFunction("printStats", [](const DNSAction& action) { setLuaNoSideEffect(); auto stats = action.getStats(); diff --git a/pdns/dnsdistdist/dnsdist-lua-rules.cc b/pdns/dnsdistdist/dnsdist-lua-rules.cc index a12eed23ea..0643311575 100644 --- a/pdns/dnsdistdist/dnsdist-lua-rules.cc +++ b/pdns/dnsdistdist/dnsdist-lua-rules.cc @@ -276,6 +276,23 @@ static std::vector getTopRules(const std::vector& rules, unsigned int top) return results; } +template +static void addRule(IdentifierT identifier, const std::string& methodName, const luadnsrule_t& var, const std::shared_ptr& action, boost::optional& params) +{ + setLuaSideEffect(); + + std::string name; + boost::uuids::uuid uuid{}; + uint64_t creationOrder = 0; + parseRuleParams(params, uuid, name, creationOrder); + checkAllParametersConsumed(methodName, params); + + auto rule = makeRule(var, methodName); + dnsdist::configuration::updateRuntimeConfiguration([identifier, &rule, &action, &name, &uuid, creationOrder](dnsdist::configuration::RuntimeConfiguration& config) { + dnsdist::rules::add(config.d_ruleChains, identifier, std::move(rule), action, std::move(name), uuid, creationOrder); + }); +} + template static LuaArray toLuaArray(std::vector&& rules) { @@ -350,25 +367,8 @@ std::optional boostToStandardOptional(const boost::optional& boostOpt) } } -// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold -void setupLuaRules(LuaContext& luaCtx) +void setupLuaRuleChainsManagement(LuaContext& luaCtx) { - luaCtx.writeFunction("makeRule", [](const luadnsrule_t& var) -> std::shared_ptr { - return makeRule(var, "makeRule"); - }); - - luaCtx.registerFunction::*)() const>("toString", [](const std::shared_ptr& rule) { return rule->toString(); }); - - luaCtx.registerFunction::*)() const>("getMatches", [](const std::shared_ptr& rule) { return rule->d_matches.load(); }); - - luaCtx.registerFunction (dnsdist::rules::RuleAction::*)() const>("getSelector", [](const dnsdist::rules::RuleAction& rule) { return rule.d_rule; }); - - luaCtx.registerFunction (dnsdist::rules::RuleAction::*)() const>("getAction", [](const dnsdist::rules::RuleAction& rule) { return rule.d_action; }); - - luaCtx.registerFunction (dnsdist::rules::ResponseRuleAction::*)() const>("getSelector", [](const dnsdist::rules::ResponseRuleAction& rule) { return rule.d_rule; }); - - luaCtx.registerFunction (dnsdist::rules::ResponseRuleAction::*)() const>("getAction", [](const dnsdist::rules::ResponseRuleAction& rule) { return rule.d_action; }); - for (const auto& chain : dnsdist::rules::getResponseRuleChainDescriptions()) { luaCtx.writeFunction("show" + chain.prefix + "ResponseRules", [&chain](boost::optional vars) { showRules(chain.identifier, vars); @@ -469,26 +469,38 @@ void setupLuaRules(LuaContext& luaCtx) }); } - luaCtx.writeFunction("SuffixMatchNodeRule", qnameSuffixRule); + for (const auto& chain : dnsdist::rules::getRuleChainDescriptions()) { + auto fullName = std::string("add") + chain.prefix + std::string("Action"); + luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error(fullName + "() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); + } - luaCtx.writeFunction("NetmaskGroupRule", [](const boost::variant> netmasks, boost::optional src, boost::optional quiet) { - if (netmasks.type() == typeid(string)) { - NetmaskGroup nmg; - nmg.addMask(*boost::get(&netmasks)); - return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); - } + addRule(chain.identifier, fullName, var, boost::get>(era), params); + }); + fullName = std::string("get") + chain.prefix + std::string("Action"); + luaCtx.writeFunction(fullName, [&chain](unsigned int num) { + setLuaNoSideEffect(); + boost::optional> ret; + const auto& chains = dnsdist::configuration::getCurrentRuntimeConfiguration().d_ruleChains; + const auto& ruleactions = dnsdist::rules::getRuleChain(chains, chain.identifier); + if (num < ruleactions.size()) { + ret = ruleactions[num].d_action; + } + return ret; + }); + } - if (netmasks.type() == typeid(LuaArray)) { - NetmaskGroup nmg; - for (const auto& str : *boost::get>(&netmasks)) { - nmg.addMask(str.second); + for (const auto& chain : dnsdist::rules::getResponseRuleChainDescriptions()) { + const auto fullName = std::string("add") + chain.prefix + std::string("ResponseAction"); + luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error(fullName + "() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); } - return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); - } - const auto& nmg = *boost::get(&netmasks); - return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); - }); + addRule(chain.identifier, fullName, var, boost::get>(era), params); + }); + } luaCtx.writeFunction("benchRule", [](const std::shared_ptr& rule, boost::optional times_, boost::optional suffix_) { setLuaNoSideEffect(); @@ -531,6 +543,47 @@ void setupLuaRules(LuaContext& luaCtx) double udiff = swatch.udiff(); g_outputBuffer = (boost::format("Had %d matches out of %d, %.1f qps, in %.1f us\n") % matches % times % (1000000 * (1.0 * times / udiff)) % udiff).str(); }); +} + +// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold +void setupLuaSelectors(LuaContext& luaCtx) +{ + luaCtx.writeFunction("makeRule", [](const luadnsrule_t& var) -> std::shared_ptr { + return makeRule(var, "makeRule"); + }); + + luaCtx.registerFunction::*)() const>("toString", [](const std::shared_ptr& rule) { return rule->toString(); }); + + luaCtx.registerFunction::*)() const>("getMatches", [](const std::shared_ptr& rule) { return rule->d_matches.load(); }); + + luaCtx.registerFunction (dnsdist::rules::RuleAction::*)() const>("getSelector", [](const dnsdist::rules::RuleAction& rule) { return rule.d_rule; }); + + luaCtx.registerFunction (dnsdist::rules::RuleAction::*)() const>("getAction", [](const dnsdist::rules::RuleAction& rule) { return rule.d_action; }); + + luaCtx.registerFunction (dnsdist::rules::ResponseRuleAction::*)() const>("getSelector", [](const dnsdist::rules::ResponseRuleAction& rule) { return rule.d_rule; }); + + luaCtx.registerFunction (dnsdist::rules::ResponseRuleAction::*)() const>("getAction", [](const dnsdist::rules::ResponseRuleAction& rule) { return rule.d_action; }); + + luaCtx.writeFunction("SuffixMatchNodeRule", qnameSuffixRule); + + luaCtx.writeFunction("NetmaskGroupRule", [](const boost::variant> netmasks, boost::optional src, boost::optional quiet) { + if (netmasks.type() == typeid(string)) { + NetmaskGroup nmg; + nmg.addMask(*boost::get(&netmasks)); + return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); + } + + if (netmasks.type() == typeid(LuaArray)) { + NetmaskGroup nmg; + for (const auto& str : *boost::get>(&netmasks)) { + nmg.addMask(str.second); + } + return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); + } + + const auto& nmg = *boost::get(&netmasks); + return std::shared_ptr(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); + }); luaCtx.writeFunction("QNameSuffixRule", qnameSuffixRule); diff --git a/pdns/dnsdistdist/dnsdist-lua.cc b/pdns/dnsdistdist/dnsdist-lua.cc index ef54de73b0..8ec44f2df8 100644 --- a/pdns/dnsdistdist/dnsdist-lua.cc +++ b/pdns/dnsdistdist/dnsdist-lua.cc @@ -3213,6 +3213,8 @@ void setupLuaBindingsOnly(LuaContext& luaCtx, bool client, bool configCheck) setupLuaInspection(luaCtx); setupLuaVars(luaCtx); setupLuaWeb(luaCtx); + setupLuaActions(luaCtx); + setupLuaSelectors(luaCtx); dnsdist::configuration::yaml::addLuaBindingsForYAMLObjects(luaCtx); #ifdef LUAJIT_VERSION @@ -3228,8 +3230,7 @@ void setupLuaConfigurationOptions(LuaContext& luaCtx, bool client, bool configCh } setupLuaConfig(luaCtx, client, configCheck); - setupLuaActions(luaCtx); - setupLuaRules(luaCtx); + setupLuaRuleChainsManagement(luaCtx); dnsdist::lua::hooks::setupLuaHooks(luaCtx); } diff --git a/pdns/dnsdistdist/dnsdist-lua.hh b/pdns/dnsdistdist/dnsdist-lua.hh index 980078c533..47ab0b258e 100644 --- a/pdns/dnsdistdist/dnsdist-lua.hh +++ b/pdns/dnsdistdist/dnsdist-lua.hh @@ -56,7 +56,8 @@ void setupLuaBindingsNetwork(LuaContext& luaCtx, bool client); void setupLuaBindingsPacketCache(LuaContext& luaCtx, bool client); void setupLuaBindingsProtoBuf(LuaContext& luaCtx, bool client, bool configCheck); void setupLuaBindingsRings(LuaContext& luaCtx, bool client); -void setupLuaRules(LuaContext& luaCtx); +void setupLuaRuleChainsManagement(LuaContext& luaCtx); +void setupLuaSelectors(LuaContext& luaCtx); void setupLuaInspection(LuaContext& luaCtx); void setupLuaVars(LuaContext& luaCtx); void setupLuaWeb(LuaContext& luaCtx);