From: Remi Gacogne Date: Thu, 14 Dec 2017 10:14:35 +0000 (+0100) Subject: rec: Add regression tests for UDP outgoing buffer size X-Git-Tag: dnsdist-1.3.0~178^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb611f07566e08adf31c374e6453a6494df7d696;p=pdns rec: Add regression tests for UDP outgoing buffer size --- diff --git a/regression-tests.recursor-dnssec/recursortests.py b/regression-tests.recursor-dnssec/recursortests.py index a33c25966..720477ed2 100644 --- a/regression-tests.recursor-dnssec/recursortests.py +++ b/regression-tests.recursor-dnssec/recursortests.py @@ -575,7 +575,7 @@ distributor-threads=1""".format(confdir=confdir, raise @classmethod - def sendUDPQuery(cls, query, timeout=2.0, fwparams=dict()): + def sendUDPQuery(cls, query, timeout=2.0, decode=True, fwparams=dict()): if timeout: cls._sock.settimeout(timeout) @@ -590,6 +590,8 @@ distributor-threads=1""".format(confdir=confdir, message = None if data: + if not decode: + return data message = dns.message.from_wire(data, **fwparams) return message diff --git a/regression-tests.recursor-dnssec/test_LargeAnswer.py b/regression-tests.recursor-dnssec/test_LargeAnswer.py new file mode 100644 index 000000000..c8300dc28 --- /dev/null +++ b/regression-tests.recursor-dnssec/test_LargeAnswer.py @@ -0,0 +1,110 @@ +import dns +import os +import socket +import struct +import threading +import time + +from recursortests import RecursorTest +from twisted.internet.protocol import DatagramProtocol +from twisted.internet import reactor + +largeReactorRunning = False + +class LargeAnswerTest(RecursorTest): + """ + This test makes sure that we correctly process an answer matching our exact + udp-truncation-threshold buffer size. + """ + _confdir = 'LargeAnswer' + _udpTruncationThreshold = 1680 + + _config_template = """ +forward-zones=large-answer.example=%s.22 +udp-truncation-threshold=%d + """ % (os.environ['PREFIX'], _udpTruncationThreshold) + + @classmethod + def startResponders(cls): + global largeReactorRunning + print("Launching responders..") + + address = cls._PREFIX + '.22' + port = 53 + + if not largeReactorRunning: + reactor.listenUDP(port, UDPLargeResponder(), interface=address) + largeReactorRunning = True + + if not reactor.running: + cls._UDPResponder = threading.Thread(name='UDP Large Responder', target=reactor.run, args=(False,)) + cls._UDPResponder.setDaemon(True) + cls._UDPResponder.start() + + @classmethod + def setUpClass(cls): + cls.setUpSockets() + + cls.startResponders() + + confdir = os.path.join('configs', cls._confdir) + cls.createConfigDir(confdir) + + cls.generateRecursorConfig(confdir) + cls.startRecursor(confdir, cls._recursorPort) + + print("Launching tests..") + + @classmethod + def tearDownClass(cls): + cls.tearDownRecursor() + + def checkResponseContent(self, rawResponse, value): + self.assertEquals(len(rawResponse), self._udpTruncationThreshold) + response = dns.message.from_wire(rawResponse) + + self.assertRcodeEqual(response, dns.rcode.NOERROR) + self.assertFalse(response.flags & dns.flags.TC) + + for record in response.answer: + self.assertEquals(record.rdtype, dns.rdatatype.TXT) + for part in record: + for string in part.strings: + self.assertTrue(len(string) == 255 or len(string) == 16) + for c in string: + self.assertEquals(c, value) + + def testLargeAnswer(self): + # why the same query 10 times, do you ask? because if we are reading from + # unintialized buffer memory, there is small risk that we find exactly the + # value we expected by chance so let's massage our buffer a bit + query = dns.message.make_query('AAAA.large-answer.example.', 'TXT', 'IN', use_edns=True, payload=4096) + for _ in range(10): + raw = self.sendUDPQuery(query, decode=False) + self.checkResponseContent(raw, 'A') + + query = dns.message.make_query('ZZZZ.large-answer.example.', 'TXT', 'IN', use_edns=True, payload=4096) + for _ in range(10): + raw = self.sendUDPQuery(query, decode=False) + self.checkResponseContent(raw, 'Z') + +class UDPLargeResponder(DatagramProtocol): + + def datagramReceived(self, datagram, address): + request = dns.message.from_wire(datagram) + + response = dns.message.make_response(request) + response.use_edns(edns=False) + response.flags |= dns.flags.AA + + if request.question[0].name == dns.name.from_text('AAAA.large-answer.example.'): + value = 'A' + else: + value = 'Z' + + answer = dns.rrset.from_text(request.question[0].name, 0, dns.rdataclass.IN, 'TXT', value*255) + for _ in range(6): + response.answer.append(answer) + answer = dns.rrset.from_text(request.question[0].name, 0, dns.rdataclass.IN, 'TXT', value*16) + response.answer.append(answer) + self.transport.write(response.to_wire(max_size=65535), address)