From: Remi Gacogne Date: Thu, 31 Dec 2015 17:08:22 +0000 (+0100) Subject: dnsdist: Add a test (and a fix) for DNSCrypt truncation case. X-Git-Tag: dnsdist-1.0.0-alpha2~128^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F3142%2Fhead;p=thirdparty%2Fpdns.git dnsdist: Add a test (and a fix) for DNSCrypt truncation case. Refactor DNSCrypt regression tests following zeha's lead. --- diff --git a/pdns/dnscrypt.cc b/pdns/dnscrypt.cc index 02492bedd8..fd280e93b8 100644 --- a/pdns/dnscrypt.cc +++ b/pdns/dnscrypt.cc @@ -382,7 +382,22 @@ int DnsCryptContext::encryptResponse(char* response, uint16_t responseLen, uint1 if (!tcp && query->paddedLen < responseLen) { struct dnsheader* dh = (struct dnsheader*) response; - responseLen = query->paddedLen; + size_t questionSize = 0; + + if (responseLen > sizeof(dnsheader)) { + unsigned int consumed = 0; + DNSName qname(response, responseLen, sizeof(dnsheader), false, 0, 0, &consumed); + if (consumed > 0) { + questionSize = consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE; + } + } + + responseLen = sizeof(dnsheader) + questionSize; + + if (responseLen > query->paddedLen) { + responseLen = query->paddedLen; + } + dh->ancount = dh->arcount = dh->nscount = 0; dh->tc = 1; } diff --git a/pdns/test-dnscrypt_cc.cc b/pdns/test-dnscrypt_cc.cc index 2b2c1255b3..8c1e8e2baf 100644 --- a/pdns/test-dnscrypt_cc.cc +++ b/pdns/test-dnscrypt_cc.cc @@ -76,8 +76,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptPlaintextQuery) { BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0); BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "2.name."); - BOOST_CHECK_EQUAL(mdp.d_qclass, QClass::IN); - BOOST_CHECK_EQUAL(mdp.d_qtype, QType::TXT); + BOOST_CHECK(mdp.d_qclass == QClass::IN); + BOOST_CHECK(mdp.d_qtype == QType::TXT); } // invalid plaintext query (A) @@ -184,8 +184,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValid) { BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0); BOOST_CHECK_EQUAL(mdp.d_qname, name); - BOOST_CHECK_EQUAL(mdp.d_qclass, QClass::IN); - BOOST_CHECK_EQUAL(mdp.d_qtype, QType::AAAA); + BOOST_CHECK(mdp.d_qclass == QClass::IN); + BOOST_CHECK(mdp.d_qtype == QType::AAAA); } // valid encrypted query with not enough room @@ -276,8 +276,8 @@ BOOST_AUTO_TEST_CASE(DNSCryptEncryptedQueryValidWithOldKey) { BOOST_CHECK_EQUAL(mdp.d_header.arcount, 0); BOOST_CHECK_EQUAL(mdp.d_qname, name); - BOOST_CHECK_EQUAL(mdp.d_qclass, QClass::IN); - BOOST_CHECK_EQUAL(mdp.d_qtype, QType::AAAA); + BOOST_CHECK(mdp.d_qclass == QClass::IN); + BOOST_CHECK(mdp.d_qtype == QType::AAAA); } // valid encrypted query with wrong key diff --git a/regression-tests.dnsdist/dnsdisttests.py b/regression-tests.dnsdist/dnsdisttests.py index a650c6c769..e8b7e6484e 100644 --- a/regression-tests.dnsdist/dnsdisttests.py +++ b/regression-tests.dnsdist/dnsdisttests.py @@ -83,7 +83,7 @@ class DNSDistTest(unittest.TestCase): if shutUp: with open(os.devnull, 'w') as fdDevNull: - cls._dnsdist = subprocess.Popen(dnsdistcmd, close_fds=True, stdout=fdDevNull, stderr=fdDevNull) + cls._dnsdist = subprocess.Popen(dnsdistcmd, close_fds=True, stdout=fdDevNull) else: cls._dnsdist = subprocess.Popen(dnsdistcmd, close_fds=True) diff --git a/regression-tests.dnsdist/test_DNSCrypt.py b/regression-tests.dnsdist/test_DNSCrypt.py index 0b4e233b9d..3bb808f14e 100644 --- a/regression-tests.dnsdist/test_DNSCrypt.py +++ b/regression-tests.dnsdist/test_DNSCrypt.py @@ -20,38 +20,18 @@ class TestDNSCrypt(DNSDistTest): _dnsDistPort = 5340 _dnsDistPortDNSCrypt = 8443 _config_template = """ - generateDNSCryptCertificate("DNSCryptProviderPrivate.key", "DNSCryptResolver.cert", "DNSCryptResolver.key", 42, %d, %d) + generateDNSCryptCertificate("DNSCryptProviderPrivate.key", "DNSCryptResolver.cert", "DNSCryptResolver.key", %d, %d, %d) addDNSCryptBind("127.0.0.1:%d", "%s", "DNSCryptResolver.cert", "DNSCryptResolver.key") newServer{address="127.0.0.1:%s"} """ - _dnsdistcmd = (os.environ['DNSDISTBIN'] + " -C dnsdist_DNSCrypt.conf --acl 127.0.0.1/32 -l 127.0.0.1:" + str(_dnsDistPort)).split() _providerFingerprint = 'E1D7:2108:9A59:BF8D:F101:16FA:ED5E:EA6A:9F6C:C78F:7F91:AF6B:027E:62F4:69C3:B1AA' _providerName = "2.provider.name" - - @classmethod - def startDNSDist(cls, shutUp=True): - print("Launching dnsdist..") - # valid from 60s ago until 2h from now - validFrom = time.time() - 60 - validUntil = time.time() + 7200 - with open('dnsdist_DNSCrypt.conf', 'w') as conf: - conf.write(cls._config_template % (validFrom, validUntil, cls._dnsDistPortDNSCrypt, cls._providerName, str(cls._testServerPort))) - - print(' '.join(cls._dnsdistcmd)) - if shutUp: - with open(os.devnull, 'w') as fdDevNull: - cls._dnsdist = subprocess.Popen(cls._dnsdistcmd, close_fds=True, stdout=fdDevNull, stderr=fdDevNull) - else: - cls._dnsdist = subprocess.Popen(cls._dnsdistcmd, close_fds=True) - - time.sleep(1) - - if cls._dnsdist.poll() is not None: - cls._dnsdist.terminate() - cls._dnsdist.wait() - sys.exit(cls._dnsdist.returncode) - + _resolverCertificateSerial = 42 + # valid from 60s ago until 2h from now + _resolverCertificateValidFrom = time.time() - 60 + _resolverCertificateValidUntil = time.time() + 7200 + _config_params = ['_resolverCertificateSerial', '_resolverCertificateValidFrom', '_resolverCertificateValidUntil', '_dnsDistPortDNSCrypt', '_providerName', '_testServerPort'] def testSimpleA(self): """ @@ -82,6 +62,40 @@ class TestDNSCrypt(DNSDistTest): self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) + def testResponseLargerThanPaddedQuery(self): + """ + Send a small encrypted query (don't forget to take + the padding into account) and check that the response + is truncated. + """ + client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", 8443) + name = 'smallquerylargeresponse.dnscrypt.tests.powerdns.com.' + query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096) + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + 3600, + dns.rdataclass.IN, + dns.rdatatype.TXT, + 'A'*255) + response.answer.append(rrset) + + self._toResponderQueue.put(response) + data = client.query(query.to_wire()) + receivedQuery = None + if not self._fromResponderQueue.empty(): + receivedQuery = self._fromResponderQueue.get(query) + + receivedResponse = dns.message.from_wire(data) + + self.assertTrue(receivedQuery) + receivedQuery.id = query.id + self.assertEquals(query, receivedQuery) + self.assertEquals(receivedResponse.question, response.question) + self.assertTrue(receivedResponse.flags & ~dns.flags.TC) + self.assertTrue(len(receivedResponse.answer) == 0) + self.assertTrue(len(receivedResponse.authority) == 0) + self.assertTrue(len(receivedResponse.additional) == 0) + if __name__ == '__main__': unittest.main() exit(0)