Note that calling `addAnyTCRule()` achieves the same thing, without
involving Lua.
+Lua actions in rules
+--------------------
+While we can pass every packet through the `blockFilter()` functions, it is also
+possible to configure `dnsdist` to only hand off some packets for Lua inspection.
+If you think Lua is too slow for your query load, or if you are doing heavy processing in Lua,
+this may make sense.
+
+To select specific packets for Lua attention, use `addLuaAction(x, func)`,
+where x is either a netmask, or a domain suffix, or a table of netmasks or a
+table of domain suffixes. This is identical to how `addPoolRule()` selects.
+
+The function should look like this:
+```
+function luarule(remote, qname, qtype, dh, len)
+ if(qtype==35) -- NAPTR
+ then
+ return DNSAction.Pool, "abuse" -- send to abuse pool
+ else
+ return DNSAction.None, "" -- no action
+ end
+end
+```
+
DNSSEC
------
To provide DNSSEC service from a separate pool, try:
* `addPoolRule({domain, domain}, pool)`: send queries to these domains to that pool
* `addPoolRule(netmask, pool)`: send queries to this netmask to that pool
* `addPoolRule({netmask, netmask}, pool)`: send queries to these netmasks to that pool
- * `addQPsPoolRule(x, limit, pool)`: like `addPoolRule`, but only select at most 'limit' queries/s for this pool
+ * `addQPSPoolRule(x, limit, pool)`: like `addPoolRule`, but only select at most 'limit' queries/s for this pool
* `getPoolServers(pool)`: return servers part of this pool
+ * Lua Action related:
+ * `addLuaAction(x, func)`: where 'x' is all the combinations from `addPoolRule`, and func is a
+ function with parameters remote, qname, qtype, dh and len, which returns an action to be taken
+ on this packet. Good for rare packets but where you want to do a lot of processing.
* Server selection policy related:
* `setServerPolicy(policy)`: set server selection policy to that policy
* `setServerPolicyLua(name, function)`: set server selection policy to one named 'name' and provided by 'function'
static vector<std::function<void(void)>>* g_launchWork;
+class LuaAction : public DNSAction
+{
+public:
+ typedef std::function<std::tuple<int, string>(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len)> func_t;
+ LuaAction(LuaAction::func_t func) : d_func(func)
+ {}
+
+ Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const
+ {
+ auto ret = d_func(remote, qname, qtype, dh, len);
+ if(ruleresult)
+ *ruleresult=std::get<1>(ret);
+ return (Action)std::get<0>(ret);
+ }
+
+ string toString() const
+ {
+ return "Lua script";
+ }
+
+private:
+ func_t d_func;
+};
+
+std::shared_ptr<DNSRule> makeRule(const boost::variant<string,vector<pair<int, string>> >& var)
+{
+ SuffixMatchNode smn;
+ NetmaskGroup nmg;
+
+ auto add=[&](string src) {
+ try {
+ smn.add(DNSName(src));
+ } catch(...) {
+ nmg.addMask(src);
+ }
+ };
+ if(auto src = boost::get<string>(&var))
+ add(*src);
+ else {
+ for(auto& a : boost::get<vector<pair<int, string>>>(var)) {
+ add(a.second);
+ }
+ }
+ if(nmg.empty())
+ return std::make_shared<SuffixMatchNodeRule>(smn);
+ else
+ return std::make_shared<NetmaskGroupRule>(nmg);
+}
+
vector<std::function<void(void)>> setupLua(bool client, const std::string& config)
{
g_launchWork= new vector<std::function<void(void)>>();
typedef std::unordered_map<std::string, boost::variant<std::string, vector<pair<int, std::string> > > > newserver_t;
+ g_lua.writeVariable("DNSAction", std::unordered_map<string,int>{
+ {"Drop", (int)DNSAction::Action::Drop},
+ {"Nxdomain", (int)DNSAction::Action::Nxdomain},
+ {"Spoof", (int)DNSAction::Action::Spoof},
+ {"Allow", (int)DNSAction::Action::Allow},
+ {"HeaderModify", (int)DNSAction::Action::HeaderModify},
+ {"Pool", (int)DNSAction::Action::Pool},
+ {"None",(int)DNSAction::Action::Pool}}
+ );
+
+
g_lua.writeFunction("newServer",
[client](boost::variant<string,newserver_t> pvars, boost::optional<int> qps)
{
return ret;
} );
+
g_lua.writeFunction("addAnyTCRule", []() {
auto rules=g_rulactions.getCopy();
rules.push_back({ std::make_shared<QTypeRule>(0xff), std::make_shared<TCAction>()});
}catch(std::exception& e) { g_outputBuffer=e.what(); throw; }
});
- g_lua.writeFunction("addPoolRule", [](boost::variant<string,vector<pair<int, string>> > var, string pool) {
- SuffixMatchNode smn;
- NetmaskGroup nmg;
+ g_lua.writeFunction("addLuaAction", [](boost::variant<string,vector<pair<int, string>> > var, LuaAction::func_t func)
+ {
+ auto rule=makeRule(var);
+ g_rulactions.modify([rule,func](decltype(g_rulactions)::value_type& rulactions){
+ rulactions.push_back({rule,
+ std::make_shared<LuaAction>(func)});
+ });
+ });
- auto add=[&](string src) {
- try {
- smn.add(DNSName(src));
- } catch(...) {
- nmg.addMask(src);
- }
- };
- if(auto src = boost::get<string>(&var))
- add(*src);
- else {
- for(auto& a : boost::get<vector<pair<int, string>>>(var)) {
- add(a.second);
- }
- }
- if(nmg.empty())
- g_rulactions.modify([smn, pool](decltype(g_rulactions)::value_type& rulactions) {
+
+ g_lua.writeFunction("addPoolRule", [](boost::variant<string,vector<pair<int, string>> > var, string pool) {
+ auto rule=makeRule(var);
+ g_rulactions.modify([rule, pool](decltype(g_rulactions)::value_type& rulactions) {
rulactions.push_back({
- std::make_shared<SuffixMatchNodeRule>(smn),
- std::make_shared<PoolAction>(pool) });
- });
- else
- g_rulactions.modify([nmg,pool](decltype(g_rulactions)::value_type& rulactions) {
- rulactions.push_back({std::make_shared<NetmaskGroupRule>(nmg),
- std::make_shared<PoolAction>(pool)});
+ rule,
+ std::make_shared<PoolAction>(pool) });
});
-
});
g_lua.writeFunction("addQPSPoolRule", [](boost::variant<string,vector<pair<int, string>> > var, int limit, string pool) {
- SuffixMatchNode smn;
- NetmaskGroup nmg;
-
- auto add=[&](string src) {
- try {
- smn.add(DNSName(src));
- } catch(...) {
- nmg.addMask(src);
- }
- };
- if(auto src = boost::get<string>(&var))
- add(*src);
- else {
- for(auto& a : boost::get<vector<pair<int, string>>>(var)) {
- add(a.second);
- }
- }
- if(nmg.empty())
- g_rulactions.modify([smn, pool,limit](decltype(g_rulactions)::value_type& rulactions) {
- rulactions.push_back({
- std::make_shared<SuffixMatchNodeRule>(smn),
- std::make_shared<QPSPoolAction>(limit, pool) });
- });
- else
- g_rulactions.modify([nmg,pool,limit](decltype(g_rulactions)::value_type& rulactions) {
- rulactions.push_back({std::make_shared<NetmaskGroupRule>(nmg),
- std::make_shared<QPSPoolAction>(limit, pool)});
- });
-
+ auto rule = makeRule(var);
+ g_rulactions.modify([rule, pool,limit](decltype(g_rulactions)::value_type& rulactions) {
+ rulactions.push_back({
+ rule,
+ std::make_shared<QPSPoolAction>(limit, pool) });
+ });
});
g_lua.writeFunction("setDNSSECPool", [](const std::string& pool) {
});
g_lua.writeFunction("addQPSLimit", [](boost::variant<string,vector<pair<int, string>> > var, int lim) {
- SuffixMatchNode smn;
- NetmaskGroup nmg;
-
- auto add=[&](string src) {
- try {
- smn.add(DNSName(src));
- } catch(...) {
- nmg.addMask(src);
- }
- };
- if(auto src = boost::get<string>(&var))
- add(*src);
- else {
- for(auto& a : boost::get<vector<pair<int, string>>>(var)) {
- add(a.second);
- }
- }
- if(nmg.empty())
- g_rulactions.modify([smn, lim](decltype(g_rulactions)::value_type& rulactions) {
- rulactions.push_back({std::make_shared<SuffixMatchNodeRule>(smn),
- std::make_shared<QPSAction>(lim)});
- });
- else
- g_rulactions.modify([nmg, lim](decltype(g_rulactions)::value_type& rulactions) {
- rulactions.push_back({std::make_shared<NetmaskGroupRule>(nmg),
- std::make_shared<QPSAction>(lim)});
- });
+ auto rule = makeRule(var);
+ g_rulactions.modify([lim,rule](decltype(g_rulactions)::value_type& rulactions) {
+ rulactions.push_back({rule,
+ std::make_shared<QPSAction>(lim)});
+ });
});
+
g_lua.writeFunction("showRules", []() {