]>
Commit | Line | Data |
---|---|---|
d328c3f0 RG |
1 | import dns |
2 | import os | |
3 | import socket | |
4 | import struct | |
5 | import threading | |
6 | import time | |
7 | ||
8 | from recursortests import RecursorTest | |
9 | from twisted.internet.protocol import DatagramProtocol | |
10 | from twisted.internet import reactor | |
11 | ||
12 | largeReactorRunning = False | |
13 | ||
14 | class LargeAnswerTest(RecursorTest): | |
15 | """ | |
16 | This test makes sure that we correctly process an answer matching our exact | |
17 | udp-truncation-threshold buffer size. | |
18 | """ | |
19 | _confdir = 'LargeAnswer' | |
20 | _udpTruncationThreshold = 1680 | |
21 | ||
22 | _config_template = """ | |
23 | forward-zones=large-answer.example=%s.22 | |
24 | udp-truncation-threshold=%d | |
25 | """ % (os.environ['PREFIX'], _udpTruncationThreshold) | |
26 | ||
27 | @classmethod | |
28 | def startResponders(cls): | |
29 | global largeReactorRunning | |
30 | print("Launching responders..") | |
31 | ||
32 | address = cls._PREFIX + '.22' | |
33 | port = 53 | |
34 | ||
35 | if not largeReactorRunning: | |
36 | reactor.listenUDP(port, UDPLargeResponder(), interface=address) | |
37 | largeReactorRunning = True | |
38 | ||
39 | if not reactor.running: | |
d023146c | 40 | cls._UDPResponder = threading.Thread(name='UDP Responder', target=reactor.run, args=(False,)) |
d328c3f0 RG |
41 | cls._UDPResponder.setDaemon(True) |
42 | cls._UDPResponder.start() | |
43 | ||
d328c3f0 RG |
44 | def checkResponseContent(self, rawResponse, value): |
45 | self.assertEquals(len(rawResponse), self._udpTruncationThreshold) | |
46 | response = dns.message.from_wire(rawResponse) | |
47 | ||
48 | self.assertRcodeEqual(response, dns.rcode.NOERROR) | |
49 | self.assertFalse(response.flags & dns.flags.TC) | |
50 | ||
51 | for record in response.answer: | |
52 | self.assertEquals(record.rdtype, dns.rdatatype.TXT) | |
53 | for part in record: | |
54 | for string in part.strings: | |
55 | self.assertTrue(len(string) == 255 or len(string) == 16) | |
56 | for c in string: | |
57 | self.assertEquals(c, value) | |
58 | ||
59 | def testLargeAnswer(self): | |
60 | # why the same query 10 times, do you ask? because if we are reading from | |
61 | # unintialized buffer memory, there is small risk that we find exactly the | |
62 | # value we expected by chance so let's massage our buffer a bit | |
63 | query = dns.message.make_query('AAAA.large-answer.example.', 'TXT', 'IN', use_edns=True, payload=4096) | |
64 | for _ in range(10): | |
65 | raw = self.sendUDPQuery(query, decode=False) | |
66 | self.checkResponseContent(raw, 'A') | |
67 | ||
68 | query = dns.message.make_query('ZZZZ.large-answer.example.', 'TXT', 'IN', use_edns=True, payload=4096) | |
69 | for _ in range(10): | |
70 | raw = self.sendUDPQuery(query, decode=False) | |
71 | self.checkResponseContent(raw, 'Z') | |
72 | ||
73 | class UDPLargeResponder(DatagramProtocol): | |
74 | ||
75 | def datagramReceived(self, datagram, address): | |
76 | request = dns.message.from_wire(datagram) | |
77 | ||
78 | response = dns.message.make_response(request) | |
79 | response.use_edns(edns=False) | |
80 | response.flags |= dns.flags.AA | |
81 | ||
82 | if request.question[0].name == dns.name.from_text('AAAA.large-answer.example.'): | |
83 | value = 'A' | |
84 | else: | |
85 | value = 'Z' | |
86 | ||
87 | answer = dns.rrset.from_text(request.question[0].name, 0, dns.rdataclass.IN, 'TXT', value*255) | |
88 | for _ in range(6): | |
89 | response.answer.append(answer) | |
90 | answer = dns.rrset.from_text(request.question[0].name, 0, dns.rdataclass.IN, 'TXT', value*16) | |
91 | response.answer.append(answer) | |
92 | self.transport.write(response.to_wire(max_size=65535), address) |