diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 21:14:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 21:14:49 +0000 |
commit | 2f230033794fafdf10822568e763d4db68cf6c6b (patch) | |
tree | 39ca5c2325b7b43c9a28ca6d4ad4026a61e7eb97 /dnsdist-lua-rules.cc | |
parent | Adding debian version 1.8.3-3. (diff) | |
download | dnsdist-2f230033794fafdf10822568e763d4db68cf6c6b.tar.xz dnsdist-2f230033794fafdf10822568e763d4db68cf6c6b.zip |
Merging upstream version 1.9.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dnsdist-lua-rules.cc')
-rw-r--r-- | dnsdist-lua-rules.cc | 216 |
1 files changed, 176 insertions, 40 deletions
diff --git a/dnsdist-lua-rules.cc b/dnsdist-lua-rules.cc index da309e5..f53b98b 100644 --- a/dnsdist-lua-rules.cc +++ b/dnsdist-lua-rules.cc @@ -22,40 +22,51 @@ #include "dnsdist.hh" #include "dnsdist-lua.hh" #include "dnsdist-rules.hh" +#include "dns_random.hh" -std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var) +std::shared_ptr<DNSRule> makeRule(const luadnsrule_t& var, const std::string& calledFrom) { - if (var.type() == typeid(std::shared_ptr<DNSRule>)) + if (var.type() == typeid(std::shared_ptr<DNSRule>)) { return *boost::get<std::shared_ptr<DNSRule>>(&var); + } + bool suffixSeen = false; SuffixMatchNode smn; NetmaskGroup nmg; - auto add=[&](string src) { + auto add = [&nmg, &smn, &suffixSeen](const string& src) { try { nmg.addMask(src); // need to try mask first, all masks are domain names! - } catch(...) { + } catch (...) { + suffixSeen = true; smn.add(DNSName(src)); } }; - if (var.type() == typeid(string)) + if (var.type() == typeid(string)) { add(*boost::get<string>(&var)); - - else if (var.type() == typeid(LuaArray<std::string>)) - for(const auto& a : *boost::get<LuaArray<std::string>>(&var)) - add(a.second); - - else if (var.type() == typeid(DNSName)) + } + else if (var.type() == typeid(LuaArray<std::string>)) { + for (const auto& str : *boost::get<LuaArray<std::string>>(&var)) { + add(str.second); + } + } + else if (var.type() == typeid(DNSName)) { smn.add(*boost::get<DNSName>(&var)); + } + else if (var.type() == typeid(LuaArray<DNSName>)) { + smn = SuffixMatchNode(); + for (const auto& name : *boost::get<LuaArray<DNSName>>(&var)) { + smn.add(name.second); + } + } - else if (var.type() == typeid(LuaArray<DNSName>)) - for(const auto& a : *boost::get<LuaArray<DNSName>>(&var)) - smn.add(a.second); - - if(nmg.empty()) + if (nmg.empty()) { return std::make_shared<SuffixMatchNodeRule>(smn); - else - return std::make_shared<NetmaskGroupRule>(nmg, true); + } + if (suffixSeen) { + warnlog("At least one parameter to %s has been parsed as a domain name amongst network masks, and will be ignored!", calledFrom); + } + return std::make_shared<NetmaskGroupRule>(nmg, true); } static boost::uuids::uuid makeRuleID(std::string& id) @@ -83,7 +94,7 @@ void parseRuleParams(boost::optional<luaruleparams_t>& params, boost::uuids::uui typedef LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int> > > ruleparams_t; template<typename T> -static std::string rulesToString(const std::vector<T>& rules, boost::optional<ruleparams_t> vars) +static std::string rulesToString(const std::vector<T>& rules, boost::optional<ruleparams_t>& vars) { int num = 0; bool showUUIDs = false; @@ -116,7 +127,7 @@ static std::string rulesToString(const std::vector<T>& rules, boost::optional<ru } template<typename T> -static void showRules(GlobalStateHolder<vector<T> > *someRuleActions, boost::optional<ruleparams_t> vars) { +static void showRules(GlobalStateHolder<vector<T> > *someRuleActions, boost::optional<ruleparams_t>& vars) { setLuaNoSideEffect(); auto rules = someRuleActions->getLocal(); @@ -124,7 +135,7 @@ static void showRules(GlobalStateHolder<vector<T> > *someRuleActions, boost::opt } template<typename T> -static void rmRule(GlobalStateHolder<vector<T> > *someRuleActions, boost::variant<unsigned int, std::string> id) { +static void rmRule(GlobalStateHolder<vector<T> > *someRuleActions, const boost::variant<unsigned int, std::string>& id) { setLuaSideEffect(); auto rules = someRuleActions->getCopy(); if (auto str = boost::get<std::string>(&id)) { @@ -227,12 +238,93 @@ static std::vector<T> getTopRules(const std::vector<T>& rules, unsigned int top) return results; } +template<typename T> +static LuaArray<T> toLuaArray(std::vector<T>&& rules) +{ + LuaArray<T> results; + results.reserve(rules.size()); + + size_t pos = 1; + for (auto& rule : rules) { + results.emplace_back(pos, std::move(rule)); + pos++; + } + + return results; +} + +template <typename T> +static boost::optional<T> getRuleFromSelector(const std::vector<T>& rules, const boost::variant<int, std::string>& selector) +{ + if (auto str = boost::get<std::string>(&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<int>(&selector)) { + /* this will throw a std::out_of_range exception if the + supplied position is out of bounds, this is fine */ + return rules.at(*pos); + } + return boost::none; +} + +namespace +{ +std::shared_ptr<DNSRule> qnameSuffixRule(const boost::variant<const SuffixMatchNode&, std::string, const LuaArray<std::string>> names, boost::optional<bool> quiet) +{ + if (names.type() == typeid(string)) { + SuffixMatchNode smn; + smn.add(DNSName(*boost::get<std::string>(&names))); + return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); + } + + if (names.type() == typeid(LuaArray<std::string>)) { + SuffixMatchNode smn; + for (const auto& str : *boost::get<const LuaArray<std::string>>(&names)) { + smn.add(DNSName(str.second)); + } + return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); + } + + const auto& smn = *boost::get<const SuffixMatchNode&>(&names); + return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); +} +} + +// 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) { - luaCtx.writeFunction("makeRule", makeRule); + luaCtx.writeFunction("makeRule", [](const luadnsrule_t& var) -> std::shared_ptr<DNSRule> { + return makeRule(var, "makeRule"); + }); luaCtx.registerFunction<string(std::shared_ptr<DNSRule>::*)()const>("toString", [](const std::shared_ptr<DNSRule>& rule) { return rule->toString(); }); + luaCtx.registerFunction<uint64_t(std::shared_ptr<DNSRule>::*)()const>("getMatches", [](const std::shared_ptr<DNSRule>& rule) { return rule->d_matches.load(); }); + + luaCtx.registerFunction<std::shared_ptr<DNSRule>(DNSDistRuleAction::*)()const>("getSelector", [](const DNSDistRuleAction& rule) { return rule.d_rule; }); + + luaCtx.registerFunction<std::shared_ptr<DNSAction>(DNSDistRuleAction::*)()const>("getAction", [](const DNSDistRuleAction& rule) { return rule.d_action; }); + + luaCtx.registerFunction<std::shared_ptr<DNSRule>(DNSDistResponseRuleAction::*)()const>("getSelector", [](const DNSDistResponseRuleAction& rule) { return rule.d_rule; }); + + luaCtx.registerFunction<std::shared_ptr<DNSResponseAction>(DNSDistResponseRuleAction::*)()const>("getAction", [](const DNSDistResponseRuleAction& rule) { return rule.d_action; }); + luaCtx.writeFunction("showResponseRules", [](boost::optional<ruleparams_t> vars) { showRules(&g_respruleactions, vars); }); @@ -323,17 +415,22 @@ void setupLuaRules(LuaContext& luaCtx) for (const auto& pair : newruleactions) { const auto& newruleaction = pair.second; if (newruleaction->d_action) { - auto rule = makeRule(newruleaction->d_rule); + auto rule = newruleaction->d_rule; gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder}); } } }); }); + luaCtx.writeFunction("getRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistRuleAction> { + auto rules = g_ruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopRules", [](boost::optional<unsigned int> 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<unsigned int> top, boost::optional<ruleparams_t> vars) { @@ -342,10 +439,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getCacheHitResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> { + auto rules = g_cachehitrespruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopCacheHitResponseRules", [](boost::optional<unsigned int> 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<unsigned int> top, boost::optional<ruleparams_t> vars) { @@ -354,10 +456,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getCacheInsertedResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> { + auto rules = g_cacheInsertedRespRuleActions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopCacheInsertedResponseRules", [](boost::optional<unsigned int> 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<unsigned int> top, boost::optional<ruleparams_t> vars) { @@ -366,10 +473,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> { + auto rules = g_respruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopResponseRules", [](boost::optional<unsigned int> 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<unsigned int> top, boost::optional<ruleparams_t> vars) { @@ -378,10 +490,15 @@ void setupLuaRules(LuaContext& luaCtx) return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + luaCtx.writeFunction("getSelfAnsweredResponseRule", [](boost::variant<int, std::string> selector) -> boost::optional<DNSDistResponseRuleAction> { + auto rules = g_selfansweredrespruleactions.getLocal(); + return getRuleFromSelector(*rules, selector); + }); + luaCtx.writeFunction("getTopSelfAnsweredResponseRules", [](boost::optional<unsigned int> 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<unsigned int> top, boost::optional<ruleparams_t> vars) { @@ -427,13 +544,26 @@ void setupLuaRules(LuaContext& luaCtx) return std::shared_ptr<DNSRule>(new SNIRule(name)); }); - luaCtx.writeFunction("SuffixMatchNodeRule", [](const SuffixMatchNode& smn, boost::optional<bool> quiet) { - return std::shared_ptr<DNSRule>(new SuffixMatchNodeRule(smn, quiet ? *quiet : false)); - }); + luaCtx.writeFunction("SuffixMatchNodeRule", qnameSuffixRule); - luaCtx.writeFunction("NetmaskGroupRule", [](const NetmaskGroup& nmg, boost::optional<bool> src, boost::optional<bool> quiet) { + luaCtx.writeFunction("NetmaskGroupRule", [](const boost::variant<const NetmaskGroup&, std::string, const LuaArray<std::string>> netmasks, boost::optional<bool> src, boost::optional<bool> quiet) { + if (netmasks.type() == typeid(string)) { + NetmaskGroup nmg; + nmg.addMask(*boost::get<std::string>(&netmasks)); return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); - }); + } + + if (netmasks.type() == typeid(LuaArray<std::string>)) { + NetmaskGroup nmg; + for (const auto& str : *boost::get<const LuaArray<std::string>>(&netmasks)) { + nmg.addMask(str.second); + } + return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); + } + + const auto& nmg = *boost::get<const NetmaskGroup&>(&netmasks); + return std::shared_ptr<DNSRule>(new NetmaskGroupRule(nmg, src ? *src : true, quiet ? *quiet : false)); + }); luaCtx.writeFunction("benchRule", [](std::shared_ptr<DNSRule> rule, boost::optional<unsigned int> times_, boost::optional<string> suffix_) { setLuaNoSideEffect(); @@ -447,9 +577,9 @@ void setupLuaRules(LuaContext& luaCtx) items.reserve(1000); for (int n = 0; n < 1000; ++n) { struct item i; - i.ids.qname = DNSName(std::to_string(random())); + i.ids.qname = DNSName(std::to_string(dns_random_uint32())); i.ids.qname += suffix; - i.ids.qtype = random() % 0xff; + i.ids.qtype = dns_random(0xff); i.ids.qclass = QClass::IN; i.ids.protocol = dnsdist::Protocol::DoUDP; i.ids.origRemote = ComboAddress("127.0.0.1"); @@ -472,7 +602,7 @@ void setupLuaRules(LuaContext& luaCtx) } } double udiff = sw.udiff(); - g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f usec\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str(); + 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(); }); @@ -488,6 +618,8 @@ void setupLuaRules(LuaContext& luaCtx) return std::shared_ptr<DNSRule>(new QNameRule(DNSName(qname))); }); + luaCtx.writeFunction("QNameSuffixRule", qnameSuffixRule); + luaCtx.writeFunction("QTypeRule", [](boost::variant<unsigned int, std::string> str) { uint16_t qtype; if (auto dir = boost::get<unsigned int>(&str)) { @@ -596,7 +728,7 @@ void setupLuaRules(LuaContext& luaCtx) }); luaCtx.writeFunction("TagRule", [](const std::string& tag, boost::optional<std::string> value) { - return std::shared_ptr<DNSRule>(new TagRule(tag, value)); + return std::shared_ptr<DNSRule>(new TagRule(tag, std::move(value))); }); luaCtx.writeFunction("TimedIPSetRule", []() { @@ -653,10 +785,14 @@ void setupLuaRules(LuaContext& luaCtx) }); luaCtx.writeFunction("LuaFFIPerThreadRule", [](const std::string& code) { - return std::shared_ptr<DNSRule>(new LuaFFIPerThreadRule(code)); - }); + return std::shared_ptr<DNSRule>(new LuaFFIPerThreadRule(code)); + }); luaCtx.writeFunction("ProxyProtocolValueRule", [](uint8_t type, boost::optional<std::string> value) { - return std::shared_ptr<DNSRule>(new ProxyProtocolValueRule(type, value)); + return std::shared_ptr<DNSRule>(new ProxyProtocolValueRule(type, std::move(value))); + }); + + luaCtx.writeFunction("PayloadSizeRule", [](const std::string& comparison, uint16_t size) { + return std::shared_ptr<DNSRule>(new PayloadSizeRule(comparison, size)); }); } |