]> granicus.if.org Git - pdns/commitdiff
dnsdist: Add regression tests for the 'ecs-scope-zero' feature
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 14 Nov 2018 11:14:17 +0000 (12:14 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 10 Jan 2019 10:13:44 +0000 (11:13 +0100)
regression-tests.dnsdist/test_Caching.py

index bddf2cdd9302677da58a248b264bcddd101ee7ab..7cb26a5648cd71fb77b7f7198aaa5cd04995c1e4 100644 (file)
@@ -1752,3 +1752,258 @@ class TestCachingCollisionWithECSParsing(DNSDistTest):
         response2.answer.append(rrset)
         (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2)
         self.assertEquals(receivedResponse, response2)
+
+class TestCachingScopeZero(DNSDistTest):
+
+    _config_template = """
+    -- Be careful to enable ECS parsing in the packet cache, otherwise scope zero is disabled
+    pc = newPacketCache(100, 86400, 1, 60, 60, false, 1, true, 3600, true)
+    getPool(""):setCache(pc)
+    newServer{address="127.0.0.1:%d", useClientSubnet=true}
+    -- to simulate a second client coming from a different IP address,
+    -- we will force the ECS value added to the query if RD is set (note that we need
+    -- to unset it using rules before the first cache lookup)
+    addAction(RDRule(), SetECSAction("192.0.2.1/32"))
+    addAction(RDRule(), NoRecurseAction())
+    """
+
+    def testScopeZero(self):
+        """
+        Cache: Test the scope-zero feature, backend returns a scope of zero
+        """
+        ttl = 600
+        name = 'scope-zero.cache.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= ~dns.flags.RD
+        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
+        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        expectedQuery.flags &= ~dns.flags.RD
+        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, 0)
+        expectedResponse = dns.message.make_response(query)
+        scopedResponse = dns.message.make_response(query)
+        scopedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
+        rrset = dns.rrset.from_text(name,
+                                    ttl,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.AAAA,
+                                    '::1')
+        scopedResponse.answer.append(rrset)
+        expectedResponse.answer.append(rrset)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, scopedResponse)
+            receivedQuery.id = expectedQuery.id
+            self.checkMessageEDNSWithECS(expectedQuery, receivedQuery)
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+        # next query should hit the cache, nothing special about that
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= dns.flags.RD
+        # next query FROM A DIFFERENT CLIENT since RD is now set should STILL hit the cache
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            receivedResponse.id = expectedResponse.id
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+        name = 'scope-zero-with-ecs.cache.tests.powerdns.com.'
+        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
+        query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        query.flags &= ~dns.flags.RD
+        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        expectedQuery.flags &= ~dns.flags.RD
+        expectedResponse = dns.message.make_response(query)
+        expectedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
+        expectedResponse.answer.append(rrset)
+        scopedResponse = dns.message.make_response(query)
+        scopedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
+        scopedResponse.answer.append(rrset)
+        # this query has ECS, it should NOT be able to use the scope-zero cached entry since the hash will be
+        # different
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, scopedResponse)
+            receivedQuery.id = expectedQuery.id
+            self.checkMessageEDNSWithECS(expectedQuery, receivedQuery)
+            print(receivedResponse)
+            print(expectedResponse)
+            self.checkMessageEDNSWithECS(receivedResponse, expectedResponse)
+
+        # it should still have been cached, though, so the next query should be a hit
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.checkMessageEDNSWithECS(receivedResponse, expectedResponse)
+
+    def testScopeNotZero(self):
+        """
+        Cache: Test the scope-zero feature, backend returns a scope of non-zero
+        """
+        ttl = 600
+        name = 'scope-not-zero.cache.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= ~dns.flags.RD
+        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
+        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        expectedQuery.flags &= ~dns.flags.RD
+        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
+        expectedQuery2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        expectedQuery2.flags &= ~dns.flags.RD
+        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, 24)
+        ecsoResponse2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32, 24)
+        rrset = dns.rrset.from_text(name,
+                                    ttl,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.AAAA,
+                                    '::1')
+        expectedResponse = dns.message.make_response(query)
+        expectedResponse.answer.append(rrset)
+        scopedResponse = dns.message.make_response(query)
+        scopedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
+        scopedResponse.answer.append(rrset)
+        scopedResponse2 = dns.message.make_response(query)
+        scopedResponse2.use_edns(edns=True, payload=4096, options=[ecsoResponse2])
+        scopedResponse2.answer.append(rrset)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, scopedResponse)
+            receivedQuery.id = expectedQuery.id
+            self.checkMessageEDNSWithECS(expectedQuery, receivedQuery)
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+        # next query should hit the cache, nothing special about that
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= dns.flags.RD
+        expectedResponse = dns.message.make_response(query)
+        expectedResponse.answer.append(rrset)
+        # next query FROM A DIFFERENT CLIENT since RD is now set should NOT hit the cache
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, scopedResponse2)
+            receivedQuery.id = expectedQuery2.id
+            self.checkMessageEDNSWithECS(expectedQuery2, receivedQuery)
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+    def testNoECS(self):
+        """
+        Cache: Test the scope-zero feature, backend returns no ECS at all
+        """
+        ttl = 600
+        name = 'scope-zero-no-ecs.cache.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= ~dns.flags.RD
+        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
+        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        expectedQuery.flags &= ~dns.flags.RD
+        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
+        expectedQuery2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        expectedQuery2.flags &= ~dns.flags.RD
+        rrset = dns.rrset.from_text(name,
+                                    ttl,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.AAAA,
+                                    '::1')
+        response = dns.message.make_response(query)
+        response.answer.append(rrset)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response)
+            receivedQuery.id = expectedQuery.id
+            self.checkMessageEDNSWithECS(expectedQuery, receivedQuery)
+            self.checkMessageNoEDNS(receivedResponse, response)
+
+        # next query should hit the cache, nothing special about that
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.checkMessageNoEDNS(receivedResponse, response)
+
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= dns.flags.RD
+        response = dns.message.make_response(query)
+        response.answer.append(rrset)
+        # next query FROM A DIFFERENT CLIENT since RD is now set should NOT hit the cache
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response)
+            receivedQuery.id = expectedQuery2.id
+            self.checkMessageEDNSWithECS(expectedQuery2, receivedQuery)
+            self.checkMessageNoEDNS(receivedResponse, response)
+
+class TestCachingScopeZeroButNoSubnetcheck(DNSDistTest):
+
+    _config_template = """
+    -- We disable ECS parsing in the packet cache, meaning scope zero is disabled
+    pc = newPacketCache(100, 86400, 1, 60, 60, false, 1, true, 3600, false)
+    getPool(""):setCache(pc)
+    newServer{address="127.0.0.1:%d", useClientSubnet=true}
+    -- to simulate a second client coming from a different IP address,
+    -- we will force the ECS value added to the query if RD is set (note that we need
+    -- to unset it using rules before the first cache lookup)
+    addAction(RDRule(), SetECSAction("192.0.2.1/32"))
+    addAction(RDRule(), NoRecurseAction())
+    """
+
+    def testScopeZero(self):
+        """
+        Cache: Test that the scope-zero feature is disabled when ECS parsing is not enabled in the cache
+        """
+        ttl = 600
+        name = 'scope-zero-no-subnet.cache.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= ~dns.flags.RD
+        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
+        expectedQuery = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512)
+        expectedQuery.flags &= ~dns.flags.RD
+        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
+        expectedQuery2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512)
+        expectedQuery2.flags &= ~dns.flags.RD
+        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, 0)
+        expectedResponse = dns.message.make_response(query)
+        scopedResponse = dns.message.make_response(query)
+        scopedResponse.use_edns(edns=True, payload=4096, options=[ecsoResponse])
+        rrset = dns.rrset.from_text(name,
+                                    ttl,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.AAAA,
+                                    '::1')
+        scopedResponse.answer.append(rrset)
+        expectedResponse.answer.append(rrset)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, scopedResponse)
+            receivedQuery.id = expectedQuery.id
+            self.checkMessageEDNSWithECS(expectedQuery, receivedQuery)
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+        # next query should hit the cache, nothing special about that
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.checkMessageNoEDNS(receivedResponse, expectedResponse)
+
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        query.flags &= dns.flags.RD
+        response = dns.message.make_response(query)
+        response.answer.append(rrset)
+        # next query FROM A DIFFERENT CLIENT since RD is now set should NOT hit the cache
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response)
+            receivedQuery.id = expectedQuery2.id
+            self.checkMessageEDNSWithECS(expectedQuery2, receivedQuery)
+            self.checkMessageNoEDNS(receivedResponse, response)