]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
add DNSSEC selection rule, plus setDNSSECPool() command
authorbert hubert <bert.hubert@netherlabs.nl>
Wed, 18 Mar 2015 07:10:33 +0000 (08:10 +0100)
committerbert hubert <bert.hubert@netherlabs.nl>
Wed, 18 Mar 2015 07:10:33 +0000 (08:10 +0100)
pdns/dnsdist-lua.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistconf.lua
pdns/dnsname.cc
pdns/dnsname.hh
pdns/dnsrulactions.hh

index df473acd875ea914f5c8fd1c8108644775d52ac1..74a5ab6dec1cc371554bb551d89e9dfcbfec060f 100644 (file)
@@ -268,6 +268,12 @@ vector<std::function<void(void)>> setupLua(bool client)
 
     });
 
+  g_lua.writeFunction("setDNSSECPool", [](const std::string& pool) {
+      g_rulactions.modify([pool](decltype(g_rulactions)::value_type& rulactions) {
+         rulactions.push_back({std::make_shared<DNSSECRule>(), 
+               std::make_shared<PoolAction>(pool)}); 
+       });
+    });
 
   g_lua.writeFunction("addQPSLimit", [](boost::variant<string,vector<pair<int, string>> > var, int lim) {
       SuffixMatchNode smn;
@@ -485,6 +491,26 @@ vector<std::function<void(void)>> setupLua(bool client)
   
   g_lua.executeCode(R"(function topQueries(top, labels) for k,v in ipairs(getTopQueries(top,labels)) do show(string.format("%4d  %-40s %4d %4.1f%%",k,v[1],v[2], v[3])) end end)");
 
+
+  g_lua.writeFunction("getResponseRing", []() {
+      decltype(g_rings.respRing) ring;
+      {
+       std::lock_guard<std::mutex> lock(g_rings.respMutex);
+       ring = g_rings.respRing;
+      }
+      vector<std::unordered_map<string, boost::variant<string, unsigned int> > > ret;
+      ret.reserve(ring.size());
+      decltype(ret)::value_type item;
+      for(const auto& r : ring) {
+       item["name"]=r.name.toString();
+       item["qtype"]=r.qtype;
+       item["rcode"]=r.rcode;
+       item["usec"]=r.usec;
+       ret.push_back(item);
+      }
+      return ret;
+    });
+
   g_lua.writeFunction("getTopResponses", [](unsigned int top, unsigned int kind, boost::optional<int> labels) {
       map<DNSName, int> counts;
       unsigned int total=0;
index 4888bd0a8efe690b1d56fbb2dfd34bd852540092..8de15d2465979639ed115638fe59ec53f57ec96c 100644 (file)
@@ -263,6 +263,27 @@ NumberedServerVector getDownstreamCandidates(const servers_t& servers, const std
   return ret;
 }
 
+// goal in life - if you send us a reasonably normal packet, we'll get Z for you, otherwise 0
+int getEDNSZ(const char* packet, unsigned int len)
+{
+  struct dnsheader* dh =(struct dnsheader*)packet;
+
+  if(dh->ancount!=0 && ntohs(dh->arcount)!=1 && dh->nscount!=0)
+    return 0;
+  
+  unsigned int consumed;
+  DNSName qname(packet, len, 12, false, 0, 0, &consumed);
+  int pos = consumed + 4;
+  uint16_t qtype, qclass;
+
+  DNSName aname(packet, len, 12+pos, false, &qtype, &qclass, &consumed);
+  
+  if(qtype!=QType::OPT || 12+pos+consumed+7 >= len)
+    return 0;
+
+  uint8_t* z = (uint8_t*)packet+12+pos+consumed+6;
+  return 0x100 * (*z) + *(z+1);
+}
 
 
 // listens to incoming queries, sends out to downstream servers, noting the intended return path 
@@ -329,10 +350,11 @@ try
       DNSAction::Action action=DNSAction::Action::None;
       string ruleresult;
       string pool;
+
       for(const auto& lr : *localRulactions) {
-       if(lr.first->matches(remote, qname, qtype, dh)) {
+       if(lr.first->matches(remote, qname, qtype, dh, len)) {
          lr.first->d_matches++;
-         action=(*lr.second)(remote, qname, qtype, dh, &ruleresult);
+         action=(*lr.second)(remote, qname, qtype, dh, len, &ruleresult);
          if(action != DNSAction::Action::None)
            break;
        }
@@ -987,6 +1009,8 @@ static char** my_completion( const char * text , int start,  int end)
 }
 }
 
+
+
 int main(int argc, char** argv)
 try
 {
index cdaacd81459153d46037ee7ab372f8ca5a7d1b63..b042558e2752e029f2a372edbec2ec468ed4b22e 100644 (file)
@@ -201,7 +201,7 @@ extern std::string g_outputBuffer; // locking for this is ok, as locked by g_lua
 class DNSRule
 {
 public:
-  virtual bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) const =0;
+  virtual bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const =0;
   virtual string toString() const = 0;
   mutable std::atomic<uint64_t> d_matches{0};
 };
@@ -219,7 +219,7 @@ 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 Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const =0;
   virtual string toString() const = 0;
 };
 
@@ -257,7 +257,7 @@ 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);
-
+int getEDNSZ(const char* packet, unsigned int len);
 template<typename T, typename... Args>
 std::unique_ptr<T> make_unique(Args&&... args)
 {
index 6cbc8ea4c0e241121690cc4832f1394f64383708..e844e6ee783ec0a43d72b5f38b00a142bbdae08c 100644 (file)
@@ -55,9 +55,12 @@ end
 
 -- setServerPolicyLua("luaroundrobin", luaroundrobin)
 
-newServer{address="2001:888:2000:1d::2", pool="auth"}
+xs=newServer{address="2001:888:2000:1d::2", pool="auth"}
 newServer{address="2a01:4f8:110:4389::2", pool="auth"}
 
+xs:addPool("dnssec")
+setDNSSECPool("dnssec")
+
 function splitSetup(servers, remote, qname, qtype, dh)
         if(dh:getRD() == false)
         then
index 8616c7c3a10ad408532d5420ccd0fd2faeeac572..7dc051e0ca57528a8d7b6088cd96b91a1b42745f 100644 (file)
@@ -24,7 +24,7 @@ DNSName::DNSName(const char* p)
 }
 
 // this should be the __only__ dns name parser in PowerDNS. 
-DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass)
+DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed)
 {
   unsigned char labellen;
   const char *opos = pos;
@@ -45,6 +45,8 @@ DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t
     appendRawLabel(string(pos, labellen));
     pos+=labellen;
   }
+  if(consumed)
+    *consumed = pos - opos - offset;
   if(qtype && pos + labellen + 2 <= end)  
     *qtype=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1);
 
@@ -180,3 +182,5 @@ string DNSName::escapeLabel(const std::string& label)
   }
   return ret;
 }
+
+
index b83a183f0eefdf52246cf0d0c3f1bd4bf2abb7ed..ea99a6389d2f63eeb81fc824becfcae117ca888e 100644 (file)
@@ -25,7 +25,7 @@ public:
   DNSName() {}                 //!< Constructs the root name
   DNSName(const char* p);      //!< Constructs from a human formatted, escaped presentation
   DNSName(const std::string& str) : DNSName(str.c_str()) {}   //!< Constructs from a human formatted, escaped presentation
-  DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0); //!< Construct from a DNS Packet, taking the first question
+  DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0, unsigned int* consumed=0); //!< Construct from a DNS Packet, taking the first question
   
   bool isPartOf(const DNSName& rhs) const;   //!< Are we part of the rhs name?
   bool operator==(const DNSName& rhs) const; //!< DNS-native comparison (case insensitive)
@@ -56,6 +56,7 @@ private:
   //  typedef __gnu_cxx::__sso_string string_t;
   typedef std::string string_t;
   string_t d_storage;
+
   static std::string escapeLabel(const std::string& orig);
   static std::string unescapeLabel(const std::string& orig);
 };
index dd8a76e65b9550c82136af4b63d5aa08150cada3..623f345f6d29e1356b09489a2e40deb2b2ab7514 100644 (file)
@@ -8,7 +8,7 @@ public:
   {
 
   }
-  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) const override
+  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
   {
     return d_nmg.match(remote);
   }
@@ -21,13 +21,32 @@ private:
   NetmaskGroup d_nmg;
 };
 
+class DNSSECRule : public DNSRule
+{
+public:
+  DNSSECRule()
+  {
+
+  }
+  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
+  {
+    return dh->cd || (getEDNSZ((const char*)dh, len) & 32768);    // turns out dig sets ad by default..
+  }
+
+  string toString() const override
+  {
+    return "DNSSEC";
+  }
+};
+
+
 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
+  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
   {
     return d_smn.check(qname);
   }
@@ -45,7 +64,7 @@ public:
   QTypeRule(uint16_t qtype) : d_qtype(qtype)
   {
   }
-  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh) const override
+  bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override
   {
     return d_qtype == qtype;
   }
@@ -61,7 +80,7 @@ private:
 class DropAction : public DNSAction
 {
 public:
-  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const override
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const override
   {
     return Action::Drop;
   }
@@ -76,7 +95,7 @@ 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
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const override
   {
     if(d_qps.check())
       return Action::Allow;
@@ -95,7 +114,7 @@ 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
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const override
   {
     *ruleresult=d_pool;
     return Action::Pool;
@@ -113,7 +132,7 @@ 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
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const override
   {
     dh->rcode = d_rcode;
     dh->qr = true; // for good measure
@@ -131,7 +150,7 @@ private:
 class TCAction : public DNSAction
 {
 public:
-  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, string* ruleresult) const override
+  DNSAction::Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const override
   {
     dh->tc = true;
     dh->qr = true; // for good measure