]> granicus.if.org Git - pdns/commitdiff
move to one central set of Rules, and document this
authorbert hubert <bert.hubert@netherlabs.nl>
Mon, 16 Mar 2015 09:31:16 +0000 (10:31 +0100)
committerbert hubert <bert.hubert@netherlabs.nl>
Mon, 16 Mar 2015 09:31:16 +0000 (10:31 +0100)
pdns/README-dnsdist.md
pdns/dnsdist-lua.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistconf.lua
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/populate
pdns/dnsrulactions.hh [new file with mode: 0644]
pdns/iputils.hh

index ca9040265a322132bb77a4927c711f48f4f74f2b..ee209da4694b257999d1c2a75a3a60a5501c3296 100644 (file)
@@ -116,7 +116,6 @@ To change the QPS for a server:
 
 Server pools
 ------------
-
 Now for some cool stuff. Let's say we know we're getting a whole bunch of
 traffic for a domain used in DoS attacks, for example 'sh43354.cn'. We can
 do two things with this kind of traffic. Either we block it outright, like
@@ -145,13 +144,34 @@ We can similarly add clients to the abuse server:
 > addPoolRule({"192.168.12.0/24", "192.168.13.14"}, "abuse")
 ```
 
-Pool rules can be inspected with `showPoolRules()`, and can be deleted with
-`rmPoolRule()`. Servers can be added or removed to pools with:
+Both `addDomainBlock` and `addPoolRule` end up the list of Rules 
+and Actions (for which see below).
+
+Servers can be added or removed to pools with:
 ```
 > getServer(7):addPool("abuse")
 > getServer(4):rmPool("abuse")
 ```
 
+
+Rules
+-----
+Rules can be inspected with `showRules()`, and can be deleted with
+`rmRule()`.  Rules are evaluated in order, and this order can be changed
+with `mvRule(from, to)` (see below for exact semantics).
+
+Rules have selectors and actions. Current selectors are:
+ * Source address
+ * Query type
+ * Query domain
+
+Current actions are:
+ * Drop
+ * Route to a pool
+ * Return with TC=1 (truncated, ie, instruction to retry with TCP)
+ * Force a ServFail, NotImp or Refused answer
+ * Send out a crafted response (NXDOMAIN or "real" data)
+
 More power
 ----------
 More powerful things can be achieved by defining a function called
@@ -173,6 +193,9 @@ If you also called setTC(1), this will tell the remote client to move to
 TCP/IP, and in this way you can implement ANY-to-TCP even for downstream
 servers that lack this feature.
 
+Note that calling `addAnyTCRule()` achieves the same thing, without
+involving Lua.
+
 Inspecting live traffic
 -----------------------
 This is still much in flux, but for now, try:
@@ -218,25 +241,24 @@ forward:
 > addQPSLimit("h4xorbooter.xyz.", 10)
 > addQPSLimit({"130.161.0.0/16", "145.14.0.0/16"} , 20)
 > addQPSLimit({"nl.", "be."}, 1)
-> showQPSLimits()
-#   Object                                                 Lim   Passed  Blocked
-0   h4xorbooter.xyz.                                        10        0        0
-1   130.161.0.0/16, 145.14.0.0/16                           20        0        0
-2   nl., be.                                                 1        2        8
+> showRules()
+#     Matches Rule                                               Action
+0           0 h4xorbooter.xyz.                                   qps limit to 10
+1           0 130.161.0.0/16, 145.14.0.0/16                      qps limit to 20
+2           0 nl., be.                                           qps limit to 1
 ```
 
-To delete a limit:
+To delete a limit (or a rule in general):
 ```
-> deleteQPSLimit(1)
-> showQPSLimits()
-#   Object                                                 Lim   Passed  Blocked
-0   h4xorbooter.xyz.                                        10        0        0
-1   nl., be.                                                 1       16      251
+> rmRule(1)
+> showRules()
+#     Matches Rule                                               Action
+0           0 h4xorbooter.xyz.                                   qps limit to 10
+1           0 nl., be.                                           qps limit to 1
 ```
 
 Dynamic load balancing
 ----------------------
-
 The default load balancing policy is called 'leastOutstanding', which means 
 we pick the server with the least queries 'in the air'. 
 
@@ -273,7 +295,7 @@ authServer=newServer{address="2001:888:2000:1d::2", pool="auth"}
 function splitSetup(servers, remote, qname, qtype, dh)
         if(dh:getRD() == false)
         then
-               return authServer
+               return leastOutstanding(getPoolServers("auth"), remote, qname, qtype, dh)
         else
                return leastOutstanding(servers, remote, qname, qtype, dh)
         end
@@ -282,9 +304,9 @@ end
 setServerPolicyLua("splitsetup", splitSetup)
 ```
 
-This will forward queries that don't want recursion to a specific
-server, and will apply the default load balancing policy to all
-other queries.
+This will forward queries that don't want recursion to the pool of auth
+servers, and will apply the default load balancing policy to all other
+queries.
 
 Running it for real
 -------------------
@@ -350,6 +372,9 @@ The '.' means 'order' is a data member, while the ':' meand addPool is a member
 
 Here are all functions:
 
+ * Practical
+   * `shutdown()`: shut down dnsdist
+   * quit or ^D: exit the console
  * ACL related:
    * `addACL(netmask)`: add to the ACL set who can use this server
    * `setACL({netmask, netmask})`: replace the ACL set with these netmasks. Use `setACL({})` to reset the list, meaning no one can use us
@@ -391,13 +416,16 @@ Here are all functions:
    * `upStatus`: if dnsdist considers this server available (overridden by `setDown()` and `setUp()`)
    * `order`: order of this server in order-based server selection policies
    * `weight`: weight of this server in weighted server selection policies
+ * Rule related:
+   * `showRules()`: show all defined rules (Pool, Block, QPS, addAnyTCRule)
+   * `rmRule(n)`: remove rule n
+   * `mvRule(from, to)`: move rule 'from' to a position where it is in front of 'to'. 'to' can be one larger than the largest rule,
+     in which case the rule will be moved to the last position.
  * Pool related:
    * `addPoolRule(domain, pool)`: send queries to this domain to that pool
    * `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  
-   * `rmPoolRule(n)`: remove rule n
-   * `showPoolRules()`: show the pool rules
    * `getPoolServers(pool)`: return servers part of this pool
  * Server selection policy related:
    * `setServerPolicy(policy)`: set server selection policy to that policy
@@ -413,8 +441,6 @@ Here are all functions:
    * `addQPSLimit({domain, domain}, n)`: limit queries within those domains (together) to n per second
    * `addQPSLimit(netmask, n)`: limit queries within that netmask to n per second
    * `addQPSLimit({netmask, netmask}, n)`: limit queries within those netmasks (together) to n per second   
-   * `rmQPSLimit(n)`: remove QPS limit n
-   * `showQPSLimits()`: outputs QPS limits
  * Advanced functions for writing your own policies and hooks
    * ComboAddress related:
      * `tostring()`: return in human-friendly format
index 0a53ba5521655182b5d0778d7c969aa65fb6c08c..c00264ec604b95d2178b213d15e278d81e0918bc 100644 (file)
@@ -1,4 +1,5 @@
 #include "dnsdist.hh"
+#include "dnsrulactions.hh"
 #include <thread>
 #include "dolog.hh"
 #include "sodcrypto.hh"
@@ -80,7 +81,43 @@ vector<std::function<void(void)>> setupLua(bool client)
                        return ret;
                      } );
 
+  g_lua.writeFunction("addAnyTCRule", []() {
+      auto rules=g_rulactions.getCopy();
+      rules.push_back({ std::make_shared<QTypeRule>(0xff), std::make_shared<TCAction>()});
+      g_rulactions.setState(rules);
+    });
 
+  g_lua.writeFunction("rmRule", [](unsigned int num) {
+      auto rules = g_rulactions.getCopy();
+      if(num >= rules.size()) {
+       g_outputBuffer = "Error: attempt to delete non-existing rule\n";
+       return;
+      }
+      rules.erase(rules.begin()+num);
+      g_rulactions.setState(rules);
+    });
+
+  g_lua.writeFunction("mvRule", [](unsigned int from, unsigned int to) {
+      auto rules = g_rulactions.getCopy();
+      if(from >= rules.size() || to > rules.size()) {
+       g_outputBuffer = "Error: attempt to move rules from/to invalid index\n";
+       return;
+      }
+      if(from==to)
+       return;
+
+
+      auto subject = rules[from];
+      rules.erase(rules.begin()+from);
+      if(to == rules.size())
+       rules.push_back(subject);
+      else {
+       if(from < to)
+         --to;
+       rules.insert(rules.begin()+to, subject);
+      }
+      g_rulactions.setState(rules);
+    });
 
 
   g_lua.writeFunction("rmServer", 
@@ -149,9 +186,14 @@ vector<std::function<void(void)>> setupLua(bool client)
 
 
   g_lua.writeFunction("addDomainBlock", [](const std::string& domain) { 
-      g_suffixMatchNodeFilter.modify([domain](SuffixMatchNode& smn) {
-         smn.add(DNSName(domain)); 
-       });
+      SuffixMatchNode smn;
+      smn.add(domain);
+       g_rulactions.modify([smn](decltype(g_rulactions)::value_type& rulactions) {
+           rulactions.push_back({
+                                  std::make_shared<SuffixMatchNodeRule>(smn), 
+                                  std::make_shared<DropAction>()  });
+         });
+
     });
   g_lua.writeFunction("showServers", []() {  
       try {
@@ -216,33 +258,19 @@ vector<std::function<void(void)>> setupLua(bool client)
        }
       }
       if(nmg.empty())
-       g_poolrules.modify([smn, pool](decltype(g_poolrules)::value_type& poolrules) {
-           poolrules.push_back({smn, pool});
+       g_rulactions.modify([smn, pool](decltype(g_rulactions)::value_type& rulactions) {
+           rulactions.push_back({
+                                  std::make_shared<SuffixMatchNodeRule>(smn), 
+                                  std::make_shared<PoolAction>(pool)  });
          });
       else
-       g_poolrules.modify([nmg,pool](decltype(g_poolrules)::value_type& poolrules) {
-         poolrules.push_back({nmg, pool}); 
+       g_rulactions.modify([nmg,pool](decltype(g_rulactions)::value_type& rulactions) {
+           rulactions.push_back({std::make_shared<NetmaskGroupRule>(nmg), 
+                 std::make_shared<PoolAction>(pool)}); 
          });
 
     });
 
-  g_lua.writeFunction("showPoolRules", []() {
-      boost::format fmt("%-3d %-50s %s\n");
-      g_outputBuffer += (fmt % "#" % "Object" % "Pool").str();
-      int num=0;
-      for(const auto& lim : g_poolrules.getCopy()) {  
-       string name;
-       if(auto nmg=boost::get<NetmaskGroup>(&lim.first)) {
-         name=nmg->toString();
-       }
-       else if(auto smn=boost::get<SuffixMatchNode>(&lim.first)) {
-         name=smn->toString(); 
-       }
-       g_outputBuffer += (fmt % num % name % lim.second).str();
-       ++num;
-      }
-    });
-
 
   g_lua.writeFunction("addQPSLimit", [](boost::variant<string,vector<pair<int, string>> > var, int lim) {
       SuffixMatchNode smn;
@@ -263,39 +291,29 @@ vector<std::function<void(void)>> setupLua(bool client)
        }
       }
       if(nmg.empty())
-       g_limiters.modify([smn, lim](decltype(g_limiters)::value_type& limiters) {
-           limiters.push_back({smn, QPSLimiter(lim, lim)});
+       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_limiters.modify([nmg, lim](decltype(g_limiters)::value_type& limiters) {
-           limiters.push_back({nmg, QPSLimiter(lim, lim)}); 
+       g_rulactions.modify([nmg, lim](decltype(g_rulactions)::value_type& rulactions) {
+           rulactions.push_back({std::make_shared<NetmaskGroupRule>(nmg), 
+                 std::make_shared<QPSAction>(lim)}); 
          });
     });
 
-  g_lua.writeFunction("rmQPSLimit", [](int i) {
-      g_limiters.modify([i](decltype(g_limiters)::value_type& limiters) { 
-         limiters.erase(limiters.begin() + i);
-       });
-    });
 
-  g_lua.writeFunction("showQPSLimits", []() {
-      boost::format fmt("%-3d %-50s %7d %8d %8d\n");
-      g_outputBuffer += (fmt % "#" % "Object" % "Lim" % "Passed" % "Blocked").str();
-      int num=0;
-      for(const auto& lim : g_limiters.getCopy()) {  
-       string name;
-       if(auto nmg=boost::get<NetmaskGroup>(&lim.first)) {
-         name=nmg->toString();
-       }
-       else if(auto smn=boost::get<SuffixMatchNode>(&lim.first)) {
-         name=smn->toString(); 
-       }
-       g_outputBuffer += (fmt % num % name % lim.second.getRate() % lim.second.getPassed() % lim.second.getBlocked()).str();
+  g_lua.writeFunction("showRules", []() {
+     boost::format fmt("%-3d %9d %-50s %s\n");
+     g_outputBuffer += (fmt % "#" % "Matches" % "Rule" % "Action").str();
+     int num=0;
+      for(const auto& lim : g_rulactions.getCopy()) {  
+        string name = lim.first->toString();
+       g_outputBuffer += (fmt % num % lim.first->d_matches % name % lim.second->toString()).str();
        ++num;
       }
     });
 
-
   g_lua.writeFunction("getServers", []() {
       vector<pair<int, std::shared_ptr<DownstreamState> > > ret;
       int count=1;
index de7cd2a33367687e43915ba8694bd3f22800900f..934fd814a83cfc5840fa6c96a0a7fa2087285be4 100644 (file)
@@ -33,6 +33,7 @@
 #include "base64.hh"
 #include <fstream>
 #include "sodcrypto.hh"
+#include "dnsrulactions.hh"
 #undef L
 
 /* Known sins:
    lack of help()
    lack of autocomplete
    TCP is a bit wonky and may pick the wrong downstream
+   ringbuffers are on a wing & a prayer because partially unlocked
 */
 
+/* the Rulaction plan
+   Set of Rules, if one matches, it leads to an Action
+   Both rules and actions could conceivably be Lua based. 
+   On the C++ side, both could be inherited from a class Rule and a class Action, 
+   on the Lua side we can't do that. */
+
 namespace po = boost::program_options;
 po::variables_map g_vm;
 using std::atomic;
@@ -90,8 +98,7 @@ vector<ComboAddress> g_locals;
 
    If all downstreams are over QPS, we pick the fastest server */
 
-GlobalStateHolder<vector<pair<boost::variant<SuffixMatchNode,NetmaskGroup>, QPSLimiter> > > g_limiters;
-GlobalStateHolder<vector<pair<boost::variant<SuffixMatchNode,NetmaskGroup>, string> > > g_poolrules;
+GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions;
 Rings g_rings;
 
 GlobalStateHolder<servers_t> g_dstates;
@@ -244,8 +251,6 @@ static void daemonize(void)
   }
 }
 
-GlobalStateHolder<SuffixMatchNode> g_suffixMatchNodeFilter;
-
 ComboAddress g_serverControl{"127.0.0.1:5199"};
 
 
@@ -260,6 +265,8 @@ NumberedServerVector getDownstreamCandidates(const servers_t& servers, const std
   return ret;
 }
 
+
+
 // listens to incoming queries, sends out to downstream servers, noting the intended return path 
 void* udpClientThread(ClientState* cs)
 try
@@ -285,9 +292,8 @@ try
   }
   auto acl = g_ACL.getLocal();
   auto localPolicy = g_policy.getLocal();
-  auto localLimiters = g_limiters.getLocal();
-  auto localPool = g_poolrules.getLocal();
-  auto localMatchNodeFilter = g_suffixMatchNodeFilter.getLocal();
+
+  auto localRulactions = g_rulactions.getLocal();
   auto localServers = g_dstates.getLocal();
   struct msghdr msgh;
   struct iovec iov;
@@ -314,27 +320,7 @@ try
       DNSName qname(packet, len, 12, false, &qtype);
       
       g_rings.queryRing.push_back(qname);
-      
-      bool blocked=false;
-      for(const auto& lim : *localLimiters) {
-       if(auto nmg=boost::get<NetmaskGroup>(&lim.first)) {
-         if(nmg->match(remote) && !lim.second.check()) {
-           blocked=true;
-           break;
-         }
-       }
-       else if(auto smn=boost::get<SuffixMatchNode>(&lim.first)) {
-         if(smn->check(qname) && !lim.second.check()) {
-           blocked=true;
-           break;
-         }
-       }
-      }
-      if(blocked)
-       continue;
-
-
-      
+            
       if(blockFilter) {
        std::lock_guard<std::mutex> lock(g_luamutex);
        
@@ -342,9 +328,39 @@ try
          continue;
       }
       
-      if(localMatchNodeFilter->check(qname))
+
+      DNSAction::Action action=DNSAction::Action::None;
+      string ruleresult;
+      string pool;
+      for(const auto& lr : *localRulactions) {
+       if(lr.first->matches(remote, qname, qtype, dh)) {
+         lr.first->d_matches++;
+         action=(*lr.second)(remote, qname, qtype, dh, &ruleresult);
+         if(action != DNSAction::Action::None)
+           break;
+       }
+      }
+      switch(action) {
+      case DNSAction::Action::Drop:
        continue;
-      
+      case DNSAction::Action::Nxdomain:
+       dh->rcode = RCode::NXDomain;
+       dh->qr=true;
+       break;
+      case DNSAction::Action::Pool: 
+       pool=ruleresult;
+       break;
+
+      case DNSAction::Action::Spoof:
+       ;
+      case DNSAction::Action::HeaderModify:
+       dh->qr=true;
+       break;
+      case DNSAction::Action::Allow:
+      case DNSAction::Action::None:
+       break;
+      }
+
       if(dh->qr) { // something turned it into a response
        ComboAddress dest;
        if(HarvestDestinationAddress(&msgh, &dest)) 
@@ -355,21 +371,6 @@ try
        continue;
       }
 
-      string pool;
-      for(const auto& pr : *localPool) {
-       if(auto nmg=boost::get<NetmaskGroup>(&pr.first)) {
-         if(nmg->match(remote)) {
-           pool=pr.second;
-           break;
-         }
-       }
-       else if(auto smn=boost::get<SuffixMatchNode>(&pr.first)) {
-         if(smn->check(qname)) {
-           pool=pr.second;
-           break;
-         }
-       }
-      }
       DownstreamState* ss = 0;
       auto candidates=getDownstreamCandidates(*localServers, pool);
       auto policy=localPolicy->policy;
index 98d449ffae1f51741c8110220155a67d7ff4f424..cdaacd81459153d46037ee7ab372f8ca5a7d1b63 100644 (file)
@@ -198,6 +198,31 @@ extern std::mutex g_luamutex;
 extern LuaContext g_lua;
 extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
 
+class DNSRule
+{
+public:
+  virtual bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) const =0;
+  virtual string toString() const = 0;
+  mutable std::atomic<uint64_t> d_matches{0};
+};
+
+/* so what could you do: 
+   drop, 
+   fake up nxdomain, 
+   provide actual answer, 
+   allow & and stop processing, 
+   continue processing, 
+   modify header:    (servfail|refused|notimp), set TC=1,
+   send to pool */
+
+class DNSAction
+{
+public:
+  enum class Action { Drop, Nxdomain, Spoof, Allow, HeaderModify, Pool, None};
+  virtual Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const =0;
+  virtual string toString() const = 0;
+};
+
 using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
 typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)> policy_t;
 
@@ -209,9 +234,7 @@ struct ServerPolicy
 
 extern GlobalStateHolder<ServerPolicy> g_policy;
 extern GlobalStateHolder<servers_t> g_dstates;
-extern GlobalStateHolder<vector<pair<boost::variant<SuffixMatchNode,NetmaskGroup>, QPSLimiter> >> g_limiters;
-extern GlobalStateHolder<vector<pair<boost::variant<SuffixMatchNode,NetmaskGroup>, std::string> >> g_poolrules;
-extern GlobalStateHolder<SuffixMatchNode> g_suffixMatchNodeFilter;
+extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions;
 extern GlobalStateHolder<NetmaskGroup> g_ACL;
 
 extern ComboAddress g_serverControl; // not changed during runtime
@@ -234,3 +257,9 @@ std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& serv
 std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
 std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
 std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
+
+template<typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args&&... args)
+{
+    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
index 31a1c043f516c988752c269dda75a689d02df591..6cbc8ea4c0e241121690cc4832f1394f64383708 100644 (file)
@@ -21,6 +21,10 @@ newServer{address="192.168.1.30:5300", pool="abuse"}
 addPoolRule({"ezdns.it.", "xxx."}, "abuse")
 addPoolRule("192.168.1.0/24", "abuse")
 
+addDomainBlock("powerdns.org.")
+addDomainBlock("spectre.")
+addDomainBlock("isis.")
+
 block=newDNSName("powerdns.org.")
 -- called before we distribute a question
 function blockFilter(remote, qname, qtype, dh)
index 0441f20b3512a66f1ef455fe8326d6ad0e4692f0..406030b3b34635b7e77a9e2e0ea913902d629478 100644 (file)
@@ -4,7 +4,7 @@ dnslabeltext.cc: dnslabeltext.rl
        ragel $< -o dnslabeltext.cc
 
 
-EXTRA_DIST=dnslabeltext.rl dnsdistconf.lua
+EXTRA_DIST=dnslabeltext.rl dnsdistconf.lua README.md
 
 bin_PROGRAMS = dnsdist
 dnsdist_SOURCES = \
@@ -15,6 +15,7 @@ dnsdist_SOURCES = \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dnsparser.hh \
+       dnsrulactions.hh \
        dnswriter.cc dnswriter.hh \
        dolog.hh \
        iputils.cc iputils.hh \
index 5e11b4a4c2c4246498f0fb3e623e18a2c30de92f..59ae7b0901571a90375bfc72bf44b958f12de39a 100755 (executable)
@@ -5,6 +5,8 @@ ln -fs ../base32.hh ../base64.hh ../dnsdist.cc ../dnsdist.hh ../dnsdist-lua.cc .
 ../dolog.hh ../iputils.cc ../iputils.hh ../misc.cc ../misc.hh ../namespaces.hh \
 ../pdnsexception.hh ../qtype.cc ../qtype.hh ../sholder.hh ../sodcrypto.cc ../sodcrypto.hh ../sstuff.hh .
 
+ln -fs ../README-dnsdist.md README.md
+
 ln -fs ../dnsdistconf.lua .
 mkdir -p pdns/ext/luawrapper/include
 ln -sf ../../../../../ext/luawrapper/include/LuaContext.hpp pdns/ext/luawrapper/include
diff --git a/pdns/dnsrulactions.hh b/pdns/dnsrulactions.hh
new file mode 100644 (file)
index 0000000..dd8a76e
--- /dev/null
@@ -0,0 +1,144 @@
+#include "dnsdist.hh"
+#include "dnsname.hh"
+
+class NetmaskGroupRule : public DNSRule
+{
+public:
+  NetmaskGroupRule(const NetmaskGroup& nmg) : d_nmg(nmg)
+  {
+
+  }
+  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) const override
+  {
+    return d_nmg.match(remote);
+  }
+
+  string toString() const override
+  {
+    return d_nmg.toString();
+  }
+private:
+  NetmaskGroup d_nmg;
+};
+
+class SuffixMatchNodeRule : public DNSRule
+{
+public:
+  SuffixMatchNodeRule(const SuffixMatchNode& smn) : d_smn(smn)
+  {
+  }
+  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) const override
+  {
+    return d_smn.check(qname);
+  }
+  string toString() const override
+  {
+    return d_smn.toString();
+  }
+private:
+  SuffixMatchNode d_smn;
+};
+
+class QTypeRule : public DNSRule
+{
+public:
+  QTypeRule(uint16_t qtype) : d_qtype(qtype)
+  {
+  }
+  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) const override
+  {
+    return d_qtype == qtype;
+  }
+  string toString() const override
+  {
+    QType qt(d_qtype);
+    return "qtype=="+qt.getName();
+  }
+private:
+  uint16_t d_qtype;
+};
+
+class DropAction : public DNSAction
+{
+public:
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const override
+  {
+    return Action::Drop;
+  }
+  string toString() const override
+  {
+    return "drop";
+  }
+};
+
+class QPSAction : public DNSAction
+{
+public:
+  QPSAction(int limit) : d_qps(limit, limit) 
+  {}
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const override
+  {
+    if(d_qps.check())
+      return Action::Allow;
+    else
+      return Action::Drop;
+  }
+  string toString() const override
+  {
+    return "qps limit to "+std::to_string(d_qps.getRate()); 
+  }
+private:
+  QPSLimiter d_qps;
+};
+
+class PoolAction : public DNSAction
+{
+public:
+  PoolAction(const std::string& pool) : d_pool(pool) {}
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const override
+  {
+    *ruleresult=d_pool;
+    return Action::Pool;
+  }
+  string toString() const override
+  {
+    return "to pool "+d_pool;
+  }
+
+private:
+  string d_pool;
+};
+
+class RCodeAction : public DNSAction
+{
+public:
+  RCodeAction(int rcode) : d_rcode(rcode) {}
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const override
+  {
+    dh->rcode = d_rcode;
+    dh->qr = true; // for good measure
+    return Action::HeaderModify;
+  }
+  string toString() const override
+  {
+    return "set rcode "+std::to_string(d_rcode);
+  }
+
+private:
+  int d_rcode;
+};
+
+class TCAction : public DNSAction
+{
+public:
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const override
+  {
+    dh->tc = true;
+    dh->qr = true; // for good measure
+    return Action::HeaderModify;
+  }
+  string toString() const override
+  {
+    return "tc=1 answer";
+  }
+};
index 7586bcf81dae6d8fd458844da73d33a8076de4fc..f1c37c85535fe2949567827f439f69cc8937c297 100644 (file)
@@ -95,6 +95,20 @@ union ComboAddress {
     }
   };
 
+  struct addressOnlyEqual: public std::binary_function<ComboAddress, ComboAddress, bool>
+  {
+    bool operator()(const ComboAddress& a, const ComboAddress& b) const
+    {
+      if(a.sin4.sin_family != b.sin4.sin_family)
+        return false;
+      if(a.sin4.sin_family == AF_INET)
+        return a.sin4.sin_addr.s_addr == b.sin4.sin_addr.s_addr;
+      else
+        return !memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16);
+    }
+  };
+
+
   socklen_t getSocklen() const
   {
     if(sin4.sin_family == AF_INET)