]> granicus.if.org Git - pdns/commitdiff
dnsdist: Add `RDRule()` to match queries with the `RD` flag set
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 28 Dec 2016 15:21:43 +0000 (16:21 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 19 Jan 2017 14:13:08 +0000 (15:13 +0100)
pdns/README-dnsdist.md
pdns/dnsdist-lua2.cc
pdns/dnsrulactions.hh
regression-tests.dnsdist/test_Advanced.py

index 3d62cafb436541698fae1ec7a201cfd9dfee15d2..3d6e10d2d759c22af06c28ecf812c68f4e8cbd1e 100644 (file)
@@ -347,6 +347,7 @@ Rules have selectors and actions. Current selectors are:
  * RE2Rule on query name (optional)
  * Response code
  * Packet requests DNSSEC processing
+ * Packet requests recursion
  * Query received over UDP or TCP
  * Opcode (OpcodeRule)
  * Number of entries in a given section (RecordsCountRule)
@@ -405,6 +406,7 @@ A DNS rule can be:
 
  * an AllRule
  * an AndRule
+ * a DNSSECRule
  * a MaxQPSIPRule
  * a MaxQPSRule
  * a NetmaskGroupRule
@@ -416,6 +418,7 @@ A DNS rule can be:
  * a QNameWireLengthRule
  * a QTypeRule
  * a RCodeRule
+ * a RDRule
  * a RegexRule
  * a RE2Rule
  * a RecordsCountRule
@@ -1327,6 +1330,7 @@ instantiate a server with additional parameters
     * `QNameWireLengthRule(min, max)`: matches if the qname's length on the wire is less than `min` or more than `max` bytes
     * `QTypeRule(qtype)`: matches queries with the specified qtype
     * `RCodeRule(rcode)`: matches queries or responses the specified rcode
+    * `RDRule()`: matches queries with the `RD` flag set
     * `RegexRule(regex)`: matches the query name against the supplied regex
     * `RecordsCountRule(section, minCount, maxCount)`: matches if there is at least `minCount` and at most `maxCount` records in the `section` section
     * `RecordsTypeCountRule(section, type, minCount, maxCount)`: matches if there is at least `minCount` and at most `maxCount` records of type `type` in the `section` section
index 9c66266067acbe4d5b9ef278fcd2c22572876cfe..419e6f9036b1dd8cfbfbca1db12c6e2b941dbc60 100644 (file)
@@ -1154,5 +1154,10 @@ void moreLua(bool client)
           return;
         }
         g_rings.setCapacity(capacity);
-      });    
+      });
+
+    g_lua.writeFunction("RDRule", []() {
+      return std::shared_ptr<DNSRule>(new RDRule());
+    });
+
 }
index 0244cd6ea97773bcdc6315c5d5734bf9b6087fa0..9af98903c661b537755bd00abdd005ae952a1a31 100644 (file)
@@ -579,6 +579,22 @@ private:
   int d_rcode;
 };
 
+class RDRule : public DNSRule
+{
+public:
+  RDRule()
+  {
+  }
+  bool matches(const DNSQuestion* dq) const override
+  {
+    return dq->dh->rd == 1;
+  }
+  string toString() const override
+  {
+    return "rd==1";
+  }
+};
+
 
 class DropAction : public DNSAction
 {
index eb35ed0a37d5b8b634d227c6534da56b538388be..a32e96df6d0b7c79cd990b34345e103c5cc82f8e 100644 (file)
@@ -1330,3 +1330,44 @@ advanced.tests.powerdns.com.
 tests.powerdns.com.
 powerdns.com.
 com.""")
+
+class TestAdvancedRD(DNSDistTest):
+
+    _config_template = """
+    addAction(RDRule(), RCodeAction(dnsdist.REFUSED))
+    newServer{address="127.0.0.1:%s"}
+    """
+
+    def testAdvancedRDRefused(self):
+        """
+        Advanced: RD query is refused
+        """
+        name = 'rd.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        expectedResponse = dns.message.make_response(query)
+        expectedResponse.set_rcode(dns.rcode.REFUSED)
+
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, expectedResponse)
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, expectedResponse)
+
+    def testAdvancedNoRDAllowed(self):
+        """
+        Advanced: No-RD query is allowed
+        """
+        name = 'no-rd.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        query.flags &= ~dns.flags.RD
+        response = dns.message.make_response(query)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        receivedQuery.id = query.id
+        self.assertEquals(receivedQuery, query)
+        self.assertEquals(receivedResponse, response)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        receivedQuery.id = query.id
+        self.assertEquals(receivedQuery, query)
+        self.assertEquals(receivedResponse, response)