summaryrefslogtreecommitdiffstats
path: root/dnsdist-lua-rules.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
commitbc282425088455198a7a99511c75914477d4ed32 (patch)
tree1b1fb887a634136a093deea7e4dd95d054201e7a /dnsdist-lua-rules.cc
parentReleasing progress-linux version 1.8.3-3~progress7.99u1. (diff)
downloaddnsdist-bc282425088455198a7a99511c75914477d4ed32.tar.xz
dnsdist-bc282425088455198a7a99511c75914477d4ed32.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.cc216
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));
});
}