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)