From: Remi Gacogne Date: Tue, 11 Jul 2023 12:18:52 +0000 (+0200) Subject: dnsdist: Add Lua bindings to access selector and actions X-Git-Tag: rec-5.0.0-alpha1~78^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d05c43ba621a37458ca496654b983b731bcde4f8;p=thirdparty%2Fpdns.git dnsdist: Add Lua bindings to access selector and actions --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index e3e5bcf325..f2e381f222 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -519,6 +519,8 @@ const std::vector g_consoleKeywords{ { "getAction", true, "n", "Returns the Action associated with rule n" }, { "getBind", true, "n", "returns the listener at index n" }, { "getBindCount", true, "", "returns the number of listeners all kinds" }, + { "getCacheHitResponseRule", true, "selector", "Return the cache-hit response rule corresponding to the selector, if any" }, + { "getCacheInsertedResponseRule", true, "selector", "Return the cache-inserted response rule corresponding to the selector, if any" }, { "getCurrentTime", true, "", "returns the current time" }, { "getDNSCryptBind", true, "n", "return the `DNSCryptContext` object corresponding to the bind `n`" }, { "getDNSCryptBindCount", true, "", "returns the number of DNSCrypt listeners" }, @@ -535,7 +537,10 @@ const std::vector g_consoleKeywords{ { "getPoolNames", true, "", "returns a table with all the pool names" }, { "getQueryCounters", true, "[max=10]", "show current buffer of query counters, limited by 'max' if provided" }, { "getResponseRing", true, "", "return the current content of the response ring" }, + { "getResponseRule", true, "selector", "Return the response rule corresponding to the selector, if any" }, { "getRespRing", true, "", "return the qname/rcode content of the response ring" }, + { "getRule", true, "selector", "Return the rule corresponding to the selector, if any" }, + { "getSelfAnsweredResponseRule", true, "selector", "Return the self-answered response rule corresponding to the selector, if any" }, { "getServer", true, "id", "returns server with index 'n' or whose uuid matches if 'id' is an UUID string" }, { "getServers", true, "", "returns a table with all defined servers" }, { "getStatisticsCounters", true, "", "returns a map of statistic counters" }, diff --git a/pdns/dnsdist-lua-rules.cc b/pdns/dnsdist-lua-rules.cc index 8549014e72..5ab1c476ef 100644 --- a/pdns/dnsdist-lua-rules.cc +++ b/pdns/dnsdist-lua-rules.cc @@ -224,12 +224,65 @@ static std::vector getTopRules(const std::vector& rules, unsigned int top) return results; } +template +static LuaArray toLuaArray(std::vector&& rules) +{ + LuaArray results; + results.reserve(rules.size()); + + size_t pos = 1; + for (auto& rule : rules) { + results.emplace_back(pos, std::move(rule)); + pos++; + } + + return results; +} + +template +static boost::optional getRuleFromSelector(const std::vector& rules, const boost::variant& selector) +{ + if (auto str = boost::get(&selector)) { + /* let's see if this a UUID */ + try { + const auto uuid = getUniqueID(*str); + for (const auto& rule : rules) { + if (rule.d_id == uuid) { + return rule; + } + } + } + catch (const std::exception& e) { + /* a name, then */ + for (const auto& rule : rules) { + if (rule.d_name == *str) { + return rule; + } + } + } + } + else if (auto pos = boost::get(&selector)) { + return rules.at(*pos); + } + return boost::none; +} + void setupLuaRules(LuaContext& luaCtx) { luaCtx.writeFunction("makeRule", 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(DNSDistRuleAction::*)()const>("getSelector", [](const DNSDistRuleAction& rule) { return rule.d_rule; }); + + luaCtx.registerFunction(DNSDistRuleAction::*)()const>("getAction", [](const DNSDistRuleAction& rule) { return rule.d_action; }); + + luaCtx.registerFunction(DNSDistResponseRuleAction::*)()const>("getSelector", [](const DNSDistResponseRuleAction& rule) { return rule.d_rule; }); + + luaCtx.registerFunction(DNSDistResponseRuleAction::*)()const>("getAction", [](const DNSDistResponseRuleAction& rule) { return rule.d_action; }); + luaCtx.writeFunction("showResponseRules", [](boost::optional vars) { showRules(&g_respruleactions, vars); }); @@ -327,10 +380,15 @@ void setupLuaRules(LuaContext& luaCtx) }); }); + luaCtx.writeFunction("getRule", [](boost::variant selector) -> boost::optional { + auto rules = g_ruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_ruleactions.getLocal(); - return getTopRules(*rules, (top ? *top : 10)); + return toLuaArray(getTopRules(*rules, (top ? *top : 10))); }); luaCtx.writeFunction("topRules", [](boost::optional top, boost::optional vars) { @@ -339,10 +397,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getCacheHitResponseRule", [](boost::variant selector) -> boost::optional { + auto rules = g_cachehitrespruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopCacheHitResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_cachehitrespruleactions.getLocal(); - return getTopRules(*rules, (top ? *top : 10)); + return toLuaArray(getTopRules(*rules, (top ? *top : 10))); }); luaCtx.writeFunction("topCacheHitResponseRules", [](boost::optional top, boost::optional vars) { @@ -351,10 +414,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getCacheInsertedResponseRule", [](boost::variant selector) -> boost::optional { + auto rules = g_cacheInsertedRespRuleActions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopCacheInsertedResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_cacheInsertedRespRuleActions.getLocal(); - return getTopRules(*rules, (top ? *top : 10)); + return toLuaArray(getTopRules(*rules, (top ? *top : 10))); }); luaCtx.writeFunction("topCacheInsertedResponseRules", [](boost::optional top, boost::optional vars) { @@ -363,10 +431,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getResponseRule", [](boost::variant selector) -> boost::optional { + auto rules = g_respruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_respruleactions.getLocal(); - return getTopRules(*rules, (top ? *top : 10)); + return toLuaArray(getTopRules(*rules, (top ? *top : 10))); }); luaCtx.writeFunction("topResponseRules", [](boost::optional top, boost::optional vars) { @@ -375,10 +448,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getSelfAnsweredResponseRule", [](boost::variant selector) -> boost::optional { + auto rules = g_selfansweredrespruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopSelfAnsweredResponseRules", [](boost::optional top) { setLuaNoSideEffect(); auto rules = g_selfansweredrespruleactions.getLocal(); - return getTopRules(*rules, (top ? *top : 10)); + return toLuaArray(getTopRules(*rules, (top ? *top : 10))); }); luaCtx.writeFunction("topSelfAnsweredResponseRules", [](boost::optional top, boost::optional vars) { diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index fca2e3c4db..7e93417713 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -951,7 +951,7 @@ public: virtual ~DNSRule () { } - virtual bool matches(const DNSQuestion* dq) const =0; + virtual bool matches(const DNSQuestion* dq) const = 0; virtual string toString() const = 0; mutable stat_t d_matches{0}; }; diff --git a/pdns/dnsdistdist/docs/rules-actions.rst b/pdns/dnsdistdist/docs/rules-actions.rst index be3dffaa3f..116c57b598 100644 --- a/pdns/dnsdistdist/docs/rules-actions.rst +++ b/pdns/dnsdistdist/docs/rules-actions.rst @@ -169,12 +169,62 @@ For Rules related to the incoming query: Remove all current rules. -.. function:: getAction(n) -> Action +.. function:: getAction(n) -> DNSDistRuleAction - Returns the Action associated with rule ``n``. + Returns the :class:`DNSDistRuleAction` associated with rule ``n``. :param int n: The rule number +.. function:: getCacheHitResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the cache-hit response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + +.. function:: getCacheInsertedResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the cache-hit response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + +.. function:: getResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + +.. function:: getRule(selector) -> DNSDistRuleAction + + .. versionadded:: 1.9.0 + + Return the rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + +.. function:: getSelfAnsweredResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the cache-hit response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + .. function:: mvRule(from, to) Move rule ``from`` to a position where it is in front of ``to``. @@ -1802,3 +1852,45 @@ The following actions exist. Subsequent rules are processed after this action. :param int ttl: Cache TTL for temporary failure replies + +Objects +------- + +.. class:: DNSDistRuleAction + + .. versionadded:: 1.9.0 + + Represents a rule composed of a :class:`DNSRule` selector, to select the queries this applies to, + and a :class:`DNSAction` action to apply when the selector matches. + + .. method:: DNSDistRuleAction:getAction() + + Return the :class:`DNSAction` action of this rule. + + .. method:: DNSDistRuleAction:getSelector() + + Return the :class:`DNSRule` selector of this rule. + +.. class:: DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Represents a rule composed of a :class:`DNSRule` selector, to select the responses this applies to, + and a :class:`DNSResponseAction` action to apply when the selector matches. + + .. method:: DNSDistResponseRuleAction:getAction() + + Return the :class:`DNSResponseAction` action of this rule. + + .. method:: DNSDistResponseRuleAction:getSelector() + + Return the :class:`DNSRule` selector of this rule. + +.. class:: DNSRule + + .. versionadded:: 1.9.0 + + .. method:: DNSRule:getMatches() -> int + + Return the number of times this selector matched a query or a response. Note that if the same selector is reused for different ``DNSDistRuleAction`` + objects, the counter will be common to all these objects.