]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add missing QPSPoolAction & DNSSECRule. Add missing tests. 3403/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 18 Feb 2016 14:01:23 +0000 (15:01 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 18 Feb 2016 14:01:23 +0000 (15:01 +0100)
QPSPoolAction() and DNSSECRule() are mentioned in the README but
the Lua bindings were missing.
Add missing tests for some actions and rules.
Clean existing tests a bit in the process.

pdns/README-dnsdist.md
pdns/dnsdist-lua.cc
regression-tests.dnsdist/.gitignore
regression-tests.dnsdist/dnscrypt.py
regression-tests.dnsdist/dnsdisttests.py
regression-tests.dnsdist/test_Advanced.py
regression-tests.dnsdist/test_Basics.py
regression-tests.dnsdist/test_DNSCrypt.py
regression-tests.dnsdist/test_EdnsClientSubnet.py

index ea72728bf55e48d8082a6617eda5dbc7a3ab2df9..c71e46f236fbf001c81f150765faa580e93e6295 100644 (file)
@@ -871,18 +871,18 @@ instantiate a server with additional parameters
     * `topRule()`: move the last rule to the first position
  * Built-in Actions for Rules:
     * `AllowAction()`: let these packets go through
-    * `DelayAction()`: delay the response by the specified amount of milliseconds (UDP-only)
+    * `DelayAction(milliseconds)`: delay the response by the specified amount of milliseconds (UDP-only)
     * `DisableValidationAction()`: set the CD bit in the question, let it go through
     * `DropAction()`: drop these packets
     * `LogAction([filename], [binary])`: Log a line for each query, to the specified file if any, to the console (require verbose) otherwise. When logging to a file, the `binary` optional parameter specifies whether we log in binary form (default) or in textual form
     * `NoRecurseAction()`: strip RD bit from the question, let it go through
-    * `PoolAction()`: set the packet into the specified pool
-    * `QPSPoolAction()`: set the packet into the specified pool only if it does not exceed the specified QPS limits
-    * `QPSAction()`: drop these packets if the QPS limits are exceeded
-    * `RCodeAction()`: reply immediatly by turning the query into a response with the specified rcode
+    * `PoolAction(poolname)`: set the packet into the specified pool
+    * `QPSPoolAction(maxqps, poolname)`: set the packet into the specified pool only if it does not exceed the specified QPS limits
+    * `QPSAction(rule, maxqps)`: drop these packets if the QPS limits are exceeded
+    * `RCodeAction(rcode)`: reply immediatly by turning the query into a response with the specified rcode
     * `SkipCacheAction()`: don't lookup the cache for this query, don't store the answer
-    * `SpoofAction()`: forge a response with the specified IPv4 (for an A query) or IPv6 (for an AAAA). If you specify two addresses, the first one should be an IPv4 and will be used for A, the second an IPv6 for an AAAA
-    * `SpoofCNAMEAction()`: forge a response with the specified CNAME value
+    * `SpoofAction(ip[, ip6])`: forge a response with the specified IPv4 (for an A query) or IPv6 (for an AAAA). If you specify two addresses, the first one should be an IPv4 and will be used for A, the second an IPv6 for an AAAA
+    * `SpoofCNAMEAction(cname)`: forge a response with the specified CNAME value
     * `TCAction()`: create answer to query with TC and RD bits set, to move to TCP/IP
  * Specialist rule generators
     * `addAnyTCRule()`: generate TC=1 answers to ANY queries received over UDP, moving them to TCP
index 32fc8328216f99660b384d2de2b3cda467c8b141..eb460531c5e503f6e9481b472f3274ce66c13775 100644 (file)
@@ -565,6 +565,10 @@ vector<std::function<void(void)>> setupLua(bool client, const std::string& confi
       return std::shared_ptr<DNSAction>(new PoolAction(a));
     });
 
+  g_lua.writeFunction("QPSPoolAction", [](int limit, const string& a) {
+      return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
+    });
+
   g_lua.writeFunction("SpoofAction", [](const string& a, boost::optional<string> b) {
       if(b) 
        return std::shared_ptr<DNSAction>(new SpoofAction(ComboAddress(a), ComboAddress(*b)));
@@ -750,6 +754,10 @@ vector<std::function<void(void)>> setupLua(bool client, const std::string& confi
       return std::shared_ptr<DNSRule>(new TCPRule(tcp));
     });
 
+  g_lua.writeFunction("DNSSECRule", []() {
+      return std::shared_ptr<DNSRule>(new DNSSECRule());
+    });
+
   g_lua.writeFunction("NotRule", [](std::shared_ptr<DNSRule>rule) {
       return std::shared_ptr<DNSRule>(new NotRule(rule));
     });
index 8fda00e5322049d3873d7498085b9124d4ff7d57..01023369295f7ebdeacfb0642999d25c0aa81c20 100644 (file)
@@ -6,3 +6,4 @@ dnsdist_*.conf
 DNSCryptResolver*
 .dnsdist_history
 .history
+dnsdist.log
\ No newline at end of file
index 82957c50ebf5bbb2f26e7cac5e8734c79f14414e..60070bb4e59cd788d8c912577c358165f6bf479c 100644 (file)
@@ -40,8 +40,8 @@ class DNSCryptResolverCertificate:
         resolverPK = orig[0:32]
         clientMagic = orig[32:40]
         serial = struct.unpack_from("I", orig[40:44])
-        validFrom = struct.unpack_from("!I", orig[44:48])[0];
-        validUntil = struct.unpack_from("!I", orig[48:52])[0];
+        validFrom = struct.unpack_from("!I", orig[44:48])[0]
+        validUntil = struct.unpack_from("!I", orig[48:52])[0]
         return DNSCryptResolverCertificate(serial, validFrom, validUntil, resolverPK, clientMagic)
 
 class DNSCryptClient:
@@ -104,7 +104,7 @@ class DNSCryptClient:
         for item in an.items:
             if len(item.strings) != 1:
                 continue
-            
+
             cert = DNSCryptResolverCertificate.fromBinary(item.strings[0], self._providerFingerprint)
             if cert.isValid():
                 self._resolverCertificates.append(cert)
index 93a19d949a52fa8c15967ea376770650e189be1c..e2c4b229312f5f2c5eb677cb9537279a032baf94 100644 (file)
@@ -1,9 +1,6 @@
 #!/usr/bin/env python2
 
-import clientsubnetoption
 import copy
-import dns
-import dns.message
 import Queue
 import os
 import socket
@@ -13,7 +10,8 @@ import sys
 import threading
 import time
 import unittest
-import random
+import dns
+import dns.message
 
 
 class DNSDistTest(unittest.TestCase):
@@ -30,9 +28,10 @@ class DNSDistTest(unittest.TestCase):
     _toResponderQueue = Queue.Queue()
     _fromResponderQueue = Queue.Queue()
     _queueTimeout = 1
-    _dnsdistStartupDelay = 2
+    _dnsdistStartupDelay = 2.0
     _dnsdist = None
     _responsesCounter = {}
+    _shutUp = True
     _config_template = """
     newServer{address="127.0.0.1:%s"}
     truncateTC(true)
@@ -110,7 +109,7 @@ class DNSDistTest(unittest.TestCase):
     def setUpClass(cls):
 
         cls.startResponders()
-        cls.startDNSDist()
+        cls.startDNSDist(cls._shutUp)
         cls.setUpSockets()
 
         print("Launching tests..")
@@ -120,7 +119,7 @@ class DNSDistTest(unittest.TestCase):
         if 'DNSDIST_FAST_TESTS' in os.environ:
             delay = 0.1
         else:
-            delay = 1
+            delay = 1.0
         if cls._dnsdist:
             cls._dnsdist.terminate()
             if cls._dnsdist.poll() is None:
@@ -195,7 +194,7 @@ class DNSDistTest(unittest.TestCase):
         sock.listen(100)
         while True:
             answered = False
-            (conn, address) = sock.accept()
+            (conn, _) = sock.accept()
             conn.settimeout(2.0)
             data = conn.recv(2)
             (datalen,) = struct.unpack("!H", data)
@@ -250,7 +249,7 @@ class DNSDistTest(unittest.TestCase):
         try:
             cls._sock.send(query.to_wire())
             data = cls._sock.recv(4096)
-        except socket.timeout as e:
+        except socket.timeout:
             data = None
         finally:
             if timeout:
index de6f997a70139aa83b92e38970ac9edbb590ebf9..64bda343123dd2abf3aacff5474ee2a1657e70ce 100644 (file)
@@ -1,13 +1,64 @@
 #!/usr/bin/env python
 from datetime import datetime, timedelta
-import dns
 import os
-import subprocess
 import threading
 import time
-import unittest
+import dns
 from dnsdisttests import DNSDistTest
 
+class TestAdvancedAllow(DNSDistTest):
+
+    _config_template = """
+    addAction(makeRule("allowed.advanced.tests.powerdns.com."), AllowAction())
+    addAction(AllRule(), DropAction())
+    newServer{address="127.0.0.1:%s"}
+    """
+
+    def testAdvancedAllow(self):
+        """
+        Advanced: Allowed qname is not dropped
+
+        A query for allowed.advanced.tests.powerdns.com. should be allowed
+        while others should be dropped.
+        """
+        name = 'allowed.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+    def testAdvancedAllowDropped(self):
+        """
+        Advanced: Not allowed qname is dropped
+
+        A query for notallowed.advanced.tests.powerdns.com. should be dropped.
+        """
+        name = 'notallowed.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, None)
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, None)
+
 class TestAdvancedFixupCase(DNSDistTest):
 
     _config_template = """
@@ -130,6 +181,7 @@ class TestAdvancedAddCD(DNSDistTest):
 
     _config_template = """
     addDisableValidationRule("setcd.advanced.tests.powerdns.com.")
+    addAction(makeRule("setcdviaaction.advanced.tests.powerdns.com."), DisableValidationAction())
     newServer{address="127.0.0.1:%s"}
     """
 
@@ -142,7 +194,41 @@ class TestAdvancedAddCD(DNSDistTest):
         """
         name = 'setcd.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
-        expectedQuery = dns.message.make_query(name.lower(), 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery.flags |= dns.flags.CD
+
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = expectedQuery.id
+        self.assertEquals(expectedQuery, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = expectedQuery.id
+        self.assertEquals(expectedQuery, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+    def testAdvancedSetCDViaAction(self):
+        """
+        Advanced: Set CD via Action
+
+        Send a query with CD cleared,
+        check that dnsdist set the CD flag.
+        """
+        name = 'setcdviaaction.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, 'A', 'IN')
         expectedQuery.flags |= dns.flags.CD
 
         response = dns.message.make_response(query)
@@ -199,11 +285,121 @@ class TestAdvancedAddCD(DNSDistTest):
         self.assertEquals(query, receivedQuery)
         self.assertEquals(response, receivedResponse)
 
+class TestAdvancedClearRD(DNSDistTest):
+
+    _config_template = """
+    addNoRecurseRule("clearrd.advanced.tests.powerdns.com.")
+    addAction(makeRule("clearrdviaaction.advanced.tests.powerdns.com."), NoRecurseAction())
+    newServer{address="127.0.0.1:%s"}
+    """
+
+    def testAdvancedClearRD(self):
+        """
+        Advanced: Clear RD
+
+        Send a query with RD set,
+        check that dnsdist clears the RD flag.
+        """
+        name = 'clearrd.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery.flags &= ~dns.flags.RD
+
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = expectedQuery.id
+        self.assertEquals(expectedQuery, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = expectedQuery.id
+        self.assertEquals(expectedQuery, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+    def testAdvancedClearRDViaAction(self):
+        """
+        Advanced: Clear RD via Action
+
+        Send a query with RD set,
+        check that dnsdist clears the RD flag.
+        """
+        name = 'clearrdviaaction.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery = dns.message.make_query(name, 'A', 'IN')
+        expectedQuery.flags &= ~dns.flags.RD
+
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = expectedQuery.id
+        self.assertEquals(expectedQuery, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = expectedQuery.id
+        self.assertEquals(expectedQuery, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+    def testAdvancedKeepRD(self):
+        """
+        Advanced: Preserve RD canary
+
+        Send a query with RD for a canary domain,
+        check that dnsdist does not clear the RD flag.
+        """
+        name = 'keeprd.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
 class TestAdvancedSpoof(DNSDistTest):
 
     _config_template = """
-    addDomainSpoof("spoof.tests.powerdns.com.", "192.0.2.1", "2001:DB8::1")
-    addDomainCNAMESpoof("cnamespoof.tests.powerdns.com.", "cname.tests.powerdns.com.")
+    addDomainSpoof("spoof.advanced.tests.powerdns.com.", "192.0.2.1", "2001:DB8::1")
+    addDomainCNAMESpoof("cnamespoof.advanced.tests.powerdns.com.", "cname.advanced.tests.powerdns.com.")
+    addAction(makeRule("spoofaction.advanced.tests.powerdns.com."), SpoofAction("192.0.2.1", "2001:DB8::1"))
+    addAction(makeRule("cnamespoofaction.advanced.tests.powerdns.com."), SpoofCNAMEAction("cnameaction.advanced.tests.powerdns.com."))
     newServer{address="127.0.0.1:%s"}
     """
 
@@ -211,10 +407,10 @@ class TestAdvancedSpoof(DNSDistTest):
         """
         Advanced: Spoof A
 
-        Send an A query to "spoof.tests.powerdns.com.",
+        Send an A query to "spoof.advanced.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'spoof.tests.powerdns.com.'
+        name = 'spoof.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -238,10 +434,10 @@ class TestAdvancedSpoof(DNSDistTest):
         """
         Advanced: Spoof AAAA
 
-        Send an AAAA query to "spoof.tests.powerdns.com.",
+        Send an AAAA query to "spoof.advanced.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'spoof.tests.powerdns.com.'
+        name = 'spoof.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -265,10 +461,10 @@ class TestAdvancedSpoof(DNSDistTest):
         """
         Advanced: Spoof CNAME
 
-        Send an A query for "cnamespoof.tests.powerdns.com.",
+        Send an A query for "cnamespoof.advanced.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'cnamespoof.tests.powerdns.com.'
+        name = 'cnamespoof.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -277,7 +473,88 @@ class TestAdvancedSpoof(DNSDistTest):
                                     60,
                                     dns.rdataclass.IN,
                                     dns.rdatatype.CNAME,
-                                    'cname.tests.powerdns.com.')
+                                    'cname.advanced.tests.powerdns.com.')
+        expectedResponse.answer.append(rrset)
+
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertTrue(receivedResponse)
+        self.assertEquals(expectedResponse, receivedResponse)
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        self.assertTrue(receivedResponse)
+        self.assertEquals(expectedResponse, receivedResponse)
+
+    def testSpoofActionA(self):
+        """
+        Advanced: Spoof A via Action
+
+        Send an A query to "spoofaction.advanced.tests.powerdns.com.",
+        check that dnsdist sends a spoofed result.
+        """
+        name = 'spoofaction.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+        expectedResponse = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '192.0.2.1')
+        expectedResponse.answer.append(rrset)
+
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertTrue(receivedResponse)
+        self.assertEquals(expectedResponse, receivedResponse)
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        self.assertTrue(receivedResponse)
+        self.assertEquals(expectedResponse, receivedResponse)
+
+    def testSpoofActionAAAA(self):
+        """
+        Advanced: Spoof AAAA via Action
+
+        Send an AAAA query to "spoofaction.advanced.tests.powerdns.com.",
+        check that dnsdist sends a spoofed result.
+        """
+        name = 'spoofaction.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+        expectedResponse = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.AAAA,
+                                    '2001:DB8::1')
+        expectedResponse.answer.append(rrset)
+
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertTrue(receivedResponse)
+        self.assertEquals(expectedResponse, receivedResponse)
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        self.assertTrue(receivedResponse)
+        self.assertEquals(expectedResponse, receivedResponse)
+
+    def testSpoofActionCNAME(self):
+        """
+        Advanced: Spoof CNAME via Action
+
+        Send an A query for "cnamespoofaction.advanced.tests.powerdns.com.",
+        check that dnsdist sends a spoofed result.
+        """
+        name = 'cnamespoofaction.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        # dnsdist set RA = RD for spoofed responses
+        query.flags &= ~dns.flags.RD
+        expectedResponse = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.CNAME,
+                                    'cnameaction.advanced.tests.powerdns.com.')
         expectedResponse.answer.append(rrset)
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
@@ -292,17 +569,47 @@ class TestAdvancedPoolRouting(DNSDistTest):
 
     _config_template = """
     newServer{address="127.0.0.1:%s", pool="real"}
-    addPoolRule("pool.tests.powerdns.com", "real")
+    addPoolRule("pool.advanced.tests.powerdns.com", "real")
+    addAction(makeRule("poolaction.advanced.tests.powerdns.com"), PoolAction("real"))
+    addQPSPoolRule("qpspool.advanced.tests.powerdns.com", 10, "abuse")
+    addAction(makeRule("qpspoolaction.advanced.tests.powerdns.com"), QPSPoolAction(10, "abuse"))
     """
 
     def testPolicyPool(self):
         """
         Advanced: Set pool by qname
 
-        Send an A query to "pool.tests.powerdns.com.",
+        Send an A query to "pool.advanced.tests.powerdns.com.",
         check that dnsdist routes the query to the "real" pool.
         """
-        name = 'pool.tests.powerdns.com.'
+        name = 'pool.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '192.0.2.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        receivedQuery.id = query.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        receivedQuery.id = query.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+    def testPolicyPoolAction(self):
+        """
+        Advanced: Set pool by qname via PoolAction
+
+        Send an A query to "poolaction.advanced.tests.powerdns.com.",
+        check that dnsdist routes the query to the "real" pool.
+        """
+        name = 'pool.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -326,11 +633,11 @@ class TestAdvancedPoolRouting(DNSDistTest):
         """
         Advanced: Set pool by qname canary
 
-        Send an A query to "notpool.tests.powerdns.com.",
+        Send an A query to "notpool.advanced.tests.powerdns.com.",
         check that dnsdist sends no response (no servers
         in the default pool).
         """
-        name = 'notpool.tests.powerdns.com.'
+        name = 'notpool.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
@@ -339,6 +646,100 @@ class TestAdvancedPoolRouting(DNSDistTest):
         (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
         self.assertEquals(receivedResponse, None)
 
+class TestAdvancedQPSPoolRouting(DNSDistTest):
+    _config_template = """
+    newServer{address="127.0.0.1:%s", pool="regular"}
+    addQPSPoolRule("qpspool.advanced.tests.powerdns.com", 10, "regular")
+    addAction(makeRule("qpspoolaction.advanced.tests.powerdns.com"), QPSPoolAction(10, "regular"))
+    """
+
+    def testQPSPool(self):
+        """
+        Advanced: Set pool by QPS
+
+        Send queries to "qpspool.advanced.tests.powerdns.com."
+        check that dnsdist does not route the query to the "regular" pool
+        when the max QPS has been reached.
+        """
+        maxQPS = 10
+        name = 'qpspool.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '192.0.2.1')
+        response.answer.append(rrset)
+
+        for _ in range(maxQPS):
+            (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+            receivedQuery.id = query.id
+            self.assertEquals(query, receivedQuery)
+            self.assertEquals(response, receivedResponse)
+
+        # we should now be sent to the "abuse" pool which is empty,
+        # so the queries should be dropped
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, None)
+
+        time.sleep(1)
+
+        # again, over TCP this time
+        for _ in range(maxQPS):
+            (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+            receivedQuery.id = query.id
+            self.assertEquals(query, receivedQuery)
+            self.assertEquals(response, receivedResponse)
+
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, None)
+
+    def testQPSPoolAction(self):
+        """
+        Advanced: Set pool by QPS via action
+
+        Send queries to "qpspoolaction.advanced.tests.powerdns.com."
+        check that dnsdist does not route the query to the "regular" pool
+        when the max QPS has been reached.
+        """
+        maxQPS = 10
+        name = 'qpspoolaction.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '192.0.2.1')
+        response.answer.append(rrset)
+
+        for _ in range(maxQPS):
+            (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+            receivedQuery.id = query.id
+            self.assertEquals(query, receivedQuery)
+            self.assertEquals(response, receivedResponse)
+
+        # we should now be sent to the "abuse" pool which is empty,
+        # so the queries should be dropped
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, None)
+
+        time.sleep(1)
+
+        # again, over TCP this time
+        for _ in range(maxQPS):
+            (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+            receivedQuery.id = query.id
+            self.assertEquals(query, receivedQuery)
+            self.assertEquals(response, receivedResponse)
+
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        self.assertEquals(receivedResponse, None)
+
+
 class TestAdvancedRoundRobinLB(DNSDistTest):
 
     _testServer2Port = 5351
@@ -373,11 +774,11 @@ class TestAdvancedRoundRobinLB(DNSDistTest):
         """
         Advanced: Round Robin
 
-        Send 100 A queries to "rr.tests.powerdns.com.",
+        Send 100 A queries to "rr.advanced.tests.powerdns.com.",
         check that dnsdist routes half of it to each backend.
         """
         numberOfQueries = 10
-        name = 'rr.tests.powerdns.com.'
+        name = 'rr.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -389,13 +790,13 @@ class TestAdvancedRoundRobinLB(DNSDistTest):
 
         # the round robin counter is shared for UDP and TCP,
         # so we need to do UDP then TCP to have a clean count
-        for idx in range(numberOfQueries):
+        for _ in range(numberOfQueries):
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
             receivedQuery.id = query.id
             self.assertEquals(query, receivedQuery)
             self.assertEquals(response, receivedResponse)
 
-        for idx in range(numberOfQueries):
+        for _ in range(numberOfQueries):
             (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
             receivedQuery.id = query.id
             self.assertEquals(query, receivedQuery)
@@ -421,11 +822,11 @@ class TestAdvancedRoundRobinLBOneDown(DNSDistTest):
         """
         Advanced: Round Robin with one server down
 
-        Send 100 A queries to "rr.tests.powerdns.com.",
+        Send 100 A queries to "rr.advanced.tests.powerdns.com.",
         check that dnsdist routes all of it to the only backend up.
         """
         numberOfQueries = 10
-        name = 'rr.tests.powerdns.com.'
+        name = 'rr.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -437,21 +838,21 @@ class TestAdvancedRoundRobinLBOneDown(DNSDistTest):
 
         # the round robin counter is shared for UDP and TCP,
         # so we need to do UDP then TCP to have a clean count
-        for idx in range(numberOfQueries):
+        for _ in range(numberOfQueries):
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
             receivedQuery.id = query.id
             self.assertEquals(query, receivedQuery)
             self.assertEquals(response, receivedResponse)
 
-        for idx in range(numberOfQueries):
+        for _ in range(numberOfQueries):
             (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
             receivedQuery.id = query.id
             self.assertEquals(query, receivedQuery)
             self.assertEquals(response, receivedResponse)
 
         total = 0
-        for key in TestAdvancedRoundRobinLB._responsesCounter:
-            value = TestAdvancedRoundRobinLB._responsesCounter[key]
+        for key in TestAdvancedRoundRobinLBOneDown._responsesCounter:
+            value = TestAdvancedRoundRobinLBOneDown._responsesCounter[key]
             self.assertTrue(value == numberOfQueries or value == 0)
             total += value
 
@@ -512,7 +913,7 @@ class TestAdvancedDelay(DNSDistTest):
         receivedQuery.id = query.id
         self.assertEquals(query, receivedQuery)
         self.assertEquals(response, receivedResponse)
-        self.assertTrue((end - begin) > timedelta(0, 1));
+        self.assertTrue((end - begin) > timedelta(0, 1))
 
         begin = datetime.now()
         (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
@@ -520,7 +921,7 @@ class TestAdvancedDelay(DNSDistTest):
         receivedQuery.id = query.id
         self.assertEquals(query, receivedQuery)
         self.assertEquals(response, receivedResponse)
-        self.assertTrue((end - begin) < timedelta(0, 1));
+        self.assertTrue((end - begin) < timedelta(0, 1))
 
 class TestAdvancedLuaSpoof(DNSDistTest):
 
@@ -537,10 +938,10 @@ class TestAdvancedLuaSpoof(DNSDistTest):
         end
     end
     function spoof2rule(dq)
-        return DNSAction.Spoof, "spoofedcname.tests.powerdns.com."
+        return DNSAction.Spoof, "spoofedcname.advanced.tests.powerdns.com."
     end
-    addLuaAction("luaspoof1.tests.powerdns.com.", spoof1rule)
-    addLuaAction("luaspoof2.tests.powerdns.com.", spoof2rule)
+    addLuaAction("luaspoof1.advanced.tests.powerdns.com.", spoof1rule)
+    addLuaAction("luaspoof2.advanced.tests.powerdns.com.", spoof2rule)
     newServer{address="127.0.0.1:%s"}
     """
 
@@ -548,10 +949,10 @@ class TestAdvancedLuaSpoof(DNSDistTest):
         """
         Advanced: Spoofing an A via Lua
 
-        Send an A query to "luaspoof1.tests.powerdns.com.",
+        Send an A query to "luaspoof1.advanced.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof1.tests.powerdns.com.'
+        name = 'luaspoof1.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -575,10 +976,10 @@ class TestAdvancedLuaSpoof(DNSDistTest):
         """
         Advanced: Spoofing an AAAA via Lua
 
-        Send an AAAA query to "luaspoof1.tests.powerdns.com.",
+        Send an AAAA query to "luaspoof1.advanced.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof1.tests.powerdns.com.'
+        name = 'luaspoof1.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -602,10 +1003,10 @@ class TestAdvancedLuaSpoof(DNSDistTest):
         """
         Advanced: Spoofing an A with a CNAME via Lua
 
-        Send an A query to "luaspoof2.tests.powerdns.com.",
+        Send an A query to "luaspoof2.advanced.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof2.tests.powerdns.com.'
+        name = 'luaspoof2.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -614,7 +1015,7 @@ class TestAdvancedLuaSpoof(DNSDistTest):
                                     60,
                                     dns.rdataclass.IN,
                                     dns.rdatatype.CNAME,
-                                    'spoofedcname.tests.powerdns.com.')
+                                    'spoofedcname.advanced.tests.powerdns.com.')
         expectedResponse.answer.append(rrset)
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
@@ -629,10 +1030,10 @@ class TestAdvancedLuaSpoof(DNSDistTest):
         """
         Advanced: Spoofing an AAAA with a CNAME via Lua
 
-        Send an AAAA query to "luaspoof2.tests.powerdns.com.",
+        Send an AAAA query to "luaspoof2.advanced.tests.powerdns.com.",
         check that dnsdist sends a spoofed result.
         """
-        name = 'luaspoof2.tests.powerdns.com.'
+        name = 'luaspoof2.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         # dnsdist set RA = RD for spoofed responses
         query.flags &= ~dns.flags.RD
@@ -641,7 +1042,7 @@ class TestAdvancedLuaSpoof(DNSDistTest):
                                     60,
                                     dns.rdataclass.IN,
                                     dns.rdatatype.CNAME,
-                                    'spoofedcname.tests.powerdns.com.')
+                                    'spoofedcname.advanced.tests.powerdns.com.')
         expectedResponse.answer.append(rrset)
 
         (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
@@ -663,11 +1064,11 @@ class TestAdvancedTruncateAnyAndTCP(DNSDistTest):
         """
         Advanced: Truncate ANY over TCP
 
-        Send an ANY query to "anytruncatetcp.tests.powerdns.com.",
+        Send an ANY query to "anytruncatetcp.advanced.tests.powerdns.com.",
         should be truncated over TCP, not over UDP (yes, it makes no sense,
         deal with it).
         """
-        name = 'anytruncatetcp.tests.powerdns.com.'
+        name = 'anytruncatetcp.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'ANY', 'IN')
 
         response = dns.message.make_response(query)
@@ -707,7 +1108,7 @@ class TestAdvancedAndNot(DNSDistTest):
         We send an A query over UDP and TCP, and check that the
         response is OK.
         """
-        name = 'andnot.tests.powerdns.com.'
+        name = 'andnot.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -740,7 +1141,7 @@ class TestAdvancedAndNot(DNSDistTest):
         We send a TXT query over UDP and TCP, and check that the
         response is OK for TCP and 'not implemented' for UDP.
         """
-        name = 'andnot.tests.powerdns.com.'
+        name = 'andnot.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'TXT', 'IN')
 
         expectedResponse = dns.message.make_response(query)
@@ -779,7 +1180,7 @@ class TestAdvancedOr(DNSDistTest):
         We send an AAAA query over UDP and TCP, and check that the
         response is 'not implemented' for UDP and OK for TCP.
         """
-        name = 'aorudp.tests.powerdns.com.'
+        name = 'aorudp.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -811,7 +1212,7 @@ class TestAdvancedOr(DNSDistTest):
         We send an A query over UDP and TCP, and check that the
         response is 'not implemented' for both.
         """
-        name = 'aorudp.tests.powerdns.com.'
+        name = 'aorudp.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN')
 
         expectedResponse = dns.message.make_response(query)
@@ -828,7 +1229,7 @@ class TestAdvancedCaching(DNSDistTest):
     _config_template = """
     pc = newPacketCache(5, 86400, 1)
     getPool(""):setCache(pc)
-    addAction(makeRule("nocache.tests.powerdns.com."), SkipCacheAction())
+    addAction(makeRule("nocache.advanced.tests.powerdns.com."), SkipCacheAction())
     newServer{address="127.0.0.1:%s"}
     """
     def testCached(self):
@@ -840,7 +1241,7 @@ class TestAdvancedCaching(DNSDistTest):
         the first one.
         """
         numberOfQueries = 10
-        name = 'cached.tests.powerdns.com.'
+        name = 'cached.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -859,7 +1260,7 @@ class TestAdvancedCaching(DNSDistTest):
         self.assertEquals(query, receivedQuery)
         self.assertEquals(receivedResponse, response)
 
-        for idx in range(numberOfQueries):
+        for _ in range(numberOfQueries):
             (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
             receivedResponse.id = response.id
             self.assertEquals(receivedResponse, response)
@@ -878,10 +1279,10 @@ class TestAdvancedCaching(DNSDistTest):
         """
         Advanced: SkipCacheAction
 
-        dnsdist is configured to not cache entries for nocache.tests.powerdns.com.
+        dnsdist is configured to not cache entries for nocache.advanced.tests.powerdns.com.
          we are sending several requests and checking that the backend get them all.
         """
-        name = 'nocache.tests.powerdns.com.'
+        name = 'nocache.advanced.tests.powerdns.com.'
         numberOfQueries = 10
         query = dns.message.make_query(name, 'AAAA', 'IN')
         response = dns.message.make_response(query)
@@ -892,7 +1293,7 @@ class TestAdvancedCaching(DNSDistTest):
                                     '::1')
         response.answer.append(rrset)
 
-        for idx in range(numberOfQueries):
+        for _ in range(numberOfQueries):
             (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
             self.assertTrue(receivedQuery)
             self.assertTrue(receivedResponse)
@@ -924,7 +1325,7 @@ class TestAdvancedCaching(DNSDistTest):
         """
         ttl = 2
         misses = 0
-        name = 'cacheexpiration.tests.powerdns.com.'
+        name = 'cacheexpiration.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -981,6 +1382,81 @@ class TestAdvancedCaching(DNSDistTest):
 
         self.assertEquals(total, misses)
 
+    def testCacheExpirationDifferentSets(self):
+        """
+        Advanced: Cache expiration with different sets
+
+        dnsdist is configured to cache entries, we are sending one request
+        (cache miss) whose response has a long and a very short TTL,
+        checking that the next requests are cached. Then we wait for the
+        short TTL to expire, check that the
+        next request is a miss but the following one a hit.
+        """
+        ttl = 2
+        misses = 0
+        name = 'cacheexpirationdifferentsets.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    ttl,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.CNAME,
+                                    'cname.cacheexpirationdifferentsets.advanced.tests.powerdns.com.')
+        response.answer.append(rrset)
+        rrset = dns.rrset.from_text('cname.cacheexpirationdifferentsets.advanced.tests.powerdns.com.',
+                                    ttl + 3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '192.2.0.1')
+        response.additional.append(rrset)
+
+        # first query to fill the cache
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(receivedResponse, response)
+        misses += 1
+
+        # next queries should hit the cache
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        receivedResponse.id = response.id
+        self.assertEquals(receivedResponse, response)
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        receivedResponse.id = response.id
+        self.assertEquals(receivedResponse, response)
+
+        # now we wait a bit for the cache entry to expire
+        time.sleep(ttl + 1)
+
+        # next query should be a miss, fill the cache again
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(receivedResponse, response)
+        misses += 1
+
+        # following queries should hit the cache again
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        receivedResponse.id = response.id
+        self.assertEquals(receivedResponse, response)
+
+        (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
+        receivedResponse.id = response.id
+        self.assertEquals(receivedResponse, response)
+
+        total = 0
+        for key in TestAdvancedCaching._responsesCounter:
+            total += TestAdvancedCaching._responsesCounter[key]
+
+        self.assertEquals(total, misses)
+
     def testCacheDecreaseTTL(self):
         """
         Advanced: Cache decreases TTL
@@ -990,7 +1466,7 @@ class TestAdvancedCaching(DNSDistTest):
         """
         ttl = 600
         misses = 0
-        name = 'cachedecreasettl.tests.powerdns.com.'
+        name = 'cachedecreasettl.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -1054,8 +1530,8 @@ class TestAdvancedCaching(DNSDistTest):
         matches.
         """
         ttl = 600
-        name = 'cachedifferentcase.tests.powerdns.com.'
-        differentCaseName = 'CacheDifferentCASE.tests.powerdns.com.'
+        name = 'cachedifferentcase.advanced.tests.powerdns.com.'
+        differentCaseName = 'CacheDifferentCASE.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'AAAA', 'IN')
         differentCaseQuery = dns.message.make_query(differentCaseName, 'AAAA', 'IN')
         response = dns.message.make_response(query)
@@ -1102,7 +1578,7 @@ class TestAdvancedCachingWithExistingEDNS(DNSDistTest):
         Payload size is not served from the cache.
         """
         misses = 0
-        name = 'cachedifferentedns.tests.powerdns.com.'
+        name = 'cachedifferentedns.advanced.tests.powerdns.com.'
         query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512)
         response = dns.message.make_response(query)
         rrset = dns.rrset.from_text(name,
@@ -1140,7 +1616,141 @@ class TestAdvancedCachingWithExistingEDNS(DNSDistTest):
         misses += 1
 
         total = 0
-        for key in TestAdvancedCaching._responsesCounter:
-            total += TestAdvancedCaching._responsesCounter[key]
+        for key in TestAdvancedCachingWithExistingEDNS._responsesCounter:
+            total += TestAdvancedCachingWithExistingEDNS._responsesCounter[key]
 
         self.assertEquals(total, misses)
+
+class TestAdvancedLogAction(DNSDistTest):
+
+    _config_template = """
+    newServer{address="127.0.0.1:%s"}
+    addAction(AllRule(), LogAction("dnsdist.log", false))
+    """
+    def testAdvancedLogAction(self):
+        """
+        Advanced: Log all queries
+
+        """
+        count = 50
+        name = 'logaction.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        for _ in range(count):
+            (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+            self.assertTrue(receivedQuery)
+            self.assertTrue(receivedResponse)
+            receivedQuery.id = query.id
+            receivedResponse.id = response.id
+            self.assertEquals(query, receivedQuery)
+            self.assertEquals(response, receivedResponse)
+
+        self.assertTrue(os.path.isfile('dnsdist.log'))
+        self.assertTrue(os.stat('dnsdist.log').st_size > 0)
+
+class TestAdvancedDNSSEC(DNSDistTest):
+
+    _config_template = """
+    newServer{address="127.0.0.1:%s"}
+    addAction(DNSSECRule(), DropAction())
+    """
+    def testAdvancedDNSSECDrop(self):
+        """
+        Advanced: DNSSEC Rule
+
+        """
+        name = 'dnssec.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        doquery = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (_, receivedResponse) = self.sendUDPQuery(doquery, response)
+        self.assertEquals(receivedResponse, None)
+        (_, receivedResponse) = self.sendTCPQuery(doquery, response)
+        self.assertEquals(receivedResponse, None)
+
+class TestAdvancedQClass(DNSDistTest):
+
+    _config_template = """
+    newServer{address="127.0.0.1:%s"}
+    addAction(QClassRule(3), DropAction())
+    """
+    def testAdvancedQClassChaosDrop(self):
+        """
+        Advanced: Drop QClass CHAOS
+
+        """
+        name = 'qclasschaos.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'TXT', 'CHAOS')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.CH,
+                                    dns.rdatatype.TXT,
+                                    'hop')
+        response.answer.append(rrset)
+
+        (_, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertEquals(receivedResponse, None)
+        (_, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertEquals(receivedResponse, None)
+
+    def testAdvancedQClassINAllow(self):
+        """
+        Advanced: Allow QClass IN
+
+        """
+        name = 'qclassin.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
+
+        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
+        self.assertTrue(receivedQuery)
+        self.assertTrue(receivedResponse)
+        receivedQuery.id = query.id
+        receivedResponse.id = response.id
+        self.assertEquals(query, receivedQuery)
+        self.assertEquals(response, receivedResponse)
index 7e191100b413f9044bce820769ce8b15322a14eb..73cc3cb6c24862a8a9518dc1a04bb68e2aa523c4 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
-import clientsubnetoption
-import dns
 import unittest
+import dns
+import clientsubnetoption
 from dnsdisttests import DNSDistTest
 
 class TestBasics(DNSDistTest):
index 72d2a0383b4d385e0951e7557dcccc5b7769da41..c8dba56de130c6d5ba85b403d17edcc92ec08efc 100644 (file)
@@ -1,11 +1,8 @@
 #!/usr/bin/env python
-import dns
-import dns.message
-import os
-import socket
-import subprocess
 import time
 import unittest
+import dns
+import dns.message
 from dnsdisttests import DNSDistTest
 import dnscrypt
 
index 32c5aadae8adedc2bffd7245000022812502b610..020545825db0bff1fc46e79bf2a511e260a84f56 100644 (file)
@@ -1,10 +1,7 @@
 #!/usr/bin/env python
-import clientsubnetoption
-import dns
-import os
-import subprocess
-import time
 import unittest
+import dns
+import clientsubnetoption
 from dnsdisttests import DNSDistTest
 
 class TestEdnsClientSubnetNoOverride(DNSDistTest):