]> git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Advanced.py
78105512e88963f88d4a6a052003837d173f549f
[thirdparty/pdns.git] / regression-tests.dnsdist / test_Advanced.py
1 #!/usr/bin/env python
2 import base64
3 from datetime import datetime, timedelta
4 import os
5 import string
6 import time
7 import dns
8 import clientsubnetoption
9 from dnsdisttests import DNSDistTest
10
11 class TestAdvancedAllow(DNSDistTest):
12
13 _config_template = """
14 addAction(AllRule(), NoneAction())
15 addAction(makeRule("allowed.advanced.tests.powerdns.com."), AllowAction())
16 addAction(AllRule(), DropAction())
17 newServer{address="127.0.0.1:%s"}
18 """
19
20 def testAdvancedAllow(self):
21 """
22 Advanced: Allowed qname is not dropped
23
24 A query for allowed.advanced.tests.powerdns.com. should be allowed
25 while others should be dropped.
26 """
27 name = 'allowed.advanced.tests.powerdns.com.'
28 query = dns.message.make_query(name, 'A', 'IN')
29 response = dns.message.make_response(query)
30 rrset = dns.rrset.from_text(name,
31 3600,
32 dns.rdataclass.IN,
33 dns.rdatatype.A,
34 '127.0.0.1')
35 response.answer.append(rrset)
36
37 for method in ("sendUDPQuery", "sendTCPQuery"):
38 sender = getattr(self, method)
39 (receivedQuery, receivedResponse) = sender(query, response)
40 self.assertTrue(receivedQuery)
41 self.assertTrue(receivedResponse)
42 receivedQuery.id = query.id
43 self.assertEquals(query, receivedQuery)
44 self.assertEquals(response, receivedResponse)
45
46 def testAdvancedAllowDropped(self):
47 """
48 Advanced: Not allowed qname is dropped
49
50 A query for notallowed.advanced.tests.powerdns.com. should be dropped.
51 """
52 name = 'notallowed.advanced.tests.powerdns.com.'
53 query = dns.message.make_query(name, 'A', 'IN')
54
55 for method in ("sendUDPQuery", "sendTCPQuery"):
56 sender = getattr(self, method)
57 (_, receivedResponse) = sender(query, response=None, useQueue=False)
58
59 class TestAdvancedFixupCase(DNSDistTest):
60
61 _config_template = """
62 truncateTC(true)
63 fixupCase(true)
64 newServer{address="127.0.0.1:%s"}
65 """
66
67 def testAdvancedFixupCase(self):
68 """
69 Advanced: Fixup Case
70
71 Send a query with lower and upper chars,
72 make the backend return a lowercase version,
73 check that dnsdist fixes the response.
74 """
75 name = 'fiXuPCasE.advanced.tests.powerdns.com.'
76 query = dns.message.make_query(name, 'A', 'IN')
77 lowercasequery = dns.message.make_query(name.lower(), 'A', 'IN')
78 response = dns.message.make_response(lowercasequery)
79 expectedResponse = dns.message.make_response(query)
80 rrset = dns.rrset.from_text(name,
81 3600,
82 dns.rdataclass.IN,
83 dns.rdatatype.A,
84 '127.0.0.1')
85 response.answer.append(rrset)
86 expectedResponse.answer.append(rrset)
87
88 for method in ("sendUDPQuery", "sendTCPQuery"):
89 sender = getattr(self, method)
90 (receivedQuery, receivedResponse) = sender(query, response)
91 self.assertTrue(receivedQuery)
92 self.assertTrue(receivedResponse)
93 receivedQuery.id = query.id
94 self.assertEquals(query, receivedQuery)
95 self.assertEquals(expectedResponse, receivedResponse)
96
97 class TestAdvancedRemoveRD(DNSDistTest):
98
99 _config_template = """
100 addAction("norecurse.advanced.tests.powerdns.com.", NoRecurseAction())
101 newServer{address="127.0.0.1:%s"}
102 """
103
104 def testAdvancedNoRD(self):
105 """
106 Advanced: No RD
107
108 Send a query with RD,
109 check that dnsdist clears the RD flag.
110 """
111 name = 'norecurse.advanced.tests.powerdns.com.'
112 query = dns.message.make_query(name, 'A', 'IN')
113 expectedQuery = dns.message.make_query(name, 'A', 'IN')
114 expectedQuery.flags &= ~dns.flags.RD
115
116 response = dns.message.make_response(query)
117 rrset = dns.rrset.from_text(name,
118 3600,
119 dns.rdataclass.IN,
120 dns.rdatatype.A,
121 '127.0.0.1')
122 response.answer.append(rrset)
123
124 for method in ("sendUDPQuery", "sendTCPQuery"):
125 sender = getattr(self, method)
126 (receivedQuery, receivedResponse) = sender(query, response)
127 self.assertTrue(receivedQuery)
128 self.assertTrue(receivedResponse)
129 receivedQuery.id = expectedQuery.id
130 self.assertEquals(expectedQuery, receivedQuery)
131 self.assertEquals(response, receivedResponse)
132
133 def testAdvancedKeepRD(self):
134 """
135 Advanced: No RD canary
136
137 Send a query with RD for a canary domain,
138 check that dnsdist does not clear the RD flag.
139 """
140 name = 'keeprecurse.advanced.tests.powerdns.com.'
141 query = dns.message.make_query(name, 'A', 'IN')
142
143 response = dns.message.make_response(query)
144 rrset = dns.rrset.from_text(name,
145 3600,
146 dns.rdataclass.IN,
147 dns.rdatatype.A,
148 '127.0.0.1')
149 response.answer.append(rrset)
150
151 for method in ("sendUDPQuery", "sendTCPQuery"):
152 sender = getattr(self, method)
153 (receivedQuery, receivedResponse) = sender(query, response)
154 self.assertTrue(receivedQuery)
155 self.assertTrue(receivedResponse)
156 receivedQuery.id = query.id
157 self.assertEquals(query, receivedQuery)
158 self.assertEquals(response, receivedResponse)
159
160 class TestAdvancedAddCD(DNSDistTest):
161
162 _config_template = """
163 addAction("setcd.advanced.tests.powerdns.com.", DisableValidationAction())
164 addAction(makeRule("setcdviaaction.advanced.tests.powerdns.com."), DisableValidationAction())
165 newServer{address="127.0.0.1:%s"}
166 """
167
168 def testAdvancedSetCD(self):
169 """
170 Advanced: Set CD
171
172 Send a query with CD cleared,
173 check that dnsdist set the CD flag.
174 """
175 name = 'setcd.advanced.tests.powerdns.com.'
176 query = dns.message.make_query(name, 'A', 'IN')
177 expectedQuery = dns.message.make_query(name, 'A', 'IN')
178 expectedQuery.flags |= dns.flags.CD
179
180 response = dns.message.make_response(query)
181 rrset = dns.rrset.from_text(name,
182 3600,
183 dns.rdataclass.IN,
184 dns.rdatatype.A,
185 '127.0.0.1')
186 response.answer.append(rrset)
187
188 for method in ("sendUDPQuery", "sendTCPQuery"):
189 sender = getattr(self, method)
190 (receivedQuery, receivedResponse) = sender(query, response)
191 self.assertTrue(receivedQuery)
192 self.assertTrue(receivedResponse)
193 receivedQuery.id = expectedQuery.id
194 self.assertEquals(expectedQuery, receivedQuery)
195 self.assertEquals(response, receivedResponse)
196
197 def testAdvancedSetCDViaAction(self):
198 """
199 Advanced: Set CD via Action
200
201 Send a query with CD cleared,
202 check that dnsdist set the CD flag.
203 """
204 name = 'setcdviaaction.advanced.tests.powerdns.com.'
205 query = dns.message.make_query(name, 'A', 'IN')
206 expectedQuery = dns.message.make_query(name, 'A', 'IN')
207 expectedQuery.flags |= dns.flags.CD
208
209 response = dns.message.make_response(query)
210 rrset = dns.rrset.from_text(name,
211 3600,
212 dns.rdataclass.IN,
213 dns.rdatatype.A,
214 '127.0.0.1')
215 response.answer.append(rrset)
216
217 for method in ("sendUDPQuery", "sendTCPQuery"):
218 sender = getattr(self, method)
219 (receivedQuery, receivedResponse) = sender(query, response)
220 self.assertTrue(receivedQuery)
221 self.assertTrue(receivedResponse)
222 receivedQuery.id = expectedQuery.id
223 self.assertEquals(expectedQuery, receivedQuery)
224 self.assertEquals(response, receivedResponse)
225
226 def testAdvancedKeepNoCD(self):
227 """
228 Advanced: Preserve CD canary
229
230 Send a query without CD for a canary domain,
231 check that dnsdist does not set the CD flag.
232 """
233 name = 'keepnocd.advanced.tests.powerdns.com.'
234 query = dns.message.make_query(name, 'A', 'IN')
235
236 response = dns.message.make_response(query)
237 rrset = dns.rrset.from_text(name,
238 3600,
239 dns.rdataclass.IN,
240 dns.rdatatype.A,
241 '127.0.0.1')
242 response.answer.append(rrset)
243
244 for method in ("sendUDPQuery", "sendTCPQuery"):
245 sender = getattr(self, method)
246 (receivedQuery, receivedResponse) = sender(query, response)
247 self.assertTrue(receivedQuery)
248 self.assertTrue(receivedResponse)
249 receivedQuery.id = query.id
250 self.assertEquals(query, receivedQuery)
251 self.assertEquals(response, receivedResponse)
252
253 class TestAdvancedClearRD(DNSDistTest):
254
255 _config_template = """
256 addAction("clearrd.advanced.tests.powerdns.com.", NoRecurseAction())
257 addAction(makeRule("clearrdviaaction.advanced.tests.powerdns.com."), NoRecurseAction())
258 newServer{address="127.0.0.1:%s"}
259 """
260
261 def testAdvancedClearRD(self):
262 """
263 Advanced: Clear RD
264
265 Send a query with RD set,
266 check that dnsdist clears the RD flag.
267 """
268 name = 'clearrd.advanced.tests.powerdns.com.'
269 query = dns.message.make_query(name, 'A', 'IN')
270 expectedQuery = dns.message.make_query(name, 'A', 'IN')
271 expectedQuery.flags &= ~dns.flags.RD
272
273 response = dns.message.make_response(query)
274 rrset = dns.rrset.from_text(name,
275 3600,
276 dns.rdataclass.IN,
277 dns.rdatatype.A,
278 '127.0.0.1')
279 response.answer.append(rrset)
280
281 for method in ("sendUDPQuery", "sendTCPQuery"):
282 sender = getattr(self, method)
283 (receivedQuery, receivedResponse) = sender(query, response)
284 self.assertTrue(receivedQuery)
285 self.assertTrue(receivedResponse)
286 receivedQuery.id = expectedQuery.id
287 self.assertEquals(expectedQuery, receivedQuery)
288 self.assertEquals(response, receivedResponse)
289
290 def testAdvancedClearRDViaAction(self):
291 """
292 Advanced: Clear RD via Action
293
294 Send a query with RD set,
295 check that dnsdist clears the RD flag.
296 """
297 name = 'clearrdviaaction.advanced.tests.powerdns.com.'
298 query = dns.message.make_query(name, 'A', 'IN')
299 expectedQuery = dns.message.make_query(name, 'A', 'IN')
300 expectedQuery.flags &= ~dns.flags.RD
301
302 response = dns.message.make_response(query)
303 rrset = dns.rrset.from_text(name,
304 3600,
305 dns.rdataclass.IN,
306 dns.rdatatype.A,
307 '127.0.0.1')
308 response.answer.append(rrset)
309
310 for method in ("sendUDPQuery", "sendTCPQuery"):
311 sender = getattr(self, method)
312 (receivedQuery, receivedResponse) = sender(query, response)
313 self.assertTrue(receivedQuery)
314 self.assertTrue(receivedResponse)
315 receivedQuery.id = expectedQuery.id
316 self.assertEquals(expectedQuery, receivedQuery)
317 self.assertEquals(response, receivedResponse)
318
319 def testAdvancedKeepRD(self):
320 """
321 Advanced: Preserve RD canary
322
323 Send a query with RD for a canary domain,
324 check that dnsdist does not clear the RD flag.
325 """
326 name = 'keeprd.advanced.tests.powerdns.com.'
327 query = dns.message.make_query(name, 'A', 'IN')
328
329 response = dns.message.make_response(query)
330 rrset = dns.rrset.from_text(name,
331 3600,
332 dns.rdataclass.IN,
333 dns.rdatatype.A,
334 '127.0.0.1')
335 response.answer.append(rrset)
336
337 for method in ("sendUDPQuery", "sendTCPQuery"):
338 sender = getattr(self, method)
339 (receivedQuery, receivedResponse) = sender(query, response)
340 self.assertTrue(receivedQuery)
341 self.assertTrue(receivedResponse)
342 receivedQuery.id = query.id
343 self.assertEquals(query, receivedQuery)
344 self.assertEquals(response, receivedResponse)
345
346
347 class TestAdvancedACL(DNSDistTest):
348
349 _config_template = """
350 newServer{address="127.0.0.1:%s"}
351 """
352 _acl = ['192.0.2.1/32']
353
354 def testACLBlocked(self):
355 """
356 Advanced: ACL blocked
357
358 Send an A query to "tests.powerdns.com.",
359 we expect no response since 127.0.0.1 is not on the
360 ACL.
361 """
362 name = 'tests.powerdns.com.'
363 query = dns.message.make_query(name, 'A', 'IN')
364
365 for method in ("sendUDPQuery", "sendTCPQuery"):
366 sender = getattr(self, method)
367 (_, receivedResponse) = sender(query, response=None, useQueue=False)
368 self.assertEquals(receivedResponse, None)
369
370 class TestAdvancedDelay(DNSDistTest):
371
372 _config_template = """
373 addAction(AllRule(), DelayAction(1000))
374 newServer{address="127.0.0.1:%s"}
375 """
376
377 def testDelayed(self):
378 """
379 Advanced: Delayed
380
381 Send an A query to "tests.powerdns.com.",
382 check that the response delay is longer than 1000 ms
383 over UDP, less than that over TCP.
384 """
385 name = 'tests.powerdns.com.'
386 query = dns.message.make_query(name, 'A', 'IN')
387 response = dns.message.make_response(query)
388 rrset = dns.rrset.from_text(name,
389 60,
390 dns.rdataclass.IN,
391 dns.rdatatype.A,
392 '192.0.2.1')
393 response.answer.append(rrset)
394
395 begin = datetime.now()
396 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
397 end = datetime.now()
398 receivedQuery.id = query.id
399 self.assertEquals(query, receivedQuery)
400 self.assertEquals(response, receivedResponse)
401 self.assertTrue((end - begin) > timedelta(0, 1))
402
403 begin = datetime.now()
404 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
405 end = datetime.now()
406 receivedQuery.id = query.id
407 self.assertEquals(query, receivedQuery)
408 self.assertEquals(response, receivedResponse)
409 self.assertTrue((end - begin) < timedelta(0, 1))
410
411
412 class TestAdvancedTruncateAnyAndTCP(DNSDistTest):
413
414 _config_template = """
415 truncateTC(false)
416 addAction(AndRule({QTypeRule("ANY"), TCPRule(true)}), TCAction())
417 newServer{address="127.0.0.1:%s"}
418 """
419 def testTruncateAnyOverTCP(self):
420 """
421 Advanced: Truncate ANY over TCP
422
423 Send an ANY query to "anytruncatetcp.advanced.tests.powerdns.com.",
424 should be truncated over TCP, not over UDP (yes, it makes no sense,
425 deal with it).
426 """
427 name = 'anytruncatetcp.advanced.tests.powerdns.com.'
428 query = dns.message.make_query(name, 'ANY', 'IN')
429
430 response = dns.message.make_response(query)
431 rrset = dns.rrset.from_text(name,
432 3600,
433 dns.rdataclass.IN,
434 dns.rdatatype.A,
435 '127.0.0.1')
436
437 response.answer.append(rrset)
438
439 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
440 self.assertTrue(receivedQuery)
441 self.assertTrue(receivedResponse)
442 receivedQuery.id = query.id
443 self.assertEquals(query, receivedQuery)
444 self.assertEquals(receivedResponse, response)
445
446 expectedResponse = dns.message.make_response(query)
447 expectedResponse.flags |= dns.flags.TC
448
449 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
450 self.assertEquals(receivedResponse, expectedResponse)
451
452 class TestAdvancedAndNot(DNSDistTest):
453
454 _config_template = """
455 addAction(AndRule({NotRule(QTypeRule("A")), TCPRule(false)}), RCodeAction(dnsdist.NOTIMP))
456 newServer{address="127.0.0.1:%s"}
457 """
458 def testAOverUDPReturnsNotImplementedCanary(self):
459 """
460 Advanced: !A && UDP canary
461
462 dnsdist is configured to reply 'not implemented' for query
463 over UDP AND !qtype A.
464 We send an A query over UDP and TCP, and check that the
465 response is OK.
466 """
467 name = 'andnot.advanced.tests.powerdns.com.'
468 query = dns.message.make_query(name, 'A', 'IN')
469 response = dns.message.make_response(query)
470 rrset = dns.rrset.from_text(name,
471 3600,
472 dns.rdataclass.IN,
473 dns.rdatatype.A,
474 '127.0.0.1')
475 response.answer.append(rrset)
476
477 for method in ("sendUDPQuery", "sendTCPQuery"):
478 sender = getattr(self, method)
479 (receivedQuery, receivedResponse) = sender(query, response)
480 self.assertTrue(receivedQuery)
481 self.assertTrue(receivedResponse)
482 receivedQuery.id = query.id
483 self.assertEquals(query, receivedQuery)
484 self.assertEquals(receivedResponse, response)
485
486 def testAOverUDPReturnsNotImplemented(self):
487 """
488 Advanced: !A && UDP
489
490 dnsdist is configured to reply 'not implemented' for query
491 over UDP AND !qtype A.
492 We send a TXT query over UDP and TCP, and check that the
493 response is OK for TCP and 'not implemented' for UDP.
494 """
495 name = 'andnot.advanced.tests.powerdns.com.'
496 query = dns.message.make_query(name, 'TXT', 'IN')
497
498 expectedResponse = dns.message.make_response(query)
499 expectedResponse.set_rcode(dns.rcode.NOTIMP)
500
501 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
502 self.assertEquals(receivedResponse, expectedResponse)
503
504 response = dns.message.make_response(query)
505 rrset = dns.rrset.from_text(name,
506 3600,
507 dns.rdataclass.IN,
508 dns.rdatatype.TXT,
509 'nothing to see here')
510 response.answer.append(rrset)
511
512 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
513 self.assertTrue(receivedQuery)
514 self.assertTrue(receivedResponse)
515 receivedQuery.id = query.id
516 self.assertEquals(query, receivedQuery)
517 self.assertEquals(receivedResponse, response)
518
519 class TestAdvancedOr(DNSDistTest):
520
521 _config_template = """
522 addAction(OrRule({QTypeRule("A"), TCPRule(false)}), RCodeAction(dnsdist.NOTIMP))
523 newServer{address="127.0.0.1:%s"}
524 """
525 def testAAAAOverUDPReturnsNotImplemented(self):
526 """
527 Advanced: A || UDP: AAAA
528
529 dnsdist is configured to reply 'not implemented' for query
530 over UDP OR qtype A.
531 We send an AAAA query over UDP and TCP, and check that the
532 response is 'not implemented' for UDP and OK for TCP.
533 """
534 name = 'aorudp.advanced.tests.powerdns.com.'
535 query = dns.message.make_query(name, 'AAAA', 'IN')
536 response = dns.message.make_response(query)
537 rrset = dns.rrset.from_text(name,
538 3600,
539 dns.rdataclass.IN,
540 dns.rdatatype.AAAA,
541 '::1')
542 response.answer.append(rrset)
543
544 expectedResponse = dns.message.make_response(query)
545 expectedResponse.set_rcode(dns.rcode.NOTIMP)
546
547 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
548 self.assertEquals(receivedResponse, expectedResponse)
549
550 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
551 self.assertTrue(receivedQuery)
552 self.assertTrue(receivedResponse)
553 receivedQuery.id = query.id
554 self.assertEquals(query, receivedQuery)
555 self.assertEquals(receivedResponse, response)
556
557 def testAOverUDPReturnsNotImplemented(self):
558 """
559 Advanced: A || UDP: A
560
561 dnsdist is configured to reply 'not implemented' for query
562 over UDP OR qtype A.
563 We send an A query over UDP and TCP, and check that the
564 response is 'not implemented' for both.
565 """
566 name = 'aorudp.advanced.tests.powerdns.com.'
567 query = dns.message.make_query(name, 'A', 'IN')
568
569 expectedResponse = dns.message.make_response(query)
570 expectedResponse.set_rcode(dns.rcode.NOTIMP)
571
572 for method in ("sendUDPQuery", "sendTCPQuery"):
573 sender = getattr(self, method)
574 (_, receivedResponse) = sender(query, response=None, useQueue=False)
575 self.assertEquals(receivedResponse, expectedResponse)
576
577
578 class TestAdvancedLogAction(DNSDistTest):
579
580 _config_template = """
581 newServer{address="127.0.0.1:%s"}
582 addAction(AllRule(), LogAction("dnsdist.log", false))
583 """
584 def testAdvancedLogAction(self):
585 """
586 Advanced: Log all queries
587
588 """
589 count = 50
590 name = 'logaction.advanced.tests.powerdns.com.'
591 query = dns.message.make_query(name, 'A', 'IN')
592 response = dns.message.make_response(query)
593 rrset = dns.rrset.from_text(name,
594 3600,
595 dns.rdataclass.IN,
596 dns.rdatatype.A,
597 '127.0.0.1')
598 response.answer.append(rrset)
599
600 for _ in range(count):
601 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
602 self.assertTrue(receivedQuery)
603 self.assertTrue(receivedResponse)
604 receivedQuery.id = query.id
605 self.assertEquals(query, receivedQuery)
606 self.assertEquals(response, receivedResponse)
607
608 self.assertTrue(os.path.isfile('dnsdist.log'))
609 self.assertTrue(os.stat('dnsdist.log').st_size > 0)
610
611 class TestAdvancedDNSSEC(DNSDistTest):
612
613 _config_template = """
614 newServer{address="127.0.0.1:%s"}
615 addAction(DNSSECRule(), DropAction())
616 """
617 def testAdvancedDNSSECDrop(self):
618 """
619 Advanced: DNSSEC Rule
620
621 """
622 name = 'dnssec.advanced.tests.powerdns.com.'
623 query = dns.message.make_query(name, 'A', 'IN')
624 doquery = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
625 response = dns.message.make_response(query)
626 rrset = dns.rrset.from_text(name,
627 3600,
628 dns.rdataclass.IN,
629 dns.rdatatype.A,
630 '127.0.0.1')
631 response.answer.append(rrset)
632
633 for method in ("sendUDPQuery", "sendTCPQuery"):
634 sender = getattr(self, method)
635 (receivedQuery, receivedResponse) = sender(query, response)
636 self.assertTrue(receivedQuery)
637 self.assertTrue(receivedResponse)
638 receivedQuery.id = query.id
639 self.assertEquals(query, receivedQuery)
640 self.assertEquals(response, receivedResponse)
641
642 for method in ("sendUDPQuery", "sendTCPQuery"):
643 sender = getattr(self, method)
644 (_, receivedResponse) = sender(doquery, response)
645 self.assertEquals(receivedResponse, None)
646
647 class TestAdvancedQClass(DNSDistTest):
648
649 _config_template = """
650 newServer{address="127.0.0.1:%s"}
651 addAction(QClassRule(DNSClass.CHAOS), DropAction())
652 """
653 def testAdvancedQClassChaosDrop(self):
654 """
655 Advanced: Drop QClass CHAOS
656
657 """
658 name = 'qclasschaos.advanced.tests.powerdns.com.'
659 query = dns.message.make_query(name, 'TXT', 'CHAOS')
660
661 for method in ("sendUDPQuery", "sendTCPQuery"):
662 sender = getattr(self, method)
663 (_, receivedResponse) = sender(query, response=None)
664 self.assertEquals(receivedResponse, None)
665
666 def testAdvancedQClassINAllow(self):
667 """
668 Advanced: Allow QClass IN
669
670 """
671 name = 'qclassin.advanced.tests.powerdns.com.'
672 query = dns.message.make_query(name, 'A', 'IN')
673 response = dns.message.make_response(query)
674 rrset = dns.rrset.from_text(name,
675 3600,
676 dns.rdataclass.IN,
677 dns.rdatatype.A,
678 '127.0.0.1')
679 response.answer.append(rrset)
680
681 for method in ("sendUDPQuery", "sendTCPQuery"):
682 sender = getattr(self, method)
683 (receivedQuery, receivedResponse) = sender(query, response)
684 self.assertTrue(receivedQuery)
685 self.assertTrue(receivedResponse)
686 receivedQuery.id = query.id
687 self.assertEquals(query, receivedQuery)
688 self.assertEquals(response, receivedResponse)
689
690 class TestAdvancedOpcode(DNSDistTest):
691
692 _config_template = """
693 newServer{address="127.0.0.1:%s"}
694 addAction(OpcodeRule(DNSOpcode.Notify), DropAction())
695 """
696 def testAdvancedOpcodeNotifyDrop(self):
697 """
698 Advanced: Drop Opcode NOTIFY
699
700 """
701 name = 'opcodenotify.advanced.tests.powerdns.com.'
702 query = dns.message.make_query(name, 'A', 'IN')
703 query.set_opcode(dns.opcode.NOTIFY)
704
705 for method in ("sendUDPQuery", "sendTCPQuery"):
706 sender = getattr(self, method)
707 (_, receivedResponse) = sender(query, response=None)
708 self.assertEquals(receivedResponse, None)
709
710 def testAdvancedOpcodeUpdateINAllow(self):
711 """
712 Advanced: Allow Opcode UPDATE
713
714 """
715 name = 'opcodeupdate.advanced.tests.powerdns.com.'
716 query = dns.message.make_query(name, 'A', 'IN')
717 query.set_opcode(dns.opcode.UPDATE)
718 response = dns.message.make_response(query)
719 rrset = dns.rrset.from_text(name,
720 3600,
721 dns.rdataclass.IN,
722 dns.rdatatype.A,
723 '127.0.0.1')
724 response.answer.append(rrset)
725
726 for method in ("sendUDPQuery", "sendTCPQuery"):
727 sender = getattr(self, method)
728 (receivedQuery, receivedResponse) = sender(query, response)
729 self.assertTrue(receivedQuery)
730 self.assertTrue(receivedResponse)
731 receivedQuery.id = query.id
732 self.assertEquals(query, receivedQuery)
733 self.assertEquals(response, receivedResponse)
734
735 class TestAdvancedNonTerminalRule(DNSDistTest):
736
737 _config_template = """
738 newServer{address="127.0.0.1:%s", pool="real"}
739 addAction(AllRule(), DisableValidationAction())
740 addAction(AllRule(), PoolAction("real"))
741 addAction(AllRule(), DropAction())
742 """
743 def testAdvancedNonTerminalRules(self):
744 """
745 Advanced: Non terminal rules
746
747 We check that DisableValidationAction() is applied
748 but does not stop the processing, then that
749 PoolAction() is applied _and_ stop the processing.
750 """
751 name = 'nonterminal.advanced.tests.powerdns.com.'
752 query = dns.message.make_query(name, 'A', 'IN')
753 expectedQuery = dns.message.make_query(name, 'A', 'IN')
754 expectedQuery.flags |= dns.flags.CD
755 response = dns.message.make_response(query)
756 rrset = dns.rrset.from_text(name,
757 3600,
758 dns.rdataclass.IN,
759 dns.rdatatype.A,
760 '192.0.2.1')
761 response.answer.append(rrset)
762
763 for method in ("sendUDPQuery", "sendTCPQuery"):
764 sender = getattr(self, method)
765 (receivedQuery, receivedResponse) = sender(query, response)
766 self.assertTrue(receivedQuery)
767 self.assertTrue(receivedResponse)
768 receivedQuery.id = expectedQuery.id
769 self.assertEquals(expectedQuery, receivedQuery)
770 self.assertEquals(response, receivedResponse)
771
772 class TestAdvancedStringOnlyServer(DNSDistTest):
773
774 _config_template = """
775 newServer("127.0.0.1:%s")
776 """
777
778 def testAdvancedStringOnlyServer(self):
779 """
780 Advanced: "string-only" server is placed in the default pool
781 """
782 name = 'string-only-server.advanced.tests.powerdns.com.'
783 query = dns.message.make_query(name, 'A', 'IN')
784 response = dns.message.make_response(query)
785 rrset = dns.rrset.from_text(name,
786 3600,
787 dns.rdataclass.IN,
788 dns.rdatatype.A,
789 '192.0.2.1')
790 response.answer.append(rrset)
791
792 for method in ("sendUDPQuery", "sendTCPQuery"):
793 sender = getattr(self, method)
794 (receivedQuery, receivedResponse) = sender(query, response)
795 self.assertTrue(receivedQuery)
796 self.assertTrue(receivedResponse)
797 receivedQuery.id = query.id
798 self.assertEquals(query, receivedQuery)
799 self.assertEquals(response, receivedResponse)
800
801 class TestAdvancedRestoreFlagsOnSelfResponse(DNSDistTest):
802
803 _config_template = """
804 addAction(AllRule(), DisableValidationAction())
805 addAction(AllRule(), SpoofAction("192.0.2.1"))
806 newServer{address="127.0.0.1:%s"}
807 """
808
809 def testAdvancedRestoreFlagsOnSpoofResponse(self):
810 """
811 Advanced: Restore flags on spoofed response
812
813 Send a query with CD flag cleared, dnsdist is
814 instructed to set it, then to spoof the response,
815 check that response has the flag cleared.
816 """
817 name = 'spoofed.restoreflags.advanced.tests.powerdns.com.'
818 query = dns.message.make_query(name, 'A', 'IN')
819 # dnsdist set RA = RD for spoofed responses
820 query.flags &= ~dns.flags.RD
821
822 response = dns.message.make_response(query)
823 rrset = dns.rrset.from_text(name,
824 60,
825 dns.rdataclass.IN,
826 dns.rdatatype.A,
827 '192.0.2.1')
828 response.answer.append(rrset)
829
830 for method in ("sendUDPQuery", "sendTCPQuery"):
831 sender = getattr(self, method)
832 (_, receivedResponse) = sender(query, response=None, useQueue=False)
833 self.assertTrue(receivedResponse)
834 self.assertEquals(response, receivedResponse)
835
836 class TestAdvancedQPS(DNSDistTest):
837
838 _config_template = """
839 addAction("qps.advanced.tests.powerdns.com", QPSAction(10))
840 newServer{address="127.0.0.1:%s"}
841 """
842
843 def testAdvancedQPSLimit(self):
844 """
845 Advanced: QPS Limit
846
847 Send queries to "qps.advanced.tests.powerdns.com."
848 check that dnsdist drops queries when the max QPS has been reached.
849 """
850 maxQPS = 10
851 name = 'qps.advanced.tests.powerdns.com.'
852 query = dns.message.make_query(name, 'A', 'IN')
853 response = dns.message.make_response(query)
854 rrset = dns.rrset.from_text(name,
855 60,
856 dns.rdataclass.IN,
857 dns.rdatatype.A,
858 '192.0.2.1')
859 response.answer.append(rrset)
860
861 for _ in range(maxQPS):
862 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
863 receivedQuery.id = query.id
864 self.assertEquals(query, receivedQuery)
865 self.assertEquals(response, receivedResponse)
866
867 # we should now be dropped
868 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
869 self.assertEquals(receivedResponse, None)
870
871 time.sleep(1)
872
873 # again, over TCP this time
874 for _ in range(maxQPS):
875 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
876 receivedQuery.id = query.id
877 self.assertEquals(query, receivedQuery)
878 self.assertEquals(response, receivedResponse)
879
880
881 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
882 self.assertEquals(receivedResponse, None)
883
884 class TestAdvancedQPSNone(DNSDistTest):
885
886 _config_template = """
887 addAction("qpsnone.advanced.tests.powerdns.com", QPSAction(100))
888 addAction(AllRule(), RCodeAction(dnsdist.REFUSED))
889 newServer{address="127.0.0.1:%s"}
890 """
891
892 def testAdvancedQPSNone(self):
893 """
894 Advanced: Not matching QPS returns None, not Allow
895
896 Send queries to "qps.advanced.tests.powerdns.com."
897 check that the rule returns None when the QPS has not been
898 reached, not Allow.
899 """
900 name = 'qpsnone.advanced.tests.powerdns.com.'
901 query = dns.message.make_query(name, 'A', 'IN')
902 expectedResponse = dns.message.make_response(query)
903 expectedResponse.set_rcode(dns.rcode.REFUSED)
904
905 for method in ("sendUDPQuery", "sendTCPQuery"):
906 sender = getattr(self, method)
907 (_, receivedResponse) = sender(query, response=None, useQueue=False)
908 self.assertEquals(receivedResponse, expectedResponse)
909
910 class TestAdvancedNMGRule(DNSDistTest):
911
912 _config_template = """
913 allowed = newNMG()
914 allowed:addMask("192.0.2.1/32")
915 addAction(NotRule(NetmaskGroupRule(allowed)), RCodeAction(dnsdist.REFUSED))
916 newServer{address="127.0.0.1:%s"}
917 """
918
919 def testAdvancedNMGRule(self):
920 """
921 Advanced: NMGRule should refuse our queries
922
923 Send queries to "nmgrule.advanced.tests.powerdns.com.",
924 check that we are getting a REFUSED response.
925 """
926 name = 'nmgrule.advanced.tests.powerdns.com.'
927 query = dns.message.make_query(name, 'A', 'IN')
928 expectedResponse = dns.message.make_response(query)
929 expectedResponse.set_rcode(dns.rcode.REFUSED)
930
931 for method in ("sendUDPQuery", "sendTCPQuery"):
932 sender = getattr(self, method)
933 (_, receivedResponse) = sender(query, response=None, useQueue=False)
934 self.assertEquals(receivedResponse, expectedResponse)
935
936 class TestDSTPortRule(DNSDistTest):
937
938 _config_params = ['_dnsDistPort', '_testServerPort']
939 _config_template = """
940 addAction(DSTPortRule(%d), RCodeAction(dnsdist.REFUSED))
941 newServer{address="127.0.0.1:%s"}
942 """
943
944 def testDSTPortRule(self):
945 """
946 Advanced: DSTPortRule should capture our queries
947
948 Send queries to "dstportrule.advanced.tests.powerdns.com.",
949 check that we are getting a REFUSED response.
950 """
951
952 name = 'dstportrule.advanced.tests.powerdns.com.'
953 query = dns.message.make_query(name, 'A', 'IN')
954 expectedResponse = dns.message.make_response(query)
955 expectedResponse.set_rcode(dns.rcode.REFUSED)
956
957 for method in ("sendUDPQuery", "sendTCPQuery"):
958 sender = getattr(self, method)
959 (_, receivedResponse) = sender(query, response=None, useQueue=False)
960 self.assertEquals(receivedResponse, expectedResponse)
961
962 class TestAdvancedLabelsCountRule(DNSDistTest):
963
964 _config_template = """
965 addAction(QNameLabelsCountRule(5,6), RCodeAction(dnsdist.REFUSED))
966 newServer{address="127.0.0.1:%s"}
967 """
968
969 def testAdvancedLabelsCountRule(self):
970 """
971 Advanced: QNameLabelsCountRule(5,6)
972 """
973 # 6 labels, we should be fine
974 name = 'ok.labelscount.advanced.tests.powerdns.com.'
975 query = dns.message.make_query(name, 'A', 'IN')
976 response = dns.message.make_response(query)
977 rrset = dns.rrset.from_text(name,
978 3600,
979 dns.rdataclass.IN,
980 dns.rdatatype.A,
981 '192.0.2.1')
982 response.answer.append(rrset)
983
984 for method in ("sendUDPQuery", "sendTCPQuery"):
985 sender = getattr(self, method)
986 (receivedQuery, receivedResponse) = sender(query, response)
987 self.assertTrue(receivedQuery)
988 self.assertTrue(receivedResponse)
989 receivedQuery.id = query.id
990 self.assertEquals(query, receivedQuery)
991 self.assertEquals(response, receivedResponse)
992
993 # more than 6 labels, the query should be refused
994 name = 'not.ok.labelscount.advanced.tests.powerdns.com.'
995 query = dns.message.make_query(name, 'A', 'IN')
996 expectedResponse = dns.message.make_response(query)
997 expectedResponse.set_rcode(dns.rcode.REFUSED)
998
999 for method in ("sendUDPQuery", "sendTCPQuery"):
1000 sender = getattr(self, method)
1001 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1002 self.assertEquals(receivedResponse, expectedResponse)
1003
1004 # less than 5 labels, the query should be refused
1005 name = 'labelscountadvanced.tests.powerdns.com.'
1006 query = dns.message.make_query(name, 'A', 'IN')
1007 expectedResponse = dns.message.make_response(query)
1008 expectedResponse.set_rcode(dns.rcode.REFUSED)
1009
1010 for method in ("sendUDPQuery", "sendTCPQuery"):
1011 sender = getattr(self, method)
1012 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1013 self.assertEquals(receivedResponse, expectedResponse)
1014
1015 class TestAdvancedWireLengthRule(DNSDistTest):
1016
1017 _config_template = """
1018 addAction(QNameWireLengthRule(54,56), RCodeAction(dnsdist.REFUSED))
1019 newServer{address="127.0.0.1:%s"}
1020 """
1021
1022 def testAdvancedWireLengthRule(self):
1023 """
1024 Advanced: QNameWireLengthRule(54,56)
1025 """
1026 name = 'longenough.qnamewirelength.advanced.tests.powerdns.com.'
1027 query = dns.message.make_query(name, 'A', 'IN')
1028 response = dns.message.make_response(query)
1029 rrset = dns.rrset.from_text(name,
1030 3600,
1031 dns.rdataclass.IN,
1032 dns.rdatatype.A,
1033 '192.0.2.1')
1034 response.answer.append(rrset)
1035
1036 for method in ("sendUDPQuery", "sendTCPQuery"):
1037 sender = getattr(self, method)
1038 (receivedQuery, receivedResponse) = sender(query, response)
1039 self.assertTrue(receivedQuery)
1040 self.assertTrue(receivedResponse)
1041 receivedQuery.id = query.id
1042 self.assertEquals(query, receivedQuery)
1043 self.assertEquals(response, receivedResponse)
1044
1045 # too short, the query should be refused
1046 name = 'short.qnamewirelength.advanced.tests.powerdns.com.'
1047 query = dns.message.make_query(name, 'A', 'IN')
1048 expectedResponse = dns.message.make_response(query)
1049 expectedResponse.set_rcode(dns.rcode.REFUSED)
1050
1051 for method in ("sendUDPQuery", "sendTCPQuery"):
1052 sender = getattr(self, method)
1053 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1054 self.assertEquals(receivedResponse, expectedResponse)
1055
1056 # too long, the query should be refused
1057 name = 'toolongtobevalid.qnamewirelength.advanced.tests.powerdns.com.'
1058 query = dns.message.make_query(name, 'A', 'IN')
1059 expectedResponse = dns.message.make_response(query)
1060 expectedResponse.set_rcode(dns.rcode.REFUSED)
1061
1062 for method in ("sendUDPQuery", "sendTCPQuery"):
1063 sender = getattr(self, method)
1064 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1065 self.assertEquals(receivedResponse, expectedResponse)
1066
1067 class TestAdvancedIncludeDir(DNSDistTest):
1068
1069 _config_template = """
1070 -- this directory contains a file allowing includedir.advanced.tests.powerdns.com.
1071 includeDirectory('test-include-dir')
1072 newServer{address="127.0.0.1:%s"}
1073 """
1074
1075 def testAdvancedIncludeDirAllowed(self):
1076 """
1077 Advanced: includeDirectory()
1078 """
1079 name = 'includedir.advanced.tests.powerdns.com.'
1080 query = dns.message.make_query(name, 'A', 'IN')
1081 response = dns.message.make_response(query)
1082 rrset = dns.rrset.from_text(name,
1083 3600,
1084 dns.rdataclass.IN,
1085 dns.rdatatype.A,
1086 '192.0.2.1')
1087 response.answer.append(rrset)
1088
1089 for method in ("sendUDPQuery", "sendTCPQuery"):
1090 sender = getattr(self, method)
1091 (receivedQuery, receivedResponse) = sender(query, response)
1092 self.assertTrue(receivedQuery)
1093 self.assertTrue(receivedResponse)
1094 receivedQuery.id = query.id
1095 self.assertEquals(query, receivedQuery)
1096 self.assertEquals(response, receivedResponse)
1097
1098 # this one should be refused
1099 name = 'notincludedir.advanced.tests.powerdns.com.'
1100 query = dns.message.make_query(name, 'A', 'IN')
1101 expectedResponse = dns.message.make_response(query)
1102 expectedResponse.set_rcode(dns.rcode.REFUSED)
1103
1104 for method in ("sendUDPQuery", "sendTCPQuery"):
1105 sender = getattr(self, method)
1106 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1107 self.assertEquals(receivedResponse, expectedResponse)
1108
1109 class TestAdvancedLuaDO(DNSDistTest):
1110
1111 _config_template = """
1112 function nxDOLua(dq)
1113 if dq:getDO() then
1114 return DNSAction.Nxdomain, ""
1115 end
1116 return DNSAction.None, ""
1117 end
1118 addAction(AllRule(), LuaAction(nxDOLua))
1119 newServer{address="127.0.0.1:%s"}
1120 """
1121
1122 def testNxDOViaLua(self):
1123 """
1124 Advanced: Nx DO queries via Lua
1125 """
1126 name = 'nxdo.advanced.tests.powerdns.com.'
1127 query = dns.message.make_query(name, 'A', 'IN')
1128 response = dns.message.make_response(query)
1129 rrset = dns.rrset.from_text(name,
1130 3600,
1131 dns.rdataclass.IN,
1132 dns.rdatatype.AAAA,
1133 '::1')
1134 response.answer.append(rrset)
1135 queryWithDO = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
1136 doResponse = dns.message.make_response(queryWithDO)
1137 doResponse.set_rcode(dns.rcode.NXDOMAIN)
1138
1139 # without DO
1140 for method in ("sendUDPQuery", "sendTCPQuery"):
1141 sender = getattr(self, method)
1142 (receivedQuery, receivedResponse) = sender(query, response)
1143 self.assertTrue(receivedQuery)
1144 self.assertTrue(receivedResponse)
1145 receivedQuery.id = query.id
1146 self.assertEquals(query, receivedQuery)
1147 self.assertEquals(receivedResponse, response)
1148
1149 # with DO
1150 for method in ("sendUDPQuery", "sendTCPQuery"):
1151 sender = getattr(self, method)
1152 (_, receivedResponse) = sender(queryWithDO, response=None, useQueue=False)
1153 self.assertTrue(receivedResponse)
1154 doResponse.id = receivedResponse.id
1155 self.assertEquals(receivedResponse, doResponse)
1156
1157 class TestAdvancedLuaRefused(DNSDistTest):
1158
1159 _config_template = """
1160 function refuse(dq)
1161 return DNSAction.Refused, ""
1162 end
1163 addAction(AllRule(), LuaAction(refuse))
1164 newServer{address="127.0.0.1:%s"}
1165 """
1166
1167 def testRefusedViaLua(self):
1168 """
1169 Advanced: Refused via Lua
1170 """
1171 name = 'refused.advanced.tests.powerdns.com.'
1172 query = dns.message.make_query(name, 'A', 'IN')
1173 response = dns.message.make_response(query)
1174 rrset = dns.rrset.from_text(name,
1175 3600,
1176 dns.rdataclass.IN,
1177 dns.rdatatype.AAAA,
1178 '::1')
1179 response.answer.append(rrset)
1180 refusedResponse = dns.message.make_response(query)
1181 refusedResponse.set_rcode(dns.rcode.REFUSED)
1182
1183 for method in ("sendUDPQuery", "sendTCPQuery"):
1184 sender = getattr(self, method)
1185 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1186 self.assertTrue(receivedResponse)
1187 refusedResponse.id = receivedResponse.id
1188 self.assertEquals(receivedResponse, refusedResponse)
1189
1190 class TestAdvancedLuaActionReturnSyntax(DNSDistTest):
1191
1192 _config_template = """
1193 function refuse(dq)
1194 return DNSAction.Refused
1195 end
1196 addAction(AllRule(), LuaAction(refuse))
1197 newServer{address="127.0.0.1:%s"}
1198 """
1199
1200 def testRefusedWithEmptyRule(self):
1201 """
1202 Advanced: Short syntax for LuaAction return values
1203 """
1204 name = 'short.refused.advanced.tests.powerdns.com.'
1205 query = dns.message.make_query(name, 'A', 'IN')
1206 response = dns.message.make_response(query)
1207 rrset = dns.rrset.from_text(name,
1208 3600,
1209 dns.rdataclass.IN,
1210 dns.rdatatype.AAAA,
1211 '::1')
1212 response.answer.append(rrset)
1213 refusedResponse = dns.message.make_response(query)
1214 refusedResponse.set_rcode(dns.rcode.REFUSED)
1215
1216 for method in ("sendUDPQuery", "sendTCPQuery"):
1217 sender = getattr(self, method)
1218 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1219 self.assertTrue(receivedResponse)
1220 refusedResponse.id = receivedResponse.id
1221 self.assertEquals(receivedResponse, refusedResponse)
1222
1223 class TestAdvancedLuaTruncated(DNSDistTest):
1224
1225 _config_template = """
1226 function trunc(dq)
1227 if not dq.tcp then
1228 return DNSAction.Truncate, ""
1229 end
1230 return DNSAction.None, ""
1231 end
1232 addAction(AllRule(), LuaAction(trunc))
1233 newServer{address="127.0.0.1:%s"}
1234 """
1235
1236 def testTCViaLua(self):
1237 """
1238 Advanced: TC via Lua
1239 """
1240 name = 'tc.advanced.tests.powerdns.com.'
1241 query = dns.message.make_query(name, 'A', 'IN')
1242 response = dns.message.make_response(query)
1243 rrset = dns.rrset.from_text(name,
1244 3600,
1245 dns.rdataclass.IN,
1246 dns.rdatatype.AAAA,
1247 '::1')
1248 response.answer.append(rrset)
1249
1250 truncatedResponse = dns.message.make_response(query)
1251 truncatedResponse.flags |= dns.flags.TC
1252
1253 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
1254 self.assertTrue(receivedResponse)
1255 truncatedResponse.id = receivedResponse.id
1256 self.assertEquals(receivedResponse, truncatedResponse)
1257
1258 # no truncation over TCP
1259 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
1260 self.assertTrue(receivedQuery)
1261 self.assertTrue(receivedResponse)
1262 receivedQuery.id = query.id
1263 self.assertEquals(query, receivedQuery)
1264 self.assertEquals(receivedResponse, response)
1265
1266 class TestStatNodeRespRingSince(DNSDistTest):
1267
1268 _consoleKey = DNSDistTest.generateConsoleKey()
1269 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
1270 _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
1271 _config_template = """
1272 setKey("%s")
1273 controlSocket("127.0.0.1:%s")
1274 s1 = newServer{address="127.0.0.1:%s"}
1275 s1:setUp()
1276 function visitor(node, self, childstat)
1277 table.insert(nodesSeen, node.fullname)
1278 end
1279 """
1280
1281 def testStatNodeRespRingSince(self):
1282 """
1283 Advanced: StatNodeRespRing with optional since parameter
1284
1285 """
1286 name = 'statnodesince.advanced.tests.powerdns.com.'
1287 query = dns.message.make_query(name, 'A', 'IN')
1288 response = dns.message.make_response(query)
1289 rrset = dns.rrset.from_text(name,
1290 1,
1291 dns.rdataclass.IN,
1292 dns.rdatatype.A,
1293 '127.0.0.1')
1294 response.answer.append(rrset)
1295
1296 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1297 self.assertTrue(receivedQuery)
1298 self.assertTrue(receivedResponse)
1299 receivedQuery.id = query.id
1300 self.assertEquals(query, receivedQuery)
1301 self.assertEquals(response, receivedResponse)
1302
1303 self.sendConsoleCommand("nodesSeen = {}")
1304 self.sendConsoleCommand("statNodeRespRing(visitor)")
1305 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1306 nodes = nodes.strip("\n")
1307 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1308 advanced.tests.powerdns.com.
1309 tests.powerdns.com.
1310 powerdns.com.
1311 com.""")
1312
1313 self.sendConsoleCommand("nodesSeen = {}")
1314 self.sendConsoleCommand("statNodeRespRing(visitor, 0)")
1315 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1316 nodes = nodes.strip("\n")
1317 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1318 advanced.tests.powerdns.com.
1319 tests.powerdns.com.
1320 powerdns.com.
1321 com.""")
1322
1323 time.sleep(5)
1324
1325 self.sendConsoleCommand("nodesSeen = {}")
1326 self.sendConsoleCommand("statNodeRespRing(visitor)")
1327 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1328 nodes = nodes.strip("\n")
1329 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1330 advanced.tests.powerdns.com.
1331 tests.powerdns.com.
1332 powerdns.com.
1333 com.""")
1334
1335 self.sendConsoleCommand("nodesSeen = {}")
1336 self.sendConsoleCommand("statNodeRespRing(visitor, 5)")
1337 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1338 nodes = nodes.strip("\n")
1339 self.assertEquals(nodes, """""")
1340
1341 self.sendConsoleCommand("nodesSeen = {}")
1342 self.sendConsoleCommand("statNodeRespRing(visitor, 10)")
1343 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1344 nodes = nodes.strip("\n")
1345 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1346 advanced.tests.powerdns.com.
1347 tests.powerdns.com.
1348 powerdns.com.
1349 com.""")
1350
1351 class TestAdvancedRD(DNSDistTest):
1352
1353 _config_template = """
1354 addAction(RDRule(), RCodeAction(dnsdist.REFUSED))
1355 newServer{address="127.0.0.1:%s"}
1356 """
1357
1358 def testAdvancedRDRefused(self):
1359 """
1360 Advanced: RD query is refused
1361 """
1362 name = 'rd.advanced.tests.powerdns.com.'
1363 query = dns.message.make_query(name, 'A', 'IN')
1364 expectedResponse = dns.message.make_response(query)
1365 expectedResponse.set_rcode(dns.rcode.REFUSED)
1366
1367 for method in ("sendUDPQuery", "sendTCPQuery"):
1368 sender = getattr(self, method)
1369 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1370 self.assertEquals(receivedResponse, expectedResponse)
1371
1372 def testAdvancedNoRDAllowed(self):
1373 """
1374 Advanced: No-RD query is allowed
1375 """
1376 name = 'no-rd.advanced.tests.powerdns.com.'
1377 query = dns.message.make_query(name, 'A', 'IN')
1378 query.flags &= ~dns.flags.RD
1379 response = dns.message.make_response(query)
1380
1381 for method in ("sendUDPQuery", "sendTCPQuery"):
1382 sender = getattr(self, method)
1383 (receivedQuery, receivedResponse) = sender(query, response)
1384 receivedQuery.id = query.id
1385 self.assertEquals(receivedQuery, query)
1386 self.assertEquals(receivedResponse, response)
1387
1388 class TestAdvancedGetLocalPort(DNSDistTest):
1389
1390 _config_template = """
1391 function answerBasedOnLocalPort(dq)
1392 local port = dq.localaddr:getPort()
1393 return DNSAction.Spoof, "port-was-"..port..".local-port.advanced.tests.powerdns.com."
1394 end
1395 addAction("local-port.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
1396 newServer{address="127.0.0.1:%s"}
1397 """
1398
1399 def testAdvancedGetLocalPort(self):
1400 """
1401 Advanced: Return CNAME containing the local port
1402 """
1403 name = 'local-port.advanced.tests.powerdns.com.'
1404 query = dns.message.make_query(name, 'A', 'IN')
1405 # dnsdist set RA = RD for spoofed responses
1406 query.flags &= ~dns.flags.RD
1407
1408 response = dns.message.make_response(query)
1409 rrset = dns.rrset.from_text(name,
1410 60,
1411 dns.rdataclass.IN,
1412 dns.rdatatype.CNAME,
1413 'port-was-{}.local-port.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
1414 response.answer.append(rrset)
1415
1416 for method in ("sendUDPQuery", "sendTCPQuery"):
1417 sender = getattr(self, method)
1418 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1419 self.assertEquals(receivedResponse, response)
1420
1421 class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest):
1422
1423 _config_template = """
1424 function answerBasedOnLocalPort(dq)
1425 local port = dq.localaddr:getPort()
1426 return DNSAction.Spoof, "port-was-"..port..".local-port-any.advanced.tests.powerdns.com."
1427 end
1428 addAction("local-port-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
1429 newServer{address="127.0.0.1:%s"}
1430 """
1431 _dnsDistListeningAddr = "0.0.0.0"
1432
1433 def testAdvancedGetLocalPortOnAnyBind(self):
1434 """
1435 Advanced: Return CNAME containing the local port for an ANY bind
1436 """
1437 name = 'local-port-any.advanced.tests.powerdns.com.'
1438 query = dns.message.make_query(name, 'A', 'IN')
1439 # dnsdist set RA = RD for spoofed responses
1440 query.flags &= ~dns.flags.RD
1441
1442 response = dns.message.make_response(query)
1443 rrset = dns.rrset.from_text(name,
1444 60,
1445 dns.rdataclass.IN,
1446 dns.rdatatype.CNAME,
1447 'port-was-{}.local-port-any.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
1448 response.answer.append(rrset)
1449
1450 for method in ("sendUDPQuery", "sendTCPQuery"):
1451 sender = getattr(self, method)
1452 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1453 self.assertEquals(receivedResponse, response)
1454
1455 class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
1456
1457 _config_template = """
1458 function answerBasedOnLocalAddress(dq)
1459 local dest = dq.localaddr:toString()
1460 local i, j = string.find(dest, "[0-9.]+")
1461 local addr = string.sub(dest, i, j)
1462 local dashAddr = string.gsub(addr, "[.]", "-")
1463 return DNSAction.Spoof, "address-was-"..dashAddr..".local-address-any.advanced.tests.powerdns.com."
1464 end
1465 addAction("local-address-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalAddress))
1466 newServer{address="127.0.0.1:%s"}
1467 """
1468 _dnsDistListeningAddr = "0.0.0.0"
1469
1470 def testAdvancedGetLocalAddressOnAnyBind(self):
1471 """
1472 Advanced: Return CNAME containing the local address for an ANY bind
1473 """
1474 name = 'local-address-any.advanced.tests.powerdns.com.'
1475 query = dns.message.make_query(name, 'A', 'IN')
1476 # dnsdist set RA = RD for spoofed responses
1477 query.flags &= ~dns.flags.RD
1478
1479 response = dns.message.make_response(query)
1480 rrset = dns.rrset.from_text(name,
1481 60,
1482 dns.rdataclass.IN,
1483 dns.rdatatype.CNAME,
1484 'address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.')
1485 response.answer.append(rrset)
1486
1487 for method in ("sendUDPQuery", "sendTCPQuery"):
1488 sender = getattr(self, method)
1489 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1490 self.assertEquals(receivedResponse, response)
1491
1492 class TestAdvancedLuaTempFailureTTL(DNSDistTest):
1493
1494 _config_template = """
1495 function testAction(dq)
1496 if dq.tempFailureTTL ~= nil then
1497 return DNSAction.Spoof, "initially.not.nil.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1498 end
1499 dq.tempFailureTTL = 30
1500 if dq.tempFailureTTL ~= 30 then
1501 return DNSAction.Spoof, "after.set.not.expected.value.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1502 end
1503 dq.tempFailureTTL = nil
1504 if dq.tempFailureTTL ~= nil then
1505 return DNSAction.Spoof, "after.unset.not.nil.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1506 end
1507 return DNSAction.None, ""
1508 end
1509 addAction(AllRule(), LuaAction(testAction))
1510 newServer{address="127.0.0.1:%s"}
1511 """
1512
1513 def testTempFailureTTLBinding(self):
1514 """
1515 Advanced: Exercise dq.tempFailureTTL Lua binding
1516 """
1517 name = 'tempfailurettlbinding.advanced.tests.powerdns.com.'
1518 query = dns.message.make_query(name, 'A', 'IN')
1519 response = dns.message.make_response(query)
1520 rrset = dns.rrset.from_text(name,
1521 3600,
1522 dns.rdataclass.IN,
1523 dns.rdatatype.AAAA,
1524 '::1')
1525 response.answer.append(rrset)
1526
1527 for method in ("sendUDPQuery", "sendTCPQuery"):
1528 sender = getattr(self, method)
1529 (receivedQuery, receivedResponse) = sender(query, response)
1530 self.assertTrue(receivedQuery)
1531 self.assertTrue(receivedResponse)
1532 receivedQuery.id = query.id
1533 self.assertEquals(query, receivedQuery)
1534 self.assertEquals(receivedResponse, response)
1535
1536 class TestAdvancedEDNSOptionRule(DNSDistTest):
1537
1538 _config_template = """
1539 newServer{address="127.0.0.1:%s"}
1540 addAction(EDNSOptionRule(EDNSOptionCode.ECS), DropAction())
1541 """
1542
1543 def testDropped(self):
1544 """
1545 Advanced: A question with ECS is dropped
1546 """
1547
1548 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1549
1550 ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
1551 query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
1552
1553 for method in ("sendUDPQuery", "sendTCPQuery"):
1554 sender = getattr(self, method)
1555 (_, receivedResponse) = sender(query, response=None)
1556 self.assertEquals(receivedResponse, None)
1557
1558 def testReplied(self):
1559 """
1560 Advanced: A question without ECS is answered
1561 """
1562
1563 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1564
1565 # both with EDNS
1566 query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[], payload=512)
1567 response = dns.message.make_response(query)
1568
1569 for method in ("sendUDPQuery", "sendTCPQuery"):
1570 sender = getattr(self, method)
1571 (receivedQuery, receivedResponse) = sender(query, response)
1572 self.assertTrue(receivedQuery)
1573 self.assertTrue(receivedResponse)
1574
1575 receivedQuery.id = query.id
1576 self.assertEquals(query, receivedQuery)
1577 self.assertEquals(receivedResponse, response)
1578
1579 # and with no EDNS at all
1580 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1581 response = dns.message.make_response(query)
1582
1583 for method in ("sendUDPQuery", "sendTCPQuery"):
1584 sender = getattr(self, method)
1585 (receivedQuery, receivedResponse) = sender(query, response)
1586 self.assertTrue(receivedQuery)
1587 self.assertTrue(receivedResponse)
1588
1589 receivedQuery.id = query.id
1590 self.assertEquals(query, receivedQuery)
1591 self.assertEquals(receivedResponse, response)
1592
1593 class TestAdvancedAllowHeaderOnly(DNSDistTest):
1594
1595 _config_template = """
1596 newServer{address="127.0.0.1:%s"}
1597 setAllowEmptyResponse(true)
1598 """
1599
1600 def testHeaderOnlyRefused(self):
1601 """
1602 Advanced: Header-only refused response
1603 """
1604 name = 'header-only-refused-response.advanced.tests.powerdns.com.'
1605 query = dns.message.make_query(name, 'A', 'IN')
1606 response = dns.message.make_response(query)
1607 response.set_rcode(dns.rcode.REFUSED)
1608 response.question = []
1609
1610 for method in ("sendUDPQuery", "sendTCPQuery"):
1611 sender = getattr(self, method)
1612 (receivedQuery, receivedResponse) = sender(query, response)
1613 self.assertTrue(receivedQuery)
1614 receivedQuery.id = query.id
1615 self.assertEquals(query, receivedQuery)
1616 self.assertEquals(receivedResponse, response)
1617
1618 def testHeaderOnlyNoErrorResponse(self):
1619 """
1620 Advanced: Header-only NoError response should be allowed
1621 """
1622 name = 'header-only-noerror-response.advanced.tests.powerdns.com.'
1623 query = dns.message.make_query(name, 'A', 'IN')
1624 response = dns.message.make_response(query)
1625 response.question = []
1626
1627 for method in ("sendUDPQuery", "sendTCPQuery"):
1628 sender = getattr(self, method)
1629 (receivedQuery, receivedResponse) = sender(query, response)
1630 self.assertTrue(receivedQuery)
1631 receivedQuery.id = query.id
1632 self.assertEquals(query, receivedQuery)
1633 self.assertEquals(receivedResponse, response)
1634
1635 def testHeaderOnlyNXDResponse(self):
1636 """
1637 Advanced: Header-only NXD response should be allowed
1638 """
1639 name = 'header-only-nxd-response.advanced.tests.powerdns.com.'
1640 query = dns.message.make_query(name, 'A', 'IN')
1641 response = dns.message.make_response(query)
1642 response.set_rcode(dns.rcode.NXDOMAIN)
1643 response.question = []
1644
1645 for method in ("sendUDPQuery", "sendTCPQuery"):
1646 sender = getattr(self, method)
1647 (receivedQuery, receivedResponse) = sender(query, response)
1648 self.assertTrue(receivedQuery)
1649 receivedQuery.id = query.id
1650 self.assertEquals(query, receivedQuery)
1651 self.assertEquals(receivedResponse, response)
1652
1653 class TestAdvancedEDNSVersionRule(DNSDistTest):
1654
1655 _config_template = """
1656 newServer{address="127.0.0.1:%s"}
1657 addAction(EDNSVersionRule(0), ERCodeAction(dnsdist.BADVERS))
1658 """
1659
1660 def testDropped(self):
1661 """
1662 Advanced: A question with ECS version larger than 0 is dropped
1663 """
1664
1665 name = 'ednsversionrule.advanced.tests.powerdns.com.'
1666
1667 query = dns.message.make_query(name, 'A', 'IN', use_edns=1)
1668 expectedResponse = dns.message.make_response(query)
1669 expectedResponse.set_rcode(dns.rcode.BADVERS)
1670
1671 for method in ("sendUDPQuery", "sendTCPQuery"):
1672 sender = getattr(self, method)
1673 (_, receivedResponse) = sender(query, response=None)
1674 self.assertEquals(receivedResponse, expectedResponse)
1675
1676 def testNoEDNS0Pass(self):
1677 """
1678 Advanced: A question with ECS version 0 goes through
1679 """
1680
1681 name = 'ednsversionrule.advanced.tests.powerdns.com.'
1682
1683 query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
1684 response = dns.message.make_response(query)
1685
1686 for method in ("sendUDPQuery", "sendTCPQuery"):
1687 sender = getattr(self, method)
1688 (receivedQuery, receivedResponse) = sender(query, response)
1689 receivedQuery.id = query.id
1690 self.assertEquals(query, receivedQuery)
1691 self.assertEquals(receivedResponse, response)
1692
1693 def testReplied(self):
1694 """
1695 Advanced: A question without ECS goes through
1696 """
1697
1698 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1699
1700 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1701 response = dns.message.make_response(query)
1702
1703 for method in ("sendUDPQuery", "sendTCPQuery"):
1704 sender = getattr(self, method)
1705 (receivedQuery, receivedResponse) = sender(query, response)
1706 receivedQuery.id = query.id
1707 self.assertEquals(query, receivedQuery)
1708 self.assertEquals(receivedResponse, response)
1709
1710 class TestSetRules(DNSDistTest):
1711
1712 _consoleKey = DNSDistTest.generateConsoleKey()
1713 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
1714 _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
1715 _config_template = """
1716 setKey("%s")
1717 controlSocket("127.0.0.1:%s")
1718 newServer{address="127.0.0.1:%s"}
1719 addAction(AllRule(), SpoofAction("192.0.2.1"))
1720 """
1721
1722 def testClearThenSetRules(self):
1723 """
1724 Advanced: Clear rules, set rules
1725
1726 """
1727 name = 'clearthensetrules.advanced.tests.powerdns.com.'
1728 query = dns.message.make_query(name, 'A', 'IN')
1729 # dnsdist set RA = RD for spoofed responses
1730 query.flags &= ~dns.flags.RD
1731 expectedResponse = dns.message.make_response(query)
1732 rrset = dns.rrset.from_text(name,
1733 60,
1734 dns.rdataclass.IN,
1735 dns.rdatatype.A,
1736 '192.0.2.1')
1737 expectedResponse.answer.append(rrset)
1738
1739 for method in ("sendUDPQuery", "sendTCPQuery"):
1740 sender = getattr(self, method)
1741
1742 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1743 self.assertTrue(receivedResponse)
1744 self.assertEquals(expectedResponse, receivedResponse)
1745
1746 # clear all the rules, we should not be spoofing and get a SERVFAIL from the responder instead
1747 self.sendConsoleCommand("clearRules()")
1748
1749 expectedResponse = dns.message.make_response(query)
1750 expectedResponse.set_rcode(dns.rcode.SERVFAIL)
1751
1752 for method in ("sendUDPQuery", "sendTCPQuery"):
1753 sender = getattr(self, method)
1754
1755 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1756 self.assertTrue(receivedResponse)
1757 self.assertEquals(expectedResponse, receivedResponse)
1758
1759 # insert a new spoofing rule
1760 self.sendConsoleCommand("setRules({ newRuleAction(AllRule(), SpoofAction(\"192.0.2.2\")) })")
1761
1762 expectedResponse = dns.message.make_response(query)
1763 rrset = dns.rrset.from_text(name,
1764 60,
1765 dns.rdataclass.IN,
1766 dns.rdatatype.A,
1767 '192.0.2.2')
1768 expectedResponse.answer.append(rrset)
1769
1770 for method in ("sendUDPQuery", "sendTCPQuery"):
1771 sender = getattr(self, method)
1772
1773 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1774 self.assertTrue(receivedResponse)
1775 self.assertEquals(expectedResponse, receivedResponse)