]> granicus.if.org Git - pdns/commitdiff
clean up duplicate Rule code in Lua and as bonus give you LuaAction & document it
authorbert hubert <bert.hubert@netherlabs.nl>
Tue, 14 Apr 2015 15:38:33 +0000 (17:38 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Tue, 14 Apr 2015 15:38:33 +0000 (17:38 +0200)
pdns/README-dnsdist.md
pdns/dnsdist-lua.cc
pdns/dnsdist.hh
pdns/dnsdistconf.lua

index 99e2d8e7e1cc67efa349ffab29aa10dc8fb8dd43..d02758e795608227449899e70bdf3e8bb3c169df 100644 (file)
@@ -223,6 +223,29 @@ servers that lack this feature.
 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:
@@ -470,8 +493,12 @@ Here are all functions:
    * `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'
index 0d764dbaab92d2ee28a2b9762be09d2098e371da..95f86c80e02d5f1648f93644388c99763eab55ce 100644 (file)
@@ -10,11 +10,71 @@ using std::thread;
 
 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)
                      { 
@@ -106,6 +166,7 @@ vector<std::function<void(void)>> setupLua(bool client, const std::string& confi
                        return ret;
                      } );
 
+
   g_lua.writeFunction("addAnyTCRule", []() {
       auto rules=g_rulactions.getCopy();
       rules.push_back({ std::make_shared<QTypeRule>(0xff), std::make_shared<TCAction>()});
@@ -270,67 +331,31 @@ vector<std::function<void(void)>> setupLua(bool client, const std::string& confi
       }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) {
@@ -341,34 +366,13 @@ vector<std::function<void(void)>> setupLua(bool client, const std::string& confi
     });
 
   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", []() {
index 8c15abf7c1bf58da75c289973ef5a79366881f6f..fda41948588bf32d1c4a21af89675dabeb02d2f5 100644 (file)
@@ -309,4 +309,4 @@ std::unique_ptr<T> make_unique(Args&&... args)
 void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password);
 bool getMsgLen(int fd, uint16_t* len);
 bool putMsgLen(int fd, uint16_t len);
-void* tcpAcceptorThread(void* p);
\ No newline at end of file
+void* tcpAcceptorThread(void* p);
index ce69fd3803de692346eaf55f4f544831c63a3fa6..49f830c5c6817d8d8e6fcbdec613a04bfe3c5939 100644 (file)
@@ -23,6 +23,17 @@ addPoolRule({"ezdns.it.", "xxx."}, "abuse")
 addPoolRule("192.168.1.0/24", "abuse")
 addQPSPoolRule("com.", 100, "abuse")
 
+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
+addLuaAction("192.168.1.0/24", luarule)
+topRule()
+
 addDomainBlock("powerdns.org.")
 addDomainBlock("spectre.")
 addDomainBlock("isis.")