From: Remi Gacogne Date: Fri, 4 Dec 2015 14:09:08 +0000 (+0100) Subject: Add more tests for dnsdist ECS support. X-Git-Tag: dnsdist-1.0.0-alpha1~108^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7b146b98b7ac8e2470f84e1178f6da00f6d0290b;p=pdns Add more tests for dnsdist ECS support. Add regression tests for rewriting the ECS value with larger / smaller values. Add one unit test for rewriting response. --- diff --git a/pdns/test-dnsdist_cc.cc b/pdns/test-dnsdist_cc.cc index fd2eddf00..4a1491679 100644 --- a/pdns/test-dnsdist_cc.cc +++ b/pdns/test-dnsdist_cc.cc @@ -43,7 +43,7 @@ bool g_verbose{true}; static void validateQuery(const char * packet, size_t packetSize) { MOADNSParser mdp(packet, packetSize); - + BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1); @@ -52,6 +52,19 @@ static void validateQuery(const char * packet, size_t packetSize) BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1); } +static void validateResponse(const char * packet, size_t packetSize, bool hasEdns) +{ + MOADNSParser mdp(packet, packetSize); + + BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); + + BOOST_CHECK_EQUAL(mdp.d_header.qr, 1); + BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1); + BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1); + BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0); + BOOST_CHECK_EQUAL(mdp.d_header.arcount, hasEdns ? 1 : 0); +} + BOOST_AUTO_TEST_CASE(addECSWithoutEDNS) { string largerPacket; @@ -60,10 +73,10 @@ BOOST_AUTO_TEST_CASE(addECSWithoutEDNS) DNSName name("www.powerdns.com."); vector query; - DNSPacketWriter pw(query, name, QType::OPT, QClass::IN, 0); + DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); pw.getHeader()->rd = 1; int len = query.size(); - + /* large enough packet */ char packet[1500]; memcpy(packet, query.data(), query.size()); @@ -72,21 +85,21 @@ BOOST_AUTO_TEST_CASE(addECSWithoutEDNS) uint16_t qtype; DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); - + BOOST_CHECK(qtype == QType::A); + handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, remote); BOOST_CHECK((size_t) len > query.size()); BOOST_CHECK_EQUAL(largerPacket.size(), 0); BOOST_CHECK_EQUAL(ednsAdded, true); validateQuery(packet, len); - + /* not large enought packet */ consumed = 0; len = query.size(); qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); - + BOOST_CHECK(qtype == QType::A); + handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, remote); BOOST_CHECK_EQUAL((size_t) len, query.size()); BOOST_CHECK(largerPacket.size() > query.size()); @@ -98,15 +111,15 @@ BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) { string largerPacket; bool ednsAdded = false; ComboAddress remote; - DNSName name("www.powerdns.com"); + DNSName name("www.powerdns.com."); vector query; - DNSPacketWriter pw(query, name, QType::OPT, QClass::IN, 0); + DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); pw.getHeader()->rd = 1; pw.addOpt(512, 0, 0); pw.commit(); int len = query.size(); - + /* large enough packet */ char packet[1500]; memcpy(packet, query.data(), query.size()); @@ -115,21 +128,21 @@ BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) { uint16_t qtype; DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); - + BOOST_CHECK(qtype == QType::A); + handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, remote); BOOST_CHECK((size_t) len > query.size()); BOOST_CHECK_EQUAL(largerPacket.size(), 0); BOOST_CHECK_EQUAL(ednsAdded, false); validateQuery(packet, len); - + /* not large enought packet */ consumed = 0; len = query.size(); qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); - + BOOST_CHECK(qtype == QType::A); + handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, remote); BOOST_CHECK_EQUAL((size_t) len, query.size()); BOOST_CHECK(largerPacket.size() > query.size()); @@ -141,11 +154,11 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) { string largerPacket; bool ednsAdded = false; ComboAddress remote("192.168.1.25"); - DNSName name("www.powerdns.com"); + DNSName name("www.powerdns.com."); ComboAddress origRemote("127.0.0.1"); vector query; - DNSPacketWriter pw(query, name, QType::OPT, QClass::IN, 0); + DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); pw.getHeader()->rd = 1; EDNSSubnetOpts ecsOpts; ecsOpts.source = Netmask(origRemote, g_ECSSourcePrefixV4); @@ -155,7 +168,7 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) { pw.addOpt(512, 0, 0, opts); pw.commit(); int len = query.size(); - + /* large enough packet */ char packet[1500]; memcpy(packet, query.data(), query.size()); @@ -164,7 +177,7 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) { uint16_t qtype; DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); + BOOST_CHECK(qtype == QType::A); g_ECSOverride = true; handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, remote); @@ -178,11 +191,11 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) { string largerPacket; bool ednsAdded = false; ComboAddress remote("192.168.1.25"); - DNSName name("www.powerdns.com"); + DNSName name("www.powerdns.com."); ComboAddress origRemote("127.0.0.1"); vector query; - DNSPacketWriter pw(query, name, QType::OPT, QClass::IN, 0); + DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); pw.getHeader()->rd = 1; EDNSSubnetOpts ecsOpts; ecsOpts.source = Netmask(origRemote, 32); @@ -192,7 +205,7 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) { pw.addOpt(512, 0, 0, opts); pw.commit(); int len = query.size(); - + /* large enough packet */ char packet[1500]; memcpy(packet, query.data(), query.size()); @@ -201,7 +214,7 @@ BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) { uint16_t qtype; DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); + BOOST_CHECK(qtype == QType::A); g_ECSOverride = true; handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, remote); @@ -215,11 +228,11 @@ BOOST_AUTO_TEST_CASE(replaceECSWithLarger) { string largerPacket; bool ednsAdded = false; ComboAddress remote("192.168.1.25"); - DNSName name("www.powerdns.com"); + DNSName name("www.powerdns.com."); ComboAddress origRemote("127.0.0.1"); vector query; - DNSPacketWriter pw(query, name, QType::OPT, QClass::IN, 0); + DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); pw.getHeader()->rd = 1; EDNSSubnetOpts ecsOpts; ecsOpts.source = Netmask(origRemote, 8); @@ -229,7 +242,7 @@ BOOST_AUTO_TEST_CASE(replaceECSWithLarger) { pw.addOpt(512, 0, 0, opts); pw.commit(); int len = query.size(); - + /* large enough packet */ char packet[1500]; memcpy(packet, query.data(), query.size()); @@ -238,7 +251,7 @@ BOOST_AUTO_TEST_CASE(replaceECSWithLarger) { uint16_t qtype; DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); + BOOST_CHECK(qtype == QType::A); g_ECSOverride = true; handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, remote); @@ -252,8 +265,8 @@ BOOST_AUTO_TEST_CASE(replaceECSWithLarger) { len = query.size(); qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); BOOST_CHECK_EQUAL(qname, name); - BOOST_CHECK(qtype == QType::OPT); - + BOOST_CHECK(qtype == QType::A); + g_ECSOverride = true; handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, remote); BOOST_CHECK_EQUAL((size_t) len, query.size()); @@ -262,4 +275,31 @@ BOOST_AUTO_TEST_CASE(replaceECSWithLarger) { validateQuery(largerPacket.c_str(), largerPacket.size()); } +BOOST_AUTO_TEST_CASE(removeEDNS) { + DNSName name("www.powerdns.com."); + + vector response; + DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); + pw.getHeader()->qr = 1; + pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); + pw.xfr32BitInt(0x01020304); + pw.addOpt(512, 0, 0); + pw.commit(); + + vector newResponse; + int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse); + + BOOST_CHECK_EQUAL(res, 0); + + unsigned int consumed = 0; + uint16_t qtype; + DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); + BOOST_CHECK_EQUAL(qname, name); + BOOST_CHECK(qtype == QType::A); + size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */; + BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize); + + validateResponse((const char *) newResponse.data(), newResponse.size(), false); +} + BOOST_AUTO_TEST_SUITE_END(); diff --git a/regression-tests.dnsdist/test_EdnsClientSubnet.py b/regression-tests.dnsdist/test_EdnsClientSubnet.py index c0412526f..aa4d87389 100644 --- a/regression-tests.dnsdist/test_EdnsClientSubnet.py +++ b/regression-tests.dnsdist/test_EdnsClientSubnet.py @@ -280,16 +280,96 @@ class TestEdnsClientSubnetOverride(DNSDistTest): self.assertEquals(expectedQuery, receivedQuery) self.assertEquals(expectedResponse, receivedResponse) - def testWithEDNSECS(self): + def testWithEDNSShorterInitialECS(self): """ Send a query with EDNS and a crafted ECS value. Check that the query received by the responder has an overwritten ECS value (not the initial one) and that the response received from dnsdist contains an EDNS pseudo-RR. + The initial ECS value is shorter than the one it will + replaced with. """ name = 'withednsecs.overriden.ecs.tests.powerdns.com.' - ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4', 24) + ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 8) + rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24) + query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso]) + expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso]) + 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 + receivedResponse.id = response.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 + receivedResponse.id = response.id + self.assertEquals(expectedQuery, receivedQuery) + self.assertEquals(response, receivedResponse) + + def testWithEDNSLongerInitialECS(self): + """ + Send a query with EDNS and a crafted ECS value. + Check that the query received by the responder + has an overwritten ECS value (not the initial one) + and that the response received from dnsdist contains + an EDNS pseudo-RR. + The initial ECS value is longer than the one it will + replaced with. + """ + name = 'withednsecs.overriden.ecs.tests.powerdns.com.' + ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32) + rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24) + query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso]) + expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso]) + 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 + receivedResponse.id = response.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 + receivedResponse.id = response.id + self.assertEquals(expectedQuery, receivedQuery) + self.assertEquals(response, receivedResponse) + + def testWithEDNSSameSizeInitialECS(self): + """ + Send a query with EDNS and a crafted ECS value. + Check that the query received by the responder + has an overwritten ECS value (not the initial one) + and that the response received from dnsdist contains + an EDNS pseudo-RR. + The initial ECS value is exactly the same size as + the one it will replaced with. + """ + name = 'withednsecs.overriden.ecs.tests.powerdns.com.' + ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24) rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24) query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso]) expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])