]> git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Advanced.py
dnsdist: Support setting the value of AA, AD and RA when spoofing
[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 # dnsdist sets RA = RD for TC responses
430 query.flags &= ~dns.flags.RD
431
432 response = dns.message.make_response(query)
433 rrset = dns.rrset.from_text(name,
434 3600,
435 dns.rdataclass.IN,
436 dns.rdatatype.A,
437 '127.0.0.1')
438
439 response.answer.append(rrset)
440
441 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
442 self.assertTrue(receivedQuery)
443 self.assertTrue(receivedResponse)
444 receivedQuery.id = query.id
445 self.assertEquals(query, receivedQuery)
446 self.assertEquals(receivedResponse, response)
447
448 expectedResponse = dns.message.make_response(query)
449 expectedResponse.flags |= dns.flags.TC
450
451 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
452 self.assertEquals(receivedResponse, expectedResponse)
453
454 class TestAdvancedAndNot(DNSDistTest):
455
456 _config_template = """
457 addAction(AndRule({NotRule(QTypeRule("A")), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
458 newServer{address="127.0.0.1:%s"}
459 """
460 def testAOverUDPReturnsNotImplementedCanary(self):
461 """
462 Advanced: !A && UDP canary
463
464 dnsdist is configured to reply 'not implemented' for query
465 over UDP AND !qtype A.
466 We send an A query over UDP and TCP, and check that the
467 response is OK.
468 """
469 name = 'andnot.advanced.tests.powerdns.com.'
470 query = dns.message.make_query(name, 'A', 'IN')
471 response = dns.message.make_response(query)
472 rrset = dns.rrset.from_text(name,
473 3600,
474 dns.rdataclass.IN,
475 dns.rdatatype.A,
476 '127.0.0.1')
477 response.answer.append(rrset)
478
479 for method in ("sendUDPQuery", "sendTCPQuery"):
480 sender = getattr(self, method)
481 (receivedQuery, receivedResponse) = sender(query, response)
482 self.assertTrue(receivedQuery)
483 self.assertTrue(receivedResponse)
484 receivedQuery.id = query.id
485 self.assertEquals(query, receivedQuery)
486 self.assertEquals(receivedResponse, response)
487
488 def testAOverUDPReturnsNotImplemented(self):
489 """
490 Advanced: !A && UDP
491
492 dnsdist is configured to reply 'not implemented' for query
493 over UDP AND !qtype A.
494 We send a TXT query over UDP and TCP, and check that the
495 response is OK for TCP and 'not implemented' for UDP.
496 """
497 name = 'andnot.advanced.tests.powerdns.com.'
498 query = dns.message.make_query(name, 'TXT', 'IN')
499
500 expectedResponse = dns.message.make_response(query)
501 expectedResponse.set_rcode(dns.rcode.NOTIMP)
502
503 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
504 self.assertEquals(receivedResponse, expectedResponse)
505
506 response = dns.message.make_response(query)
507 rrset = dns.rrset.from_text(name,
508 3600,
509 dns.rdataclass.IN,
510 dns.rdatatype.TXT,
511 'nothing to see here')
512 response.answer.append(rrset)
513
514 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
515 self.assertTrue(receivedQuery)
516 self.assertTrue(receivedResponse)
517 receivedQuery.id = query.id
518 self.assertEquals(query, receivedQuery)
519 self.assertEquals(receivedResponse, response)
520
521 class TestAdvancedOr(DNSDistTest):
522
523 _config_template = """
524 addAction(OrRule({QTypeRule("A"), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
525 newServer{address="127.0.0.1:%s"}
526 """
527 def testAAAAOverUDPReturnsNotImplemented(self):
528 """
529 Advanced: A || UDP: AAAA
530
531 dnsdist is configured to reply 'not implemented' for query
532 over UDP OR qtype A.
533 We send an AAAA query over UDP and TCP, and check that the
534 response is 'not implemented' for UDP and OK for TCP.
535 """
536 name = 'aorudp.advanced.tests.powerdns.com.'
537 query = dns.message.make_query(name, 'AAAA', 'IN')
538 response = dns.message.make_response(query)
539 rrset = dns.rrset.from_text(name,
540 3600,
541 dns.rdataclass.IN,
542 dns.rdatatype.AAAA,
543 '::1')
544 response.answer.append(rrset)
545
546 expectedResponse = dns.message.make_response(query)
547 expectedResponse.set_rcode(dns.rcode.NOTIMP)
548
549 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
550 self.assertEquals(receivedResponse, expectedResponse)
551
552 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
553 self.assertTrue(receivedQuery)
554 self.assertTrue(receivedResponse)
555 receivedQuery.id = query.id
556 self.assertEquals(query, receivedQuery)
557 self.assertEquals(receivedResponse, response)
558
559 def testAOverUDPReturnsNotImplemented(self):
560 """
561 Advanced: A || UDP: A
562
563 dnsdist is configured to reply 'not implemented' for query
564 over UDP OR qtype A.
565 We send an A query over UDP and TCP, and check that the
566 response is 'not implemented' for both.
567 """
568 name = 'aorudp.advanced.tests.powerdns.com.'
569 query = dns.message.make_query(name, 'A', 'IN')
570
571 expectedResponse = dns.message.make_response(query)
572 expectedResponse.set_rcode(dns.rcode.NOTIMP)
573
574 for method in ("sendUDPQuery", "sendTCPQuery"):
575 sender = getattr(self, method)
576 (_, receivedResponse) = sender(query, response=None, useQueue=False)
577 self.assertEquals(receivedResponse, expectedResponse)
578
579
580 class TestAdvancedLogAction(DNSDistTest):
581
582 _config_template = """
583 newServer{address="127.0.0.1:%s"}
584 addAction(AllRule(), LogAction("dnsdist.log", false))
585 """
586 def testAdvancedLogAction(self):
587 """
588 Advanced: Log all queries
589
590 """
591 count = 50
592 name = 'logaction.advanced.tests.powerdns.com.'
593 query = dns.message.make_query(name, 'A', 'IN')
594 response = dns.message.make_response(query)
595 rrset = dns.rrset.from_text(name,
596 3600,
597 dns.rdataclass.IN,
598 dns.rdatatype.A,
599 '127.0.0.1')
600 response.answer.append(rrset)
601
602 for _ in range(count):
603 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
604 self.assertTrue(receivedQuery)
605 self.assertTrue(receivedResponse)
606 receivedQuery.id = query.id
607 self.assertEquals(query, receivedQuery)
608 self.assertEquals(response, receivedResponse)
609
610 self.assertTrue(os.path.isfile('dnsdist.log'))
611 self.assertTrue(os.stat('dnsdist.log').st_size > 0)
612
613 class TestAdvancedDNSSEC(DNSDistTest):
614
615 _config_template = """
616 newServer{address="127.0.0.1:%s"}
617 addAction(DNSSECRule(), DropAction())
618 """
619 def testAdvancedDNSSECDrop(self):
620 """
621 Advanced: DNSSEC Rule
622
623 """
624 name = 'dnssec.advanced.tests.powerdns.com.'
625 query = dns.message.make_query(name, 'A', 'IN')
626 doquery = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
627 response = dns.message.make_response(query)
628 rrset = dns.rrset.from_text(name,
629 3600,
630 dns.rdataclass.IN,
631 dns.rdatatype.A,
632 '127.0.0.1')
633 response.answer.append(rrset)
634
635 for method in ("sendUDPQuery", "sendTCPQuery"):
636 sender = getattr(self, method)
637 (receivedQuery, receivedResponse) = sender(query, response)
638 self.assertTrue(receivedQuery)
639 self.assertTrue(receivedResponse)
640 receivedQuery.id = query.id
641 self.assertEquals(query, receivedQuery)
642 self.assertEquals(response, receivedResponse)
643
644 for method in ("sendUDPQuery", "sendTCPQuery"):
645 sender = getattr(self, method)
646 (_, receivedResponse) = sender(doquery, response)
647 self.assertEquals(receivedResponse, None)
648
649 class TestAdvancedQClass(DNSDistTest):
650
651 _config_template = """
652 newServer{address="127.0.0.1:%s"}
653 addAction(QClassRule(DNSClass.CHAOS), DropAction())
654 """
655 def testAdvancedQClassChaosDrop(self):
656 """
657 Advanced: Drop QClass CHAOS
658
659 """
660 name = 'qclasschaos.advanced.tests.powerdns.com.'
661 query = dns.message.make_query(name, 'TXT', 'CHAOS')
662
663 for method in ("sendUDPQuery", "sendTCPQuery"):
664 sender = getattr(self, method)
665 (_, receivedResponse) = sender(query, response=None)
666 self.assertEquals(receivedResponse, None)
667
668 def testAdvancedQClassINAllow(self):
669 """
670 Advanced: Allow QClass IN
671
672 """
673 name = 'qclassin.advanced.tests.powerdns.com.'
674 query = dns.message.make_query(name, 'A', 'IN')
675 response = dns.message.make_response(query)
676 rrset = dns.rrset.from_text(name,
677 3600,
678 dns.rdataclass.IN,
679 dns.rdatatype.A,
680 '127.0.0.1')
681 response.answer.append(rrset)
682
683 for method in ("sendUDPQuery", "sendTCPQuery"):
684 sender = getattr(self, method)
685 (receivedQuery, receivedResponse) = sender(query, response)
686 self.assertTrue(receivedQuery)
687 self.assertTrue(receivedResponse)
688 receivedQuery.id = query.id
689 self.assertEquals(query, receivedQuery)
690 self.assertEquals(response, receivedResponse)
691
692 class TestAdvancedOpcode(DNSDistTest):
693
694 _config_template = """
695 newServer{address="127.0.0.1:%s"}
696 addAction(OpcodeRule(DNSOpcode.Notify), DropAction())
697 """
698 def testAdvancedOpcodeNotifyDrop(self):
699 """
700 Advanced: Drop Opcode NOTIFY
701
702 """
703 name = 'opcodenotify.advanced.tests.powerdns.com.'
704 query = dns.message.make_query(name, 'A', 'IN')
705 query.set_opcode(dns.opcode.NOTIFY)
706
707 for method in ("sendUDPQuery", "sendTCPQuery"):
708 sender = getattr(self, method)
709 (_, receivedResponse) = sender(query, response=None)
710 self.assertEquals(receivedResponse, None)
711
712 def testAdvancedOpcodeUpdateINAllow(self):
713 """
714 Advanced: Allow Opcode UPDATE
715
716 """
717 name = 'opcodeupdate.advanced.tests.powerdns.com.'
718 query = dns.message.make_query(name, 'A', 'IN')
719 query.set_opcode(dns.opcode.UPDATE)
720 response = dns.message.make_response(query)
721 rrset = dns.rrset.from_text(name,
722 3600,
723 dns.rdataclass.IN,
724 dns.rdatatype.A,
725 '127.0.0.1')
726 response.answer.append(rrset)
727
728 for method in ("sendUDPQuery", "sendTCPQuery"):
729 sender = getattr(self, method)
730 (receivedQuery, receivedResponse) = sender(query, response)
731 self.assertTrue(receivedQuery)
732 self.assertTrue(receivedResponse)
733 receivedQuery.id = query.id
734 self.assertEquals(query, receivedQuery)
735 self.assertEquals(response, receivedResponse)
736
737 class TestAdvancedNonTerminalRule(DNSDistTest):
738
739 _config_template = """
740 newServer{address="127.0.0.1:%s", pool="real"}
741 addAction(AllRule(), DisableValidationAction())
742 addAction(AllRule(), PoolAction("real"))
743 addAction(AllRule(), DropAction())
744 """
745 def testAdvancedNonTerminalRules(self):
746 """
747 Advanced: Non terminal rules
748
749 We check that DisableValidationAction() is applied
750 but does not stop the processing, then that
751 PoolAction() is applied _and_ stop the processing.
752 """
753 name = 'nonterminal.advanced.tests.powerdns.com.'
754 query = dns.message.make_query(name, 'A', 'IN')
755 expectedQuery = dns.message.make_query(name, 'A', 'IN')
756 expectedQuery.flags |= dns.flags.CD
757 response = dns.message.make_response(query)
758 rrset = dns.rrset.from_text(name,
759 3600,
760 dns.rdataclass.IN,
761 dns.rdatatype.A,
762 '192.0.2.1')
763 response.answer.append(rrset)
764
765 for method in ("sendUDPQuery", "sendTCPQuery"):
766 sender = getattr(self, method)
767 (receivedQuery, receivedResponse) = sender(query, response)
768 self.assertTrue(receivedQuery)
769 self.assertTrue(receivedResponse)
770 receivedQuery.id = expectedQuery.id
771 self.assertEquals(expectedQuery, receivedQuery)
772 self.assertEquals(response, receivedResponse)
773
774 class TestAdvancedStringOnlyServer(DNSDistTest):
775
776 _config_template = """
777 newServer("127.0.0.1:%s")
778 """
779
780 def testAdvancedStringOnlyServer(self):
781 """
782 Advanced: "string-only" server is placed in the default pool
783 """
784 name = 'string-only-server.advanced.tests.powerdns.com.'
785 query = dns.message.make_query(name, 'A', 'IN')
786 response = dns.message.make_response(query)
787 rrset = dns.rrset.from_text(name,
788 3600,
789 dns.rdataclass.IN,
790 dns.rdatatype.A,
791 '192.0.2.1')
792 response.answer.append(rrset)
793
794 for method in ("sendUDPQuery", "sendTCPQuery"):
795 sender = getattr(self, method)
796 (receivedQuery, receivedResponse) = sender(query, response)
797 self.assertTrue(receivedQuery)
798 self.assertTrue(receivedResponse)
799 receivedQuery.id = query.id
800 self.assertEquals(query, receivedQuery)
801 self.assertEquals(response, receivedResponse)
802
803 class TestAdvancedRestoreFlagsOnSelfResponse(DNSDistTest):
804
805 _config_template = """
806 addAction(AllRule(), DisableValidationAction())
807 addAction(AllRule(), SpoofAction("192.0.2.1"))
808 newServer{address="127.0.0.1:%s"}
809 """
810
811 def testAdvancedRestoreFlagsOnSpoofResponse(self):
812 """
813 Advanced: Restore flags on spoofed response
814
815 Send a query with CD flag cleared, dnsdist is
816 instructed to set it, then to spoof the response,
817 check that response has the flag cleared.
818 """
819 name = 'spoofed.restoreflags.advanced.tests.powerdns.com.'
820 query = dns.message.make_query(name, 'A', 'IN')
821 # dnsdist set RA = RD for spoofed responses
822 query.flags &= ~dns.flags.RD
823
824 response = dns.message.make_response(query)
825 rrset = dns.rrset.from_text(name,
826 60,
827 dns.rdataclass.IN,
828 dns.rdatatype.A,
829 '192.0.2.1')
830 response.answer.append(rrset)
831
832 for method in ("sendUDPQuery", "sendTCPQuery"):
833 sender = getattr(self, method)
834 (_, receivedResponse) = sender(query, response=None, useQueue=False)
835 self.assertTrue(receivedResponse)
836 self.assertEquals(response, receivedResponse)
837
838 class TestAdvancedQPS(DNSDistTest):
839
840 _config_template = """
841 addAction("qps.advanced.tests.powerdns.com", QPSAction(10))
842 newServer{address="127.0.0.1:%s"}
843 """
844
845 def testAdvancedQPSLimit(self):
846 """
847 Advanced: QPS Limit
848
849 Send queries to "qps.advanced.tests.powerdns.com."
850 check that dnsdist drops queries when the max QPS has been reached.
851 """
852 maxQPS = 10
853 name = 'qps.advanced.tests.powerdns.com.'
854 query = dns.message.make_query(name, 'A', 'IN')
855 response = dns.message.make_response(query)
856 rrset = dns.rrset.from_text(name,
857 60,
858 dns.rdataclass.IN,
859 dns.rdatatype.A,
860 '192.0.2.1')
861 response.answer.append(rrset)
862
863 for _ in range(maxQPS):
864 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
865 receivedQuery.id = query.id
866 self.assertEquals(query, receivedQuery)
867 self.assertEquals(response, receivedResponse)
868
869 # we should now be dropped
870 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
871 self.assertEquals(receivedResponse, None)
872
873 time.sleep(1)
874
875 # again, over TCP this time
876 for _ in range(maxQPS):
877 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
878 receivedQuery.id = query.id
879 self.assertEquals(query, receivedQuery)
880 self.assertEquals(response, receivedResponse)
881
882
883 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
884 self.assertEquals(receivedResponse, None)
885
886 class TestAdvancedQPSNone(DNSDistTest):
887
888 _config_template = """
889 addAction("qpsnone.advanced.tests.powerdns.com", QPSAction(100))
890 addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
891 newServer{address="127.0.0.1:%s"}
892 """
893
894 def testAdvancedQPSNone(self):
895 """
896 Advanced: Not matching QPS returns None, not Allow
897
898 Send queries to "qps.advanced.tests.powerdns.com."
899 check that the rule returns None when the QPS has not been
900 reached, not Allow.
901 """
902 name = 'qpsnone.advanced.tests.powerdns.com.'
903 query = dns.message.make_query(name, 'A', 'IN')
904 expectedResponse = dns.message.make_response(query)
905 expectedResponse.set_rcode(dns.rcode.REFUSED)
906
907 for method in ("sendUDPQuery", "sendTCPQuery"):
908 sender = getattr(self, method)
909 (_, receivedResponse) = sender(query, response=None, useQueue=False)
910 self.assertEquals(receivedResponse, expectedResponse)
911
912 class TestAdvancedNMGRule(DNSDistTest):
913
914 _config_template = """
915 allowed = newNMG()
916 allowed:addMask("192.0.2.1/32")
917 addAction(NotRule(NetmaskGroupRule(allowed)), RCodeAction(DNSRCode.REFUSED))
918 newServer{address="127.0.0.1:%s"}
919 """
920
921 def testAdvancedNMGRule(self):
922 """
923 Advanced: NMGRule should refuse our queries
924
925 Send queries to "nmgrule.advanced.tests.powerdns.com.",
926 check that we are getting a REFUSED response.
927 """
928 name = 'nmgrule.advanced.tests.powerdns.com.'
929 query = dns.message.make_query(name, 'A', 'IN')
930 expectedResponse = dns.message.make_response(query)
931 expectedResponse.set_rcode(dns.rcode.REFUSED)
932
933 for method in ("sendUDPQuery", "sendTCPQuery"):
934 sender = getattr(self, method)
935 (_, receivedResponse) = sender(query, response=None, useQueue=False)
936 self.assertEquals(receivedResponse, expectedResponse)
937
938 class TestDSTPortRule(DNSDistTest):
939
940 _config_params = ['_dnsDistPort', '_testServerPort']
941 _config_template = """
942 addAction(DSTPortRule(%d), RCodeAction(DNSRCode.REFUSED))
943 newServer{address="127.0.0.1:%s"}
944 """
945
946 def testDSTPortRule(self):
947 """
948 Advanced: DSTPortRule should capture our queries
949
950 Send queries to "dstportrule.advanced.tests.powerdns.com.",
951 check that we are getting a REFUSED response.
952 """
953
954 name = 'dstportrule.advanced.tests.powerdns.com.'
955 query = dns.message.make_query(name, 'A', 'IN')
956 expectedResponse = dns.message.make_response(query)
957 expectedResponse.set_rcode(dns.rcode.REFUSED)
958
959 for method in ("sendUDPQuery", "sendTCPQuery"):
960 sender = getattr(self, method)
961 (_, receivedResponse) = sender(query, response=None, useQueue=False)
962 self.assertEquals(receivedResponse, expectedResponse)
963
964 class TestAdvancedLabelsCountRule(DNSDistTest):
965
966 _config_template = """
967 addAction(QNameLabelsCountRule(5,6), RCodeAction(DNSRCode.REFUSED))
968 newServer{address="127.0.0.1:%s"}
969 """
970
971 def testAdvancedLabelsCountRule(self):
972 """
973 Advanced: QNameLabelsCountRule(5,6)
974 """
975 # 6 labels, we should be fine
976 name = 'ok.labelscount.advanced.tests.powerdns.com.'
977 query = dns.message.make_query(name, 'A', 'IN')
978 response = dns.message.make_response(query)
979 rrset = dns.rrset.from_text(name,
980 3600,
981 dns.rdataclass.IN,
982 dns.rdatatype.A,
983 '192.0.2.1')
984 response.answer.append(rrset)
985
986 for method in ("sendUDPQuery", "sendTCPQuery"):
987 sender = getattr(self, method)
988 (receivedQuery, receivedResponse) = sender(query, response)
989 self.assertTrue(receivedQuery)
990 self.assertTrue(receivedResponse)
991 receivedQuery.id = query.id
992 self.assertEquals(query, receivedQuery)
993 self.assertEquals(response, receivedResponse)
994
995 # more than 6 labels, the query should be refused
996 name = 'not.ok.labelscount.advanced.tests.powerdns.com.'
997 query = dns.message.make_query(name, 'A', 'IN')
998 expectedResponse = dns.message.make_response(query)
999 expectedResponse.set_rcode(dns.rcode.REFUSED)
1000
1001 for method in ("sendUDPQuery", "sendTCPQuery"):
1002 sender = getattr(self, method)
1003 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1004 self.assertEquals(receivedResponse, expectedResponse)
1005
1006 # less than 5 labels, the query should be refused
1007 name = 'labelscountadvanced.tests.powerdns.com.'
1008 query = dns.message.make_query(name, 'A', 'IN')
1009 expectedResponse = dns.message.make_response(query)
1010 expectedResponse.set_rcode(dns.rcode.REFUSED)
1011
1012 for method in ("sendUDPQuery", "sendTCPQuery"):
1013 sender = getattr(self, method)
1014 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1015 self.assertEquals(receivedResponse, expectedResponse)
1016
1017 class TestAdvancedWireLengthRule(DNSDistTest):
1018
1019 _config_template = """
1020 addAction(QNameWireLengthRule(54,56), RCodeAction(DNSRCode.REFUSED))
1021 newServer{address="127.0.0.1:%s"}
1022 """
1023
1024 def testAdvancedWireLengthRule(self):
1025 """
1026 Advanced: QNameWireLengthRule(54,56)
1027 """
1028 name = 'longenough.qnamewirelength.advanced.tests.powerdns.com.'
1029 query = dns.message.make_query(name, 'A', 'IN')
1030 response = dns.message.make_response(query)
1031 rrset = dns.rrset.from_text(name,
1032 3600,
1033 dns.rdataclass.IN,
1034 dns.rdatatype.A,
1035 '192.0.2.1')
1036 response.answer.append(rrset)
1037
1038 for method in ("sendUDPQuery", "sendTCPQuery"):
1039 sender = getattr(self, method)
1040 (receivedQuery, receivedResponse) = sender(query, response)
1041 self.assertTrue(receivedQuery)
1042 self.assertTrue(receivedResponse)
1043 receivedQuery.id = query.id
1044 self.assertEquals(query, receivedQuery)
1045 self.assertEquals(response, receivedResponse)
1046
1047 # too short, the query should be refused
1048 name = 'short.qnamewirelength.advanced.tests.powerdns.com.'
1049 query = dns.message.make_query(name, 'A', 'IN')
1050 expectedResponse = dns.message.make_response(query)
1051 expectedResponse.set_rcode(dns.rcode.REFUSED)
1052
1053 for method in ("sendUDPQuery", "sendTCPQuery"):
1054 sender = getattr(self, method)
1055 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1056 self.assertEquals(receivedResponse, expectedResponse)
1057
1058 # too long, the query should be refused
1059 name = 'toolongtobevalid.qnamewirelength.advanced.tests.powerdns.com.'
1060 query = dns.message.make_query(name, 'A', 'IN')
1061 expectedResponse = dns.message.make_response(query)
1062 expectedResponse.set_rcode(dns.rcode.REFUSED)
1063
1064 for method in ("sendUDPQuery", "sendTCPQuery"):
1065 sender = getattr(self, method)
1066 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1067 self.assertEquals(receivedResponse, expectedResponse)
1068
1069 class TestAdvancedIncludeDir(DNSDistTest):
1070
1071 _config_template = """
1072 -- this directory contains a file allowing includedir.advanced.tests.powerdns.com.
1073 includeDirectory('test-include-dir')
1074 newServer{address="127.0.0.1:%s"}
1075 """
1076
1077 def testAdvancedIncludeDirAllowed(self):
1078 """
1079 Advanced: includeDirectory()
1080 """
1081 name = 'includedir.advanced.tests.powerdns.com.'
1082 query = dns.message.make_query(name, 'A', 'IN')
1083 response = dns.message.make_response(query)
1084 rrset = dns.rrset.from_text(name,
1085 3600,
1086 dns.rdataclass.IN,
1087 dns.rdatatype.A,
1088 '192.0.2.1')
1089 response.answer.append(rrset)
1090
1091 for method in ("sendUDPQuery", "sendTCPQuery"):
1092 sender = getattr(self, method)
1093 (receivedQuery, receivedResponse) = sender(query, response)
1094 self.assertTrue(receivedQuery)
1095 self.assertTrue(receivedResponse)
1096 receivedQuery.id = query.id
1097 self.assertEquals(query, receivedQuery)
1098 self.assertEquals(response, receivedResponse)
1099
1100 # this one should be refused
1101 name = 'notincludedir.advanced.tests.powerdns.com.'
1102 query = dns.message.make_query(name, 'A', 'IN')
1103 expectedResponse = dns.message.make_response(query)
1104 expectedResponse.set_rcode(dns.rcode.REFUSED)
1105
1106 for method in ("sendUDPQuery", "sendTCPQuery"):
1107 sender = getattr(self, method)
1108 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1109 self.assertEquals(receivedResponse, expectedResponse)
1110
1111 class TestAdvancedLuaDO(DNSDistTest):
1112
1113 _config_template = """
1114 function nxDOLua(dq)
1115 if dq:getDO() then
1116 return DNSAction.Nxdomain, ""
1117 end
1118 return DNSAction.None, ""
1119 end
1120 addAction(AllRule(), LuaAction(nxDOLua))
1121 newServer{address="127.0.0.1:%s"}
1122 """
1123
1124 def testNxDOViaLua(self):
1125 """
1126 Advanced: Nx DO queries via Lua
1127 """
1128 name = 'nxdo.advanced.tests.powerdns.com.'
1129 query = dns.message.make_query(name, 'A', 'IN')
1130 response = dns.message.make_response(query)
1131 rrset = dns.rrset.from_text(name,
1132 3600,
1133 dns.rdataclass.IN,
1134 dns.rdatatype.AAAA,
1135 '::1')
1136 response.answer.append(rrset)
1137 queryWithDO = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
1138 doResponse = dns.message.make_response(queryWithDO)
1139 doResponse.set_rcode(dns.rcode.NXDOMAIN)
1140
1141 # without DO
1142 for method in ("sendUDPQuery", "sendTCPQuery"):
1143 sender = getattr(self, method)
1144 (receivedQuery, receivedResponse) = sender(query, response)
1145 self.assertTrue(receivedQuery)
1146 self.assertTrue(receivedResponse)
1147 receivedQuery.id = query.id
1148 self.assertEquals(query, receivedQuery)
1149 self.assertEquals(receivedResponse, response)
1150
1151 # with DO
1152 for method in ("sendUDPQuery", "sendTCPQuery"):
1153 sender = getattr(self, method)
1154 (_, receivedResponse) = sender(queryWithDO, response=None, useQueue=False)
1155 self.assertTrue(receivedResponse)
1156 doResponse.id = receivedResponse.id
1157 self.assertEquals(receivedResponse, doResponse)
1158
1159 class TestAdvancedLuaRefused(DNSDistTest):
1160
1161 _config_template = """
1162 function refuse(dq)
1163 return DNSAction.Refused, ""
1164 end
1165 addAction(AllRule(), LuaAction(refuse))
1166 newServer{address="127.0.0.1:%s"}
1167 """
1168
1169 def testRefusedViaLua(self):
1170 """
1171 Advanced: Refused via Lua
1172 """
1173 name = 'refused.advanced.tests.powerdns.com.'
1174 query = dns.message.make_query(name, 'A', 'IN')
1175 response = dns.message.make_response(query)
1176 rrset = dns.rrset.from_text(name,
1177 3600,
1178 dns.rdataclass.IN,
1179 dns.rdatatype.AAAA,
1180 '::1')
1181 response.answer.append(rrset)
1182 refusedResponse = dns.message.make_response(query)
1183 refusedResponse.set_rcode(dns.rcode.REFUSED)
1184
1185 for method in ("sendUDPQuery", "sendTCPQuery"):
1186 sender = getattr(self, method)
1187 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1188 self.assertTrue(receivedResponse)
1189 refusedResponse.id = receivedResponse.id
1190 self.assertEquals(receivedResponse, refusedResponse)
1191
1192 class TestAdvancedLuaActionReturnSyntax(DNSDistTest):
1193
1194 _config_template = """
1195 function refuse(dq)
1196 return DNSAction.Refused
1197 end
1198 addAction(AllRule(), LuaAction(refuse))
1199 newServer{address="127.0.0.1:%s"}
1200 """
1201
1202 def testRefusedWithEmptyRule(self):
1203 """
1204 Advanced: Short syntax for LuaAction return values
1205 """
1206 name = 'short.refused.advanced.tests.powerdns.com.'
1207 query = dns.message.make_query(name, 'A', 'IN')
1208 response = dns.message.make_response(query)
1209 rrset = dns.rrset.from_text(name,
1210 3600,
1211 dns.rdataclass.IN,
1212 dns.rdatatype.AAAA,
1213 '::1')
1214 response.answer.append(rrset)
1215 refusedResponse = dns.message.make_response(query)
1216 refusedResponse.set_rcode(dns.rcode.REFUSED)
1217
1218 for method in ("sendUDPQuery", "sendTCPQuery"):
1219 sender = getattr(self, method)
1220 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1221 self.assertTrue(receivedResponse)
1222 refusedResponse.id = receivedResponse.id
1223 self.assertEquals(receivedResponse, refusedResponse)
1224
1225 class TestAdvancedLuaTruncated(DNSDistTest):
1226
1227 _config_template = """
1228 function trunc(dq)
1229 if not dq.tcp then
1230 return DNSAction.Truncate, ""
1231 end
1232 return DNSAction.None, ""
1233 end
1234 addAction(AllRule(), LuaAction(trunc))
1235 newServer{address="127.0.0.1:%s"}
1236 """
1237
1238 def testTCViaLua(self):
1239 """
1240 Advanced: TC via Lua
1241 """
1242 name = 'tc.advanced.tests.powerdns.com.'
1243 query = dns.message.make_query(name, 'A', 'IN')
1244 # dnsdist sets RA = RD for TC responses
1245 query.flags &= ~dns.flags.RD
1246 response = dns.message.make_response(query)
1247 rrset = dns.rrset.from_text(name,
1248 3600,
1249 dns.rdataclass.IN,
1250 dns.rdatatype.AAAA,
1251 '::1')
1252 response.answer.append(rrset)
1253
1254 truncatedResponse = dns.message.make_response(query)
1255 truncatedResponse.flags |= dns.flags.TC
1256
1257 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
1258 self.assertTrue(receivedResponse)
1259 truncatedResponse.id = receivedResponse.id
1260 self.assertEquals(receivedResponse, truncatedResponse)
1261
1262 # no truncation over TCP
1263 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
1264 self.assertTrue(receivedQuery)
1265 self.assertTrue(receivedResponse)
1266 receivedQuery.id = query.id
1267 self.assertEquals(query, receivedQuery)
1268 self.assertEquals(receivedResponse, response)
1269
1270 class TestStatNodeRespRingSince(DNSDistTest):
1271
1272 _consoleKey = DNSDistTest.generateConsoleKey()
1273 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
1274 _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
1275 _config_template = """
1276 setKey("%s")
1277 controlSocket("127.0.0.1:%s")
1278 s1 = newServer{address="127.0.0.1:%s"}
1279 s1:setUp()
1280 function visitor(node, self, childstat)
1281 table.insert(nodesSeen, node.fullname)
1282 end
1283 """
1284
1285 def testStatNodeRespRingSince(self):
1286 """
1287 Advanced: StatNodeRespRing with optional since parameter
1288
1289 """
1290 name = 'statnodesince.advanced.tests.powerdns.com.'
1291 query = dns.message.make_query(name, 'A', 'IN')
1292 response = dns.message.make_response(query)
1293 rrset = dns.rrset.from_text(name,
1294 1,
1295 dns.rdataclass.IN,
1296 dns.rdatatype.A,
1297 '127.0.0.1')
1298 response.answer.append(rrset)
1299
1300 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1301 self.assertTrue(receivedQuery)
1302 self.assertTrue(receivedResponse)
1303 receivedQuery.id = query.id
1304 self.assertEquals(query, receivedQuery)
1305 self.assertEquals(response, receivedResponse)
1306
1307 self.sendConsoleCommand("nodesSeen = {}")
1308 self.sendConsoleCommand("statNodeRespRing(visitor)")
1309 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1310 nodes = nodes.strip("\n")
1311 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1312 advanced.tests.powerdns.com.
1313 tests.powerdns.com.
1314 powerdns.com.
1315 com.""")
1316
1317 self.sendConsoleCommand("nodesSeen = {}")
1318 self.sendConsoleCommand("statNodeRespRing(visitor, 0)")
1319 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1320 nodes = nodes.strip("\n")
1321 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1322 advanced.tests.powerdns.com.
1323 tests.powerdns.com.
1324 powerdns.com.
1325 com.""")
1326
1327 time.sleep(5)
1328
1329 self.sendConsoleCommand("nodesSeen = {}")
1330 self.sendConsoleCommand("statNodeRespRing(visitor)")
1331 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1332 nodes = nodes.strip("\n")
1333 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1334 advanced.tests.powerdns.com.
1335 tests.powerdns.com.
1336 powerdns.com.
1337 com.""")
1338
1339 self.sendConsoleCommand("nodesSeen = {}")
1340 self.sendConsoleCommand("statNodeRespRing(visitor, 5)")
1341 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1342 nodes = nodes.strip("\n")
1343 self.assertEquals(nodes, """""")
1344
1345 self.sendConsoleCommand("nodesSeen = {}")
1346 self.sendConsoleCommand("statNodeRespRing(visitor, 10)")
1347 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1348 nodes = nodes.strip("\n")
1349 self.assertEquals(nodes, """statnodesince.advanced.tests.powerdns.com.
1350 advanced.tests.powerdns.com.
1351 tests.powerdns.com.
1352 powerdns.com.
1353 com.""")
1354
1355 class TestAdvancedRD(DNSDistTest):
1356
1357 _config_template = """
1358 addAction(RDRule(), RCodeAction(DNSRCode.REFUSED))
1359 newServer{address="127.0.0.1:%s"}
1360 """
1361
1362 def testAdvancedRDRefused(self):
1363 """
1364 Advanced: RD query is refused
1365 """
1366 name = 'rd.advanced.tests.powerdns.com.'
1367 query = dns.message.make_query(name, 'A', 'IN')
1368 expectedResponse = dns.message.make_response(query)
1369 expectedResponse.set_rcode(dns.rcode.REFUSED)
1370
1371 for method in ("sendUDPQuery", "sendTCPQuery"):
1372 sender = getattr(self, method)
1373 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1374 self.assertEquals(receivedResponse, expectedResponse)
1375
1376 def testAdvancedNoRDAllowed(self):
1377 """
1378 Advanced: No-RD query is allowed
1379 """
1380 name = 'no-rd.advanced.tests.powerdns.com.'
1381 query = dns.message.make_query(name, 'A', 'IN')
1382 query.flags &= ~dns.flags.RD
1383 response = dns.message.make_response(query)
1384
1385 for method in ("sendUDPQuery", "sendTCPQuery"):
1386 sender = getattr(self, method)
1387 (receivedQuery, receivedResponse) = sender(query, response)
1388 receivedQuery.id = query.id
1389 self.assertEquals(receivedQuery, query)
1390 self.assertEquals(receivedResponse, response)
1391
1392 class TestAdvancedGetLocalPort(DNSDistTest):
1393
1394 _config_template = """
1395 function answerBasedOnLocalPort(dq)
1396 local port = dq.localaddr:getPort()
1397 return DNSAction.Spoof, "port-was-"..port..".local-port.advanced.tests.powerdns.com."
1398 end
1399 addAction("local-port.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
1400 newServer{address="127.0.0.1:%s"}
1401 """
1402
1403 def testAdvancedGetLocalPort(self):
1404 """
1405 Advanced: Return CNAME containing the local port
1406 """
1407 name = 'local-port.advanced.tests.powerdns.com.'
1408 query = dns.message.make_query(name, 'A', 'IN')
1409 # dnsdist set RA = RD for spoofed responses
1410 query.flags &= ~dns.flags.RD
1411
1412 response = dns.message.make_response(query)
1413 rrset = dns.rrset.from_text(name,
1414 60,
1415 dns.rdataclass.IN,
1416 dns.rdatatype.CNAME,
1417 'port-was-{}.local-port.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
1418 response.answer.append(rrset)
1419
1420 for method in ("sendUDPQuery", "sendTCPQuery"):
1421 sender = getattr(self, method)
1422 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1423 self.assertEquals(receivedResponse, response)
1424
1425 class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest):
1426
1427 _config_template = """
1428 function answerBasedOnLocalPort(dq)
1429 local port = dq.localaddr:getPort()
1430 return DNSAction.Spoof, "port-was-"..port..".local-port-any.advanced.tests.powerdns.com."
1431 end
1432 addAction("local-port-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
1433 newServer{address="127.0.0.1:%s"}
1434 """
1435 _dnsDistListeningAddr = "0.0.0.0"
1436
1437 def testAdvancedGetLocalPortOnAnyBind(self):
1438 """
1439 Advanced: Return CNAME containing the local port for an ANY bind
1440 """
1441 name = 'local-port-any.advanced.tests.powerdns.com.'
1442 query = dns.message.make_query(name, 'A', 'IN')
1443 # dnsdist set RA = RD for spoofed responses
1444 query.flags &= ~dns.flags.RD
1445
1446 response = dns.message.make_response(query)
1447 rrset = dns.rrset.from_text(name,
1448 60,
1449 dns.rdataclass.IN,
1450 dns.rdatatype.CNAME,
1451 'port-was-{}.local-port-any.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
1452 response.answer.append(rrset)
1453
1454 for method in ("sendUDPQuery", "sendTCPQuery"):
1455 sender = getattr(self, method)
1456 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1457 self.assertEquals(receivedResponse, response)
1458
1459 class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
1460
1461 _config_template = """
1462 function answerBasedOnLocalAddress(dq)
1463 local dest = dq.localaddr:toString()
1464 local i, j = string.find(dest, "[0-9.]+")
1465 local addr = string.sub(dest, i, j)
1466 local dashAddr = string.gsub(addr, "[.]", "-")
1467 return DNSAction.Spoof, "address-was-"..dashAddr..".local-address-any.advanced.tests.powerdns.com."
1468 end
1469 addAction("local-address-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalAddress))
1470 newServer{address="127.0.0.1:%s"}
1471 """
1472 _dnsDistListeningAddr = "0.0.0.0"
1473
1474 def testAdvancedGetLocalAddressOnAnyBind(self):
1475 """
1476 Advanced: Return CNAME containing the local address for an ANY bind
1477 """
1478 name = 'local-address-any.advanced.tests.powerdns.com.'
1479 query = dns.message.make_query(name, 'A', 'IN')
1480 # dnsdist set RA = RD for spoofed responses
1481 query.flags &= ~dns.flags.RD
1482
1483 response = dns.message.make_response(query)
1484 rrset = dns.rrset.from_text(name,
1485 60,
1486 dns.rdataclass.IN,
1487 dns.rdatatype.CNAME,
1488 'address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.')
1489 response.answer.append(rrset)
1490
1491 for method in ("sendUDPQuery", "sendTCPQuery"):
1492 sender = getattr(self, method)
1493 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1494 self.assertEquals(receivedResponse, response)
1495
1496 class TestAdvancedLuaTempFailureTTL(DNSDistTest):
1497
1498 _config_template = """
1499 function testAction(dq)
1500 if dq.tempFailureTTL ~= nil then
1501 return DNSAction.Spoof, "initially.not.nil.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1502 end
1503 dq.tempFailureTTL = 30
1504 if dq.tempFailureTTL ~= 30 then
1505 return DNSAction.Spoof, "after.set.not.expected.value.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1506 end
1507 dq.tempFailureTTL = nil
1508 if dq.tempFailureTTL ~= nil then
1509 return DNSAction.Spoof, "after.unset.not.nil.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1510 end
1511 return DNSAction.None, ""
1512 end
1513 addAction(AllRule(), LuaAction(testAction))
1514 newServer{address="127.0.0.1:%s"}
1515 """
1516
1517 def testTempFailureTTLBinding(self):
1518 """
1519 Advanced: Exercise dq.tempFailureTTL Lua binding
1520 """
1521 name = 'tempfailurettlbinding.advanced.tests.powerdns.com.'
1522 query = dns.message.make_query(name, 'A', 'IN')
1523 response = dns.message.make_response(query)
1524 rrset = dns.rrset.from_text(name,
1525 3600,
1526 dns.rdataclass.IN,
1527 dns.rdatatype.AAAA,
1528 '::1')
1529 response.answer.append(rrset)
1530
1531 for method in ("sendUDPQuery", "sendTCPQuery"):
1532 sender = getattr(self, method)
1533 (receivedQuery, receivedResponse) = sender(query, response)
1534 self.assertTrue(receivedQuery)
1535 self.assertTrue(receivedResponse)
1536 receivedQuery.id = query.id
1537 self.assertEquals(query, receivedQuery)
1538 self.assertEquals(receivedResponse, response)
1539
1540 class TestAdvancedEDNSOptionRule(DNSDistTest):
1541
1542 _config_template = """
1543 newServer{address="127.0.0.1:%s"}
1544 addAction(EDNSOptionRule(EDNSOptionCode.ECS), DropAction())
1545 """
1546
1547 def testDropped(self):
1548 """
1549 Advanced: A question with ECS is dropped
1550 """
1551
1552 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1553
1554 ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
1555 query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
1556
1557 for method in ("sendUDPQuery", "sendTCPQuery"):
1558 sender = getattr(self, method)
1559 (_, receivedResponse) = sender(query, response=None)
1560 self.assertEquals(receivedResponse, None)
1561
1562 def testReplied(self):
1563 """
1564 Advanced: A question without ECS is answered
1565 """
1566
1567 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1568
1569 # both with EDNS
1570 query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[], payload=512)
1571 response = dns.message.make_response(query)
1572
1573 for method in ("sendUDPQuery", "sendTCPQuery"):
1574 sender = getattr(self, method)
1575 (receivedQuery, receivedResponse) = sender(query, response)
1576 self.assertTrue(receivedQuery)
1577 self.assertTrue(receivedResponse)
1578
1579 receivedQuery.id = query.id
1580 self.assertEquals(query, receivedQuery)
1581 self.assertEquals(receivedResponse, response)
1582
1583 # and with no EDNS at all
1584 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1585 response = dns.message.make_response(query)
1586
1587 for method in ("sendUDPQuery", "sendTCPQuery"):
1588 sender = getattr(self, method)
1589 (receivedQuery, receivedResponse) = sender(query, response)
1590 self.assertTrue(receivedQuery)
1591 self.assertTrue(receivedResponse)
1592
1593 receivedQuery.id = query.id
1594 self.assertEquals(query, receivedQuery)
1595 self.assertEquals(receivedResponse, response)
1596
1597 class TestAdvancedAllowHeaderOnly(DNSDistTest):
1598
1599 _config_template = """
1600 newServer{address="127.0.0.1:%s"}
1601 setAllowEmptyResponse(true)
1602 """
1603
1604 def testHeaderOnlyRefused(self):
1605 """
1606 Advanced: Header-only refused response
1607 """
1608 name = 'header-only-refused-response.advanced.tests.powerdns.com.'
1609 query = dns.message.make_query(name, 'A', 'IN')
1610 response = dns.message.make_response(query)
1611 response.set_rcode(dns.rcode.REFUSED)
1612 response.question = []
1613
1614 for method in ("sendUDPQuery", "sendTCPQuery"):
1615 sender = getattr(self, method)
1616 (receivedQuery, receivedResponse) = sender(query, response)
1617 self.assertTrue(receivedQuery)
1618 receivedQuery.id = query.id
1619 self.assertEquals(query, receivedQuery)
1620 self.assertEquals(receivedResponse, response)
1621
1622 def testHeaderOnlyNoErrorResponse(self):
1623 """
1624 Advanced: Header-only NoError response should be allowed
1625 """
1626 name = 'header-only-noerror-response.advanced.tests.powerdns.com.'
1627 query = dns.message.make_query(name, 'A', 'IN')
1628 response = dns.message.make_response(query)
1629 response.question = []
1630
1631 for method in ("sendUDPQuery", "sendTCPQuery"):
1632 sender = getattr(self, method)
1633 (receivedQuery, receivedResponse) = sender(query, response)
1634 self.assertTrue(receivedQuery)
1635 receivedQuery.id = query.id
1636 self.assertEquals(query, receivedQuery)
1637 self.assertEquals(receivedResponse, response)
1638
1639 def testHeaderOnlyNXDResponse(self):
1640 """
1641 Advanced: Header-only NXD response should be allowed
1642 """
1643 name = 'header-only-nxd-response.advanced.tests.powerdns.com.'
1644 query = dns.message.make_query(name, 'A', 'IN')
1645 response = dns.message.make_response(query)
1646 response.set_rcode(dns.rcode.NXDOMAIN)
1647 response.question = []
1648
1649 for method in ("sendUDPQuery", "sendTCPQuery"):
1650 sender = getattr(self, method)
1651 (receivedQuery, receivedResponse) = sender(query, response)
1652 self.assertTrue(receivedQuery)
1653 receivedQuery.id = query.id
1654 self.assertEquals(query, receivedQuery)
1655 self.assertEquals(receivedResponse, response)
1656
1657 class TestAdvancedEDNSVersionRule(DNSDistTest):
1658
1659 _config_template = """
1660 newServer{address="127.0.0.1:%s"}
1661 addAction(EDNSVersionRule(0), ERCodeAction(DNSRCode.BADVERS))
1662 """
1663
1664 def testDropped(self):
1665 """
1666 Advanced: A question with ECS version larger than 0 is dropped
1667 """
1668
1669 name = 'ednsversionrule.advanced.tests.powerdns.com.'
1670
1671 query = dns.message.make_query(name, 'A', 'IN', use_edns=1)
1672 expectedResponse = dns.message.make_response(query)
1673 expectedResponse.set_rcode(dns.rcode.BADVERS)
1674
1675 for method in ("sendUDPQuery", "sendTCPQuery"):
1676 sender = getattr(self, method)
1677 (_, receivedResponse) = sender(query, response=None)
1678 self.assertEquals(receivedResponse, expectedResponse)
1679
1680 def testNoEDNS0Pass(self):
1681 """
1682 Advanced: A question with ECS version 0 goes through
1683 """
1684
1685 name = 'ednsversionrule.advanced.tests.powerdns.com.'
1686
1687 query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
1688 response = dns.message.make_response(query)
1689
1690 for method in ("sendUDPQuery", "sendTCPQuery"):
1691 sender = getattr(self, method)
1692 (receivedQuery, receivedResponse) = sender(query, response)
1693 receivedQuery.id = query.id
1694 self.assertEquals(query, receivedQuery)
1695 self.assertEquals(receivedResponse, response)
1696
1697 def testReplied(self):
1698 """
1699 Advanced: A question without ECS goes through
1700 """
1701
1702 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1703
1704 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1705 response = dns.message.make_response(query)
1706
1707 for method in ("sendUDPQuery", "sendTCPQuery"):
1708 sender = getattr(self, method)
1709 (receivedQuery, receivedResponse) = sender(query, response)
1710 receivedQuery.id = query.id
1711 self.assertEquals(query, receivedQuery)
1712 self.assertEquals(receivedResponse, response)
1713
1714 class TestSetRules(DNSDistTest):
1715
1716 _consoleKey = DNSDistTest.generateConsoleKey()
1717 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
1718 _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
1719 _config_template = """
1720 setKey("%s")
1721 controlSocket("127.0.0.1:%s")
1722 newServer{address="127.0.0.1:%s"}
1723 addAction(AllRule(), SpoofAction("192.0.2.1"))
1724 """
1725
1726 def testClearThenSetRules(self):
1727 """
1728 Advanced: Clear rules, set rules
1729
1730 """
1731 name = 'clearthensetrules.advanced.tests.powerdns.com.'
1732 query = dns.message.make_query(name, 'A', 'IN')
1733 # dnsdist set RA = RD for spoofed responses
1734 query.flags &= ~dns.flags.RD
1735 expectedResponse = dns.message.make_response(query)
1736 rrset = dns.rrset.from_text(name,
1737 60,
1738 dns.rdataclass.IN,
1739 dns.rdatatype.A,
1740 '192.0.2.1')
1741 expectedResponse.answer.append(rrset)
1742
1743 for method in ("sendUDPQuery", "sendTCPQuery"):
1744 sender = getattr(self, method)
1745
1746 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1747 self.assertTrue(receivedResponse)
1748 self.assertEquals(expectedResponse, receivedResponse)
1749
1750 # clear all the rules, we should not be spoofing and get a SERVFAIL from the responder instead
1751 self.sendConsoleCommand("clearRules()")
1752
1753 expectedResponse = dns.message.make_response(query)
1754 expectedResponse.set_rcode(dns.rcode.SERVFAIL)
1755
1756 for method in ("sendUDPQuery", "sendTCPQuery"):
1757 sender = getattr(self, method)
1758
1759 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1760 self.assertTrue(receivedResponse)
1761 self.assertEquals(expectedResponse, receivedResponse)
1762
1763 # insert a new spoofing rule
1764 self.sendConsoleCommand("setRules({ newRuleAction(AllRule(), SpoofAction(\"192.0.2.2\")) })")
1765
1766 expectedResponse = dns.message.make_response(query)
1767 rrset = dns.rrset.from_text(name,
1768 60,
1769 dns.rdataclass.IN,
1770 dns.rdatatype.A,
1771 '192.0.2.2')
1772 expectedResponse.answer.append(rrset)
1773
1774 for method in ("sendUDPQuery", "sendTCPQuery"):
1775 sender = getattr(self, method)
1776
1777 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1778 self.assertTrue(receivedResponse)
1779 self.assertEquals(expectedResponse, receivedResponse)
1780
1781 class TestAdvancedContinueAction(DNSDistTest):
1782
1783 _config_template = """
1784 newServer{address="127.0.0.1:%s", pool="mypool"}
1785 addAction("nocontinue.continue-action.advanced.tests.powerdns.com.", PoolAction("mypool"))
1786 addAction("continue.continue-action.advanced.tests.powerdns.com.", ContinueAction(PoolAction("mypool")))
1787 addAction(AllRule(), DisableValidationAction())
1788 """
1789
1790 def testNoContinue(self):
1791 """
1792 Advanced: Query routed to pool, PoolAction should be terminal
1793 """
1794
1795 name = 'nocontinue.continue-action.advanced.tests.powerdns.com.'
1796
1797 query = dns.message.make_query(name, 'A', 'IN')
1798 expectedQuery = dns.message.make_query(name, 'A', 'IN')
1799
1800 response = dns.message.make_response(query)
1801 expectedResponse = dns.message.make_response(query)
1802
1803 for method in ("sendUDPQuery", "sendTCPQuery"):
1804 sender = getattr(self, method)
1805 (receivedQuery, receivedResponse) = sender(query, response)
1806 self.assertEquals(receivedQuery, expectedQuery)
1807 self.assertEquals(receivedResponse, expectedResponse)
1808
1809 def testNoContinue(self):
1810 """
1811 Advanced: Query routed to pool, ContinueAction() should not stop the processing
1812 """
1813
1814 name = 'continue.continue-action.advanced.tests.powerdns.com.'
1815
1816 query = dns.message.make_query(name, 'A', 'IN')
1817 expectedQuery = dns.message.make_query(name, 'A', 'IN')
1818 expectedQuery.flags |= dns.flags.CD
1819
1820 response = dns.message.make_response(query)
1821 expectedResponse = dns.message.make_response(query)
1822
1823 for method in ("sendUDPQuery", "sendTCPQuery"):
1824 sender = getattr(self, method)
1825 (receivedQuery, receivedResponse) = sender(query, response)
1826 expectedQuery.id = receivedQuery.id
1827 self.assertEquals(receivedQuery, expectedQuery)
1828 print(receivedResponse)
1829 print(expectedResponse)
1830 self.assertEquals(receivedResponse, expectedResponse)