]> git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Trailing.py
Merge pull request #9801 from rgacogne/ddist-noqueue-for-trailing-data-queries
[thirdparty/pdns.git] / regression-tests.dnsdist / test_Trailing.py
1 #!/usr/bin/env python
2 import threading
3 import dns
4 from dnsdisttests import DNSDistTest
5
6 class TestTrailingDataToBackend(DNSDistTest):
7
8 # this test suite uses a different responder port
9 # because, contrary to the other ones, its
10 # responders allow trailing data and we don't want
11 # to mix things up.
12 _testServerPort = 5360
13 _verboseMode = True
14 _config_template = """
15 newServer{address="127.0.0.1:%s"}
16
17 function replaceTrailingData(dq)
18 local success = dq:setTrailingData("ABC")
19 if not success then
20 return DNSAction.ServFail, ""
21 end
22 return DNSAction.None, ""
23 end
24 addAction("added.trailing.tests.powerdns.com.", LuaAction(replaceTrailingData))
25
26 function fillBuffer(dq)
27 local available = dq.size - dq.len
28 local tail = string.rep("A", available)
29 local success = dq:setTrailingData(tail)
30 if not success then
31 return DNSAction.ServFail, ""
32 end
33 return DNSAction.None, ""
34 end
35 addAction("max.trailing.tests.powerdns.com.", LuaAction(fillBuffer))
36
37 function exceedBuffer(dq)
38 local available = dq.size - dq.len
39 local tail = string.rep("A", available + 1)
40 local success = dq:setTrailingData(tail)
41 if not success then
42 return DNSAction.ServFail, ""
43 end
44 return DNSAction.None, ""
45 end
46 addAction("limited.trailing.tests.powerdns.com.", LuaAction(exceedBuffer))
47 """
48 @classmethod
49 def startResponders(cls):
50 print("Launching responders..")
51
52 # Respond REFUSED to queries with trailing data.
53 cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, dns.rcode.REFUSED])
54 cls._UDPResponder.setDaemon(True)
55 cls._UDPResponder.start()
56
57 # Respond REFUSED to queries with trailing data.
58 cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort, cls._toResponderQueue, cls._fromResponderQueue, dns.rcode.REFUSED])
59 cls._TCPResponder.setDaemon(True)
60 cls._TCPResponder.start()
61
62 def testTrailingPassthrough(self):
63 """
64 Trailing data: Pass through
65
66 """
67 name = 'passthrough.trailing.tests.powerdns.com.'
68 query = dns.message.make_query(name, 'A', 'IN')
69 response = dns.message.make_response(query)
70 rrset = dns.rrset.from_text(name,
71 3600,
72 dns.rdataclass.IN,
73 dns.rdatatype.A,
74 '127.0.0.1')
75 response.answer.append(rrset)
76 expectedResponse = dns.message.make_response(query)
77 expectedResponse.set_rcode(dns.rcode.REFUSED)
78
79 raw = query.to_wire()
80 raw = raw + b'A'* 20
81
82 for method in ("sendUDPQuery", "sendTCPQuery"):
83 sender = getattr(self, method)
84 (receivedQuery, receivedResponse) = sender(raw, response, rawQuery=True)
85 self.assertTrue(receivedQuery)
86 self.assertTrue(receivedResponse)
87 receivedQuery.id = query.id
88 self.assertEquals(receivedQuery, query)
89 self.assertEquals(receivedResponse, expectedResponse)
90
91 def testTrailingCapacity(self):
92 """
93 Trailing data: Fill buffer
94
95 """
96 name = 'max.trailing.tests.powerdns.com.'
97 query = dns.message.make_query(name, 'A', 'IN')
98 response = dns.message.make_response(query)
99 rrset = dns.rrset.from_text(name,
100 3600,
101 dns.rdataclass.IN,
102 dns.rdatatype.A,
103 '127.0.0.1')
104 response.answer.append(rrset)
105 expectedResponse = dns.message.make_response(query)
106 expectedResponse.set_rcode(dns.rcode.REFUSED)
107
108 for method in ("sendUDPQuery", "sendTCPQuery"):
109 sender = getattr(self, method)
110 (receivedQuery, receivedResponse) = sender(query, response)
111 self.assertTrue(receivedQuery)
112 self.assertTrue(receivedResponse)
113 receivedQuery.id = query.id
114 self.assertEquals(receivedQuery, query)
115 self.assertEquals(receivedResponse, expectedResponse)
116
117 def testTrailingLimited(self):
118 """
119 Trailing data: Reject buffer overflows
120
121 """
122 name = 'limited.trailing.tests.powerdns.com.'
123 query = dns.message.make_query(name, 'A', 'IN')
124 response = dns.message.make_response(query)
125 rrset = dns.rrset.from_text(name,
126 3600,
127 dns.rdataclass.IN,
128 dns.rdatatype.A,
129 '127.0.0.1')
130 response.answer.append(rrset)
131 expectedResponse = dns.message.make_response(query)
132 expectedResponse.set_rcode(dns.rcode.SERVFAIL)
133
134 for method in ("sendUDPQuery", "sendTCPQuery"):
135 sender = getattr(self, method)
136 (_, receivedResponse) = sender(query, response, useQueue=False)
137 self.assertTrue(receivedResponse)
138 self.assertEquals(receivedResponse, expectedResponse)
139
140 def testTrailingAdded(self):
141 """
142 Trailing data: Add
143
144 """
145 name = 'added.trailing.tests.powerdns.com.'
146 query = dns.message.make_query(name, 'A', 'IN')
147 response = dns.message.make_response(query)
148 rrset = dns.rrset.from_text(name,
149 3600,
150 dns.rdataclass.IN,
151 dns.rdatatype.A,
152 '127.0.0.1')
153 response.answer.append(rrset)
154 expectedResponse = dns.message.make_response(query)
155 expectedResponse.set_rcode(dns.rcode.REFUSED)
156
157 for method in ("sendUDPQuery", "sendTCPQuery"):
158 sender = getattr(self, method)
159 (receivedQuery, receivedResponse) = sender(query, response)
160 self.assertTrue(receivedQuery)
161 self.assertTrue(receivedResponse)
162 receivedQuery.id = query.id
163 self.assertEquals(receivedQuery, query)
164 self.assertEquals(receivedResponse, expectedResponse)
165
166 class TestTrailingDataToDnsdist(DNSDistTest):
167 _verboseMode = True
168 _config_template = """
169 newServer{address="127.0.0.1:%s"}
170
171 addAction(AndRule({QNameRule("dropped.trailing.tests.powerdns.com."), TrailingDataRule()}), DropAction())
172
173 function removeTrailingData(dq)
174 local success = dq:setTrailingData("")
175 if not success then
176 print("Trailing removal failed")
177 return DNSAction.ServFail, ""
178 end
179 return DNSAction.None, ""
180 end
181 addAction("removed.trailing.tests.powerdns.com.", LuaAction(removeTrailingData))
182
183 function reportTrailingData(dq)
184 local tail = dq:getTrailingData()
185 return DNSAction.Spoof, "-" .. tail .. ".echoed.trailing.tests.powerdns.com."
186 end
187 addAction("echoed.trailing.tests.powerdns.com.", LuaAction(reportTrailingData))
188
189 function replaceTrailingData(dq)
190 local success = dq:setTrailingData("ABC")
191 if not success then
192 return DNSAction.ServFail, ""
193 end
194 return DNSAction.None, ""
195 end
196 addAction("replaced.trailing.tests.powerdns.com.", LuaAction(replaceTrailingData))
197 addAction("replaced.trailing.tests.powerdns.com.", LuaAction(reportTrailingData))
198
199 function reportTrailingHex(dq)
200 local tail = dq:getTrailingData()
201 local hex = string.gsub(tail, ".", function(ch)
202 return string.sub(string.format("\\x2502X", string.byte(ch)), -2)
203 end)
204 return DNSAction.Spoof, "-0x" .. hex .. ".echoed-hex.trailing.tests.powerdns.com."
205 end
206 addAction("echoed-hex.trailing.tests.powerdns.com.", LuaAction(reportTrailingHex))
207
208 function replaceTrailingData_unsafe(dq)
209 local success = dq:setTrailingData("\\xB0\\x00\\xDE\\xADB\\xF0\\x9F\\x91\\xBB\\xC3\\xBE")
210 if not success then
211 return DNSAction.ServFail, ""
212 end
213 return DNSAction.None, ""
214 end
215 addAction("replaced-unsafe.trailing.tests.powerdns.com.", LuaAction(replaceTrailingData_unsafe))
216 addAction("replaced-unsafe.trailing.tests.powerdns.com.", LuaAction(reportTrailingHex))
217 """
218
219 def testTrailingDropped(self):
220 """
221 Trailing data: Drop query
222
223 """
224 name = 'dropped.trailing.tests.powerdns.com.'
225 query = dns.message.make_query(name, 'A', 'IN')
226 response = dns.message.make_response(query)
227 rrset = dns.rrset.from_text(name,
228 3600,
229 dns.rdataclass.IN,
230 dns.rdatatype.A,
231 '127.0.0.1')
232 response.answer.append(rrset)
233
234 raw = query.to_wire()
235 raw = raw + b'A'* 20
236
237 for method in ("sendUDPQuery", "sendTCPQuery"):
238 sender = getattr(self, method)
239
240 # Verify that queries with no trailing data make it through.
241 (receivedQuery, receivedResponse) = sender(query, response)
242 self.assertTrue(receivedQuery)
243 self.assertTrue(receivedResponse)
244 receivedQuery.id = query.id
245 self.assertEquals(query, receivedQuery)
246 self.assertEquals(response, receivedResponse)
247
248 # Verify that queries with trailing data don't make it through.
249 (_, receivedResponse) = sender(raw, response, rawQuery=True, useQueue=False)
250 self.assertEquals(receivedResponse, None)
251
252 def testTrailingRemoved(self):
253 """
254 Trailing data: Remove
255
256 """
257 name = 'removed.trailing.tests.powerdns.com.'
258 query = dns.message.make_query(name, 'A', 'IN')
259 response = dns.message.make_response(query)
260 rrset = dns.rrset.from_text(name,
261 3600,
262 dns.rdataclass.IN,
263 dns.rdatatype.A,
264 '127.0.0.1')
265 response.answer.append(rrset)
266
267 raw = query.to_wire()
268 raw = raw + b'A'* 20
269
270 for method in ("sendUDPQuery", "sendTCPQuery"):
271 sender = getattr(self, method)
272 (receivedQuery, receivedResponse) = sender(raw, response, rawQuery=True)
273 self.assertTrue(receivedQuery)
274 self.assertTrue(receivedResponse)
275 receivedQuery.id = query.id
276 self.assertEquals(receivedQuery, query)
277 self.assertEquals(receivedResponse, response)
278
279 def testTrailingRead(self):
280 """
281 Trailing data: Echo
282
283 """
284 name = 'echoed.trailing.tests.powerdns.com.'
285 query = dns.message.make_query(name, 'A', 'IN')
286 response = dns.message.make_response(query)
287 response.set_rcode(dns.rcode.SERVFAIL)
288 expectedResponse = dns.message.make_response(query)
289 rrset = dns.rrset.from_text(name,
290 60,
291 dns.rdataclass.IN,
292 dns.rdatatype.CNAME,
293 '-TrailingData.echoed.trailing.tests.powerdns.com.')
294 expectedResponse.answer.append(rrset)
295
296 raw = query.to_wire()
297 raw = raw + b'TrailingData'
298
299 for method in ("sendUDPQuery", "sendTCPQuery"):
300 sender = getattr(self, method)
301 (_, receivedResponse) = sender(raw, response=None, rawQuery=True, useQueue=False)
302 self.assertTrue(receivedResponse)
303 expectedResponse.flags = receivedResponse.flags
304 self.assertEquals(receivedResponse, expectedResponse)
305
306 def testTrailingReplaced(self):
307 """
308 Trailing data: Replace
309
310 """
311 name = 'replaced.trailing.tests.powerdns.com.'
312 query = dns.message.make_query(name, 'A', 'IN')
313 response = dns.message.make_response(query)
314 response.set_rcode(dns.rcode.SERVFAIL)
315 expectedResponse = dns.message.make_response(query)
316 rrset = dns.rrset.from_text(name,
317 60,
318 dns.rdataclass.IN,
319 dns.rdatatype.CNAME,
320 '-ABC.echoed.trailing.tests.powerdns.com.')
321 expectedResponse.answer.append(rrset)
322
323 raw = query.to_wire()
324 raw = raw + b'TrailingData'
325
326 for method in ("sendUDPQuery", "sendTCPQuery"):
327 sender = getattr(self, method)
328 (_, receivedResponse) = sender(raw, response=None, rawQuery=True, useQueue=False)
329 self.assertTrue(receivedResponse)
330 expectedResponse.flags = receivedResponse.flags
331 self.assertEquals(receivedResponse, expectedResponse)
332
333 def testTrailingReadUnsafe(self):
334 """
335 Trailing data: Echo as hex
336
337 """
338 name = 'echoed-hex.trailing.tests.powerdns.com.'
339 query = dns.message.make_query(name, 'A', 'IN')
340 response = dns.message.make_response(query)
341 response.set_rcode(dns.rcode.SERVFAIL)
342 expectedResponse = dns.message.make_response(query)
343 rrset = dns.rrset.from_text(name,
344 60,
345 dns.rdataclass.IN,
346 dns.rdatatype.CNAME,
347 '-0x0000DEAD.echoed-hex.trailing.tests.powerdns.com.')
348 expectedResponse.answer.append(rrset)
349
350 raw = query.to_wire()
351 raw = raw + b'\x00\x00\xDE\xAD'
352
353 for method in ("sendUDPQuery", "sendTCPQuery"):
354 sender = getattr(self, method)
355 (_, receivedResponse) = sender(raw, response=None, rawQuery=True, useQueue=False)
356 self.assertTrue(receivedResponse)
357 expectedResponse.flags = receivedResponse.flags
358 self.assertEquals(receivedResponse, expectedResponse)
359
360 def testTrailingReplacedUnsafe(self):
361 """
362 Trailing data: Replace with null and/or non-ASCII bytes
363
364 """
365 name = 'replaced-unsafe.trailing.tests.powerdns.com.'
366 query = dns.message.make_query(name, 'A', 'IN')
367 response = dns.message.make_response(query)
368 response.set_rcode(dns.rcode.SERVFAIL)
369 expectedResponse = dns.message.make_response(query)
370 rrset = dns.rrset.from_text(name,
371 60,
372 dns.rdataclass.IN,
373 dns.rdatatype.CNAME,
374 '-0xB000DEAD42F09F91BBC3BE.echoed-hex.trailing.tests.powerdns.com.')
375 expectedResponse.answer.append(rrset)
376
377 raw = query.to_wire()
378 raw = raw + b'TrailingData'
379
380 for method in ("sendUDPQuery", "sendTCPQuery"):
381 sender = getattr(self, method)
382 (_, receivedResponse) = sender(raw, response=None, rawQuery=True, useQueue=False)
383 self.assertTrue(receivedResponse)
384 expectedResponse.flags = receivedResponse.flags
385 self.assertEquals(receivedResponse, expectedResponse)