def testMultiCookiesECS6FFI(self): """ EDNS Options: Two Cookies + ECS6 (FFI) """ name = 'multiplecookies-ecs6.ednsoptions.tests.powerdns.com.' eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef') ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128) eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de') query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco1, ecso, eco2]) 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 method in ("sendUDPQuery", "sendTCPQuery"): sender = getattr(self, method) (receivedQuery, receivedResponse) = sender(query, response) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = query.id self.assertEquals(receivedQuery, query) self.assertEquals(receivedResponse, response)
def testCookie(self): """ EDNS Options: Cookie """ name = 'cookie.ednsoptions.tests.powerdns.com.' eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef') query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco]) 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 method in ("sendUDPQuery", "sendTCPQuery"): sender = getattr(self, method) (receivedQuery, receivedResponse) = sender(query, response) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = query.id self.assertEquals(receivedQuery, query) self.assertEquals(receivedResponse, response)
def testECS6Cookie(self): """ EDNS Options: Cookie + ECS6 (adding ECS) """ name = 'cookie-ecs6.ednsoptions-ecs.tests.powerdns.com.' eco = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef') ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128) query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso, eco]) ecsoResponse = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128, scope=56) response = dns.message.make_response(query) response.use_edns(edns=True, payload=4096, options=[ecsoResponse]) rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, '127.0.0.1') response.answer.append(rrset) for method in ("sendUDPQuery", "sendTCPQuery"): sender = getattr(self, method) (receivedQuery, receivedResponse) = sender(query, response) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = query.id self.checkQueryEDNSWithECS(query, receivedQuery, 1) self.checkResponseEDNSWithECS(response, receivedResponse)
def testECS6Cookie(self): """ EDNS Options: Cookie + ECS6 """ name = 'cookie-ecs6.ednsoptions.tests.powerdns.com.' eco = cookiesoption.CookiesOption('deadbeef', 'deadbeef') ecso = clientsubnetoption.ClientSubnetOption('2001:DB8::1', 128) query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso, eco]) 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(receivedQuery, query) self.assertEquals(receivedResponse, response) (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = query.id self.assertEquals(receivedQuery, query) self.assertEquals(receivedResponse, response)
def testWithEDNSNoECSResponseWithCookiesThenECS(self): """ ECS: Existing EDNS without ECS (BE returning Cookies then ECS options) Send a query with EDNS but no ECS value. Check that the query received by the responder has a valid ECS value and that the response received from dnsdist contains an EDNS pseudo-RR. This time the response returned by the backend contains one cookies then one ECS option. """ name = 'withednsnoecs.bereturnscookiesthenecs.ecs.tests.powerdns.com.' ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24) query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso]) response = dns.message.make_response(expectedQuery) ecoResponse = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef') ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, scope=24) response.use_edns(edns=True, payload=4096, options=[ecoResponse, ecsoResponse]) expectedResponse = 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) expectedResponse.answer.append(rrset) expectedResponse.use_edns(edns=True, payload=4096, options=[ecoResponse]) (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = expectedQuery.id self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) self.checkResponseEDNSWithoutECS(expectedResponse, receivedResponse, withCookies=1) (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = expectedQuery.id self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) self.checkResponseEDNSWithoutECS(expectedResponse, receivedResponse, withCookies=1)
def testEDNSOptions(self): name = 'gettag-ednsoptions.lua.' subnet = '192.0.2.255' subnetMask = 32 ecso = clientsubnetoption.ClientSubnetOption(subnet, subnetMask) eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef') eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de') expected = [ dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.1'), dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [name, 'gettag-qtype-1', 'edns-subnet-' + subnet + '/' + str(subnetMask), 'ednsoption-10-count-2', 'ednsoption-10-total-len-32', 'ednsoption-8-count-1', 'ednsoption-8-total-len-8' ]), ] query = dns.message.make_query(name, 'A', want_dnssec=True, options=[eco1,ecso,eco2]) query.flags |= dns.flags.CD res = self.sendUDPQuery(query) self.assertResponseMatches(query, expected, res)
def testCookie(self): """ EDNS Options: Cookie (adding ECS) """ name = 'cookie.ednsoptions-ecs.tests.powerdns.com.' eco = cookiesoption.CookiesOption('deadbeef', 'deadbeef') query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[eco]) ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24) expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[eco, ecso], payload=512) 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.checkQueryEDNSWithECS(expectedQuery, receivedQuery, 1) self.checkResponseEDNSWithoutECS(response, receivedResponse) (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = expectedQuery.id self.checkQueryEDNSWithECS(expectedQuery, receivedQuery, 1) self.checkResponseEDNSWithoutECS(response, receivedResponse)
def testPacketCache(self): # first query, no cookie qname = 'a.example.' query = dns.message.make_query(qname, 'A', want_dnssec=True) expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42') for method in ("sendUDPQuery", "sendTCPQuery"): sender = getattr(self, method) res = sender(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(0, 1) # we should get a hit over UDP this time res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(1, 1) eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef') eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de') ecso1 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32) ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32) # we add a cookie, should not match anymore query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(1, 2) # same cookie, should match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(2, 2) # different cookie, should still match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco2]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(3, 2) # first cookie but with an ECS option, should not match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1, ecso1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(3, 3) # different cookie but same ECS option, should match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco2, ecso1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(4, 3) # first cookie but different ECS option, should still match (we ignore EDNS Client Subnet # in the recursor's packet cache, but ECS-specific responses are not cached query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1, ecso2]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(5, 3)
def testPacketCache(self): # first query, no cookie qname = 'a.example.' query = dns.message.make_query(qname, 'A', want_dnssec=True) expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A', '192.0.2.42') for method in ("sendUDPQuery", "sendTCPQuery"): sender = getattr(self, method) res = sender(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(0, 2) # we should get a hit over UDP this time res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(1, 2) # we should get a hit over TCP this time res = self.sendTCPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(2, 2) eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef') eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de') ecso1 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32) ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32) # we add a cookie, should not match anymore query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(2, 3) # same cookie, should match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(3, 3) # different cookie, should still match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco2]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(4, 3) # first cookie but with an ECS option, should not match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1, ecso1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(4, 4) # different cookie but same ECS option, should match query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco2, ecso1]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(5, 4) # first cookie but different ECS option, should still match (we ignore EDNS Client Subnet # in the recursor's packet cache, but ECS-specific responses are not cached query = dns.message.make_query(qname, 'A', want_dnssec=True, options=[eco1, ecso2]) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertRRsetInAnswer(res, expected) self.checkPacketCacheMetrics(6, 4) # NXDomain should get default packetcache TTL (10) query = dns.message.make_query('nxdomain.example.', 'A', want_dnssec=True) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NXDOMAIN) self.checkPacketCacheMetrics(6, 5) # NoData should get default packetcache TTL (10) query = dns.message.make_query('a.example.', 'AAAA', want_dnssec=True) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.NOERROR) self.checkPacketCacheMetrics(6, 6) # ServFail should get ServFail TTL (5) query = dns.message.make_query('f.example.', 'A', want_dnssec=True) res = self.sendUDPQuery(query) self.assertRcodeEqual(res, dns.rcode.SERVFAIL) self.checkPacketCacheMetrics(6, 7) # We peek into the cache to check TTLs and allow TTLs to be one lower than inserted since the clock might have ticked rec_controlCmd = [os.environ['RECCONTROL'], '--config-dir=%s' % 'configs/' + self._confdir, 'dump-cache', '-'] try: ret = subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT) self.assertTrue((b"a.example. 10 A ; tag 0 udp\n" in ret) or (b"a.example. 9 A ; tag 0 udp\n" in ret)) self.assertTrue((b"nxdomain.example. 10 A ; tag 0 udp\n" in ret) or (b"nxdomain.example. 9 A ; tag 0 udp\n" in ret)) self.assertTrue((b"a.example. 10 AAAA ; tag 0 udp\n" in ret) or (b"a.example. 9 AAAA ; tag 0 udp\n" in ret)) self.assertTrue((b"f.example. 5 A ; tag 0 udp\n" in ret) or (b"f.example. 4 A ; tag 0 udp\n" in ret)) except subprocess.CalledProcessError as e: print(e.output) raise