]> git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Advanced.py
Merge pull request #10501 from rgacogne/ddist-per-thread-lua-ffi
[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.assertEqual(query, receivedQuery)
44 self.assertEqual(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 self.assertEqual(receivedResponse, None)
59
60 class TestAdvancedFixupCase(DNSDistTest):
61
62 _config_template = """
63 truncateTC(true)
64 fixupCase(true)
65 newServer{address="127.0.0.1:%s"}
66 """
67
68 def testAdvancedFixupCase(self):
69 """
70 Advanced: Fixup Case
71
72 Send a query with lower and upper chars,
73 make the backend return a lowercase version,
74 check that dnsdist fixes the response.
75 """
76 name = 'fiXuPCasE.advanced.tests.powerdns.com.'
77 query = dns.message.make_query(name, 'A', 'IN')
78 lowercasequery = dns.message.make_query(name.lower(), 'A', 'IN')
79 response = dns.message.make_response(lowercasequery)
80 expectedResponse = dns.message.make_response(query)
81 rrset = dns.rrset.from_text(name,
82 3600,
83 dns.rdataclass.IN,
84 dns.rdatatype.A,
85 '127.0.0.1')
86 response.answer.append(rrset)
87 expectedResponse.answer.append(rrset)
88
89 for method in ("sendUDPQuery", "sendTCPQuery"):
90 sender = getattr(self, method)
91 (receivedQuery, receivedResponse) = sender(query, response)
92 self.assertTrue(receivedQuery)
93 self.assertTrue(receivedResponse)
94 receivedQuery.id = query.id
95 self.assertEqual(query, receivedQuery)
96 self.assertEqual(expectedResponse, receivedResponse)
97
98 class TestAdvancedRemoveRD(DNSDistTest):
99
100 _config_template = """
101 addAction("norecurse.advanced.tests.powerdns.com.", SetNoRecurseAction())
102 newServer{address="127.0.0.1:%s"}
103 """
104
105 def testAdvancedNoRD(self):
106 """
107 Advanced: No RD
108
109 Send a query with RD,
110 check that dnsdist clears the RD flag.
111 """
112 name = 'norecurse.advanced.tests.powerdns.com.'
113 query = dns.message.make_query(name, 'A', 'IN')
114 expectedQuery = dns.message.make_query(name, 'A', 'IN')
115 expectedQuery.flags &= ~dns.flags.RD
116
117 response = dns.message.make_response(query)
118 rrset = dns.rrset.from_text(name,
119 3600,
120 dns.rdataclass.IN,
121 dns.rdatatype.A,
122 '127.0.0.1')
123 response.answer.append(rrset)
124
125 for method in ("sendUDPQuery", "sendTCPQuery"):
126 sender = getattr(self, method)
127 (receivedQuery, receivedResponse) = sender(query, response)
128 self.assertTrue(receivedQuery)
129 self.assertTrue(receivedResponse)
130 receivedQuery.id = expectedQuery.id
131 self.assertEqual(expectedQuery, receivedQuery)
132 self.assertEqual(response, receivedResponse)
133
134 def testAdvancedKeepRD(self):
135 """
136 Advanced: No RD canary
137
138 Send a query with RD for a canary domain,
139 check that dnsdist does not clear the RD flag.
140 """
141 name = 'keeprecurse.advanced.tests.powerdns.com.'
142 query = dns.message.make_query(name, 'A', 'IN')
143
144 response = dns.message.make_response(query)
145 rrset = dns.rrset.from_text(name,
146 3600,
147 dns.rdataclass.IN,
148 dns.rdatatype.A,
149 '127.0.0.1')
150 response.answer.append(rrset)
151
152 for method in ("sendUDPQuery", "sendTCPQuery"):
153 sender = getattr(self, method)
154 (receivedQuery, receivedResponse) = sender(query, response)
155 self.assertTrue(receivedQuery)
156 self.assertTrue(receivedResponse)
157 receivedQuery.id = query.id
158 self.assertEqual(query, receivedQuery)
159 self.assertEqual(response, receivedResponse)
160
161 class TestAdvancedAddCD(DNSDistTest):
162
163 _config_template = """
164 addAction("setcd.advanced.tests.powerdns.com.", SetDisableValidationAction())
165 addAction(makeRule("setcdviaaction.advanced.tests.powerdns.com."), SetDisableValidationAction())
166 newServer{address="127.0.0.1:%s"}
167 """
168
169 def testAdvancedSetCD(self):
170 """
171 Advanced: Set CD
172
173 Send a query with CD cleared,
174 check that dnsdist set the CD flag.
175 """
176 name = 'setcd.advanced.tests.powerdns.com.'
177 query = dns.message.make_query(name, 'A', 'IN')
178 expectedQuery = dns.message.make_query(name, 'A', 'IN')
179 expectedQuery.flags |= dns.flags.CD
180
181 response = dns.message.make_response(query)
182 rrset = dns.rrset.from_text(name,
183 3600,
184 dns.rdataclass.IN,
185 dns.rdatatype.A,
186 '127.0.0.1')
187 response.answer.append(rrset)
188
189 for method in ("sendUDPQuery", "sendTCPQuery"):
190 sender = getattr(self, method)
191 (receivedQuery, receivedResponse) = sender(query, response)
192 self.assertTrue(receivedQuery)
193 self.assertTrue(receivedResponse)
194 receivedQuery.id = expectedQuery.id
195 self.assertEqual(expectedQuery, receivedQuery)
196 self.assertEqual(response, receivedResponse)
197
198 def testAdvancedSetCDViaAction(self):
199 """
200 Advanced: Set CD via Action
201
202 Send a query with CD cleared,
203 check that dnsdist set the CD flag.
204 """
205 name = 'setcdviaaction.advanced.tests.powerdns.com.'
206 query = dns.message.make_query(name, 'A', 'IN')
207 expectedQuery = dns.message.make_query(name, 'A', 'IN')
208 expectedQuery.flags |= dns.flags.CD
209
210 response = dns.message.make_response(query)
211 rrset = dns.rrset.from_text(name,
212 3600,
213 dns.rdataclass.IN,
214 dns.rdatatype.A,
215 '127.0.0.1')
216 response.answer.append(rrset)
217
218 for method in ("sendUDPQuery", "sendTCPQuery"):
219 sender = getattr(self, method)
220 (receivedQuery, receivedResponse) = sender(query, response)
221 self.assertTrue(receivedQuery)
222 self.assertTrue(receivedResponse)
223 receivedQuery.id = expectedQuery.id
224 self.assertEqual(expectedQuery, receivedQuery)
225 self.assertEqual(response, receivedResponse)
226
227 def testAdvancedKeepNoCD(self):
228 """
229 Advanced: Preserve CD canary
230
231 Send a query without CD for a canary domain,
232 check that dnsdist does not set the CD flag.
233 """
234 name = 'keepnocd.advanced.tests.powerdns.com.'
235 query = dns.message.make_query(name, 'A', 'IN')
236
237 response = dns.message.make_response(query)
238 rrset = dns.rrset.from_text(name,
239 3600,
240 dns.rdataclass.IN,
241 dns.rdatatype.A,
242 '127.0.0.1')
243 response.answer.append(rrset)
244
245 for method in ("sendUDPQuery", "sendTCPQuery"):
246 sender = getattr(self, method)
247 (receivedQuery, receivedResponse) = sender(query, response)
248 self.assertTrue(receivedQuery)
249 self.assertTrue(receivedResponse)
250 receivedQuery.id = query.id
251 self.assertEqual(query, receivedQuery)
252 self.assertEqual(response, receivedResponse)
253
254 class TestAdvancedClearRD(DNSDistTest):
255
256 _config_template = """
257 addAction("clearrd.advanced.tests.powerdns.com.", SetNoRecurseAction())
258 addAction(makeRule("clearrdviaaction.advanced.tests.powerdns.com."), SetNoRecurseAction())
259 newServer{address="127.0.0.1:%s"}
260 """
261
262 def testAdvancedClearRD(self):
263 """
264 Advanced: Clear RD
265
266 Send a query with RD set,
267 check that dnsdist clears the RD flag.
268 """
269 name = 'clearrd.advanced.tests.powerdns.com.'
270 query = dns.message.make_query(name, 'A', 'IN')
271 expectedQuery = dns.message.make_query(name, 'A', 'IN')
272 expectedQuery.flags &= ~dns.flags.RD
273
274 response = dns.message.make_response(query)
275 rrset = dns.rrset.from_text(name,
276 3600,
277 dns.rdataclass.IN,
278 dns.rdatatype.A,
279 '127.0.0.1')
280 response.answer.append(rrset)
281
282 for method in ("sendUDPQuery", "sendTCPQuery"):
283 sender = getattr(self, method)
284 (receivedQuery, receivedResponse) = sender(query, response)
285 self.assertTrue(receivedQuery)
286 self.assertTrue(receivedResponse)
287 receivedQuery.id = expectedQuery.id
288 self.assertEqual(expectedQuery, receivedQuery)
289 self.assertEqual(response, receivedResponse)
290
291 def testAdvancedClearRDViaAction(self):
292 """
293 Advanced: Clear RD via Action
294
295 Send a query with RD set,
296 check that dnsdist clears the RD flag.
297 """
298 name = 'clearrdviaaction.advanced.tests.powerdns.com.'
299 query = dns.message.make_query(name, 'A', 'IN')
300 expectedQuery = dns.message.make_query(name, 'A', 'IN')
301 expectedQuery.flags &= ~dns.flags.RD
302
303 response = dns.message.make_response(query)
304 rrset = dns.rrset.from_text(name,
305 3600,
306 dns.rdataclass.IN,
307 dns.rdatatype.A,
308 '127.0.0.1')
309 response.answer.append(rrset)
310
311 for method in ("sendUDPQuery", "sendTCPQuery"):
312 sender = getattr(self, method)
313 (receivedQuery, receivedResponse) = sender(query, response)
314 self.assertTrue(receivedQuery)
315 self.assertTrue(receivedResponse)
316 receivedQuery.id = expectedQuery.id
317 self.assertEqual(expectedQuery, receivedQuery)
318 self.assertEqual(response, receivedResponse)
319
320 def testAdvancedKeepRD(self):
321 """
322 Advanced: Preserve RD canary
323
324 Send a query with RD for a canary domain,
325 check that dnsdist does not clear the RD flag.
326 """
327 name = 'keeprd.advanced.tests.powerdns.com.'
328 query = dns.message.make_query(name, 'A', 'IN')
329
330 response = dns.message.make_response(query)
331 rrset = dns.rrset.from_text(name,
332 3600,
333 dns.rdataclass.IN,
334 dns.rdatatype.A,
335 '127.0.0.1')
336 response.answer.append(rrset)
337
338 for method in ("sendUDPQuery", "sendTCPQuery"):
339 sender = getattr(self, method)
340 (receivedQuery, receivedResponse) = sender(query, response)
341 self.assertTrue(receivedQuery)
342 self.assertTrue(receivedResponse)
343 receivedQuery.id = query.id
344 self.assertEqual(query, receivedQuery)
345 self.assertEqual(response, receivedResponse)
346
347
348 class TestAdvancedACL(DNSDistTest):
349
350 _config_template = """
351 newServer{address="127.0.0.1:%s"}
352 """
353 _acl = ['192.0.2.1/32']
354
355 def testACLBlocked(self):
356 """
357 Advanced: ACL blocked
358
359 Send an A query to "tests.powerdns.com.",
360 we expect no response since 127.0.0.1 is not on the
361 ACL.
362 """
363 name = 'tests.powerdns.com.'
364 query = dns.message.make_query(name, 'A', 'IN')
365
366 for method in ("sendUDPQuery", "sendTCPQuery"):
367 sender = getattr(self, method)
368 (_, receivedResponse) = sender(query, response=None, useQueue=False)
369 self.assertEqual(receivedResponse, None)
370
371 class TestAdvancedDelay(DNSDistTest):
372
373 _config_template = """
374 addAction(AllRule(), DelayAction(1000))
375 newServer{address="127.0.0.1:%s"}
376 """
377
378 def testDelayed(self):
379 """
380 Advanced: Delayed
381
382 Send an A query to "tests.powerdns.com.",
383 check that the response delay is longer than 1000 ms
384 over UDP, less than that over TCP.
385 """
386 name = 'tests.powerdns.com.'
387 query = dns.message.make_query(name, 'A', 'IN')
388 response = dns.message.make_response(query)
389 rrset = dns.rrset.from_text(name,
390 60,
391 dns.rdataclass.IN,
392 dns.rdatatype.A,
393 '192.0.2.1')
394 response.answer.append(rrset)
395
396 begin = datetime.now()
397 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
398 end = datetime.now()
399 receivedQuery.id = query.id
400 self.assertEqual(query, receivedQuery)
401 self.assertEqual(response, receivedResponse)
402 self.assertTrue((end - begin) > timedelta(0, 1))
403
404 begin = datetime.now()
405 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
406 end = datetime.now()
407 receivedQuery.id = query.id
408 self.assertEqual(query, receivedQuery)
409 self.assertEqual(response, receivedResponse)
410 self.assertTrue((end - begin) < timedelta(0, 1))
411
412
413 class TestAdvancedTruncateAnyAndTCP(DNSDistTest):
414
415 _config_template = """
416 truncateTC(false)
417 addAction(AndRule({QTypeRule("ANY"), TCPRule(true)}), TCAction())
418 newServer{address="127.0.0.1:%s"}
419 """
420 def testTruncateAnyOverTCP(self):
421 """
422 Advanced: Truncate ANY over TCP
423
424 Send an ANY query to "anytruncatetcp.advanced.tests.powerdns.com.",
425 should be truncated over TCP, not over UDP (yes, it makes no sense,
426 deal with it).
427 """
428 name = 'anytruncatetcp.advanced.tests.powerdns.com.'
429 query = dns.message.make_query(name, 'ANY', 'IN')
430 # dnsdist sets RA = RD for TC responses
431 query.flags &= ~dns.flags.RD
432
433 response = dns.message.make_response(query)
434 rrset = dns.rrset.from_text(name,
435 3600,
436 dns.rdataclass.IN,
437 dns.rdatatype.A,
438 '127.0.0.1')
439
440 response.answer.append(rrset)
441
442 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
443 self.assertTrue(receivedQuery)
444 self.assertTrue(receivedResponse)
445 receivedQuery.id = query.id
446 self.assertEqual(query, receivedQuery)
447 self.assertEqual(receivedResponse, response)
448
449 expectedResponse = dns.message.make_response(query)
450 expectedResponse.flags |= dns.flags.TC
451
452 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
453 self.assertEqual(receivedResponse, expectedResponse)
454
455 class TestAdvancedAndNot(DNSDistTest):
456
457 _config_template = """
458 addAction(AndRule({NotRule(QTypeRule("A")), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
459 newServer{address="127.0.0.1:%s"}
460 """
461 def testAOverUDPReturnsNotImplementedCanary(self):
462 """
463 Advanced: !A && UDP canary
464
465 dnsdist is configured to reply 'not implemented' for query
466 over UDP AND !qtype A.
467 We send an A query over UDP and TCP, and check that the
468 response is OK.
469 """
470 name = 'andnot.advanced.tests.powerdns.com.'
471 query = dns.message.make_query(name, 'A', 'IN')
472 response = dns.message.make_response(query)
473 rrset = dns.rrset.from_text(name,
474 3600,
475 dns.rdataclass.IN,
476 dns.rdatatype.A,
477 '127.0.0.1')
478 response.answer.append(rrset)
479
480 for method in ("sendUDPQuery", "sendTCPQuery"):
481 sender = getattr(self, method)
482 (receivedQuery, receivedResponse) = sender(query, response)
483 self.assertTrue(receivedQuery)
484 self.assertTrue(receivedResponse)
485 receivedQuery.id = query.id
486 self.assertEqual(query, receivedQuery)
487 self.assertEqual(receivedResponse, response)
488
489 def testAOverUDPReturnsNotImplemented(self):
490 """
491 Advanced: !A && UDP
492
493 dnsdist is configured to reply 'not implemented' for query
494 over UDP AND !qtype A.
495 We send a TXT query over UDP and TCP, and check that the
496 response is OK for TCP and 'not implemented' for UDP.
497 """
498 name = 'andnot.advanced.tests.powerdns.com.'
499 query = dns.message.make_query(name, 'TXT', 'IN')
500 # dnsdist sets RA = RD for TC responses
501 query.flags &= ~dns.flags.RD
502
503 expectedResponse = dns.message.make_response(query)
504 expectedResponse.set_rcode(dns.rcode.NOTIMP)
505
506 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
507 self.assertEqual(receivedResponse, expectedResponse)
508
509 response = dns.message.make_response(query)
510 rrset = dns.rrset.from_text(name,
511 3600,
512 dns.rdataclass.IN,
513 dns.rdatatype.TXT,
514 'nothing to see here')
515 response.answer.append(rrset)
516
517 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
518 self.assertTrue(receivedQuery)
519 self.assertTrue(receivedResponse)
520 receivedQuery.id = query.id
521 self.assertEqual(query, receivedQuery)
522 self.assertEqual(receivedResponse, response)
523
524 class TestAdvancedOr(DNSDistTest):
525
526 _config_template = """
527 addAction(OrRule({QTypeRule("A"), TCPRule(false)}), RCodeAction(DNSRCode.NOTIMP))
528 newServer{address="127.0.0.1:%s"}
529 """
530 def testAAAAOverUDPReturnsNotImplemented(self):
531 """
532 Advanced: A || UDP: AAAA
533
534 dnsdist is configured to reply 'not implemented' for query
535 over UDP OR qtype A.
536 We send an AAAA query over UDP and TCP, and check that the
537 response is 'not implemented' for UDP and OK for TCP.
538 """
539 name = 'aorudp.advanced.tests.powerdns.com.'
540 query = dns.message.make_query(name, 'AAAA', 'IN')
541 query.flags &= ~dns.flags.RD
542 response = dns.message.make_response(query)
543 rrset = dns.rrset.from_text(name,
544 3600,
545 dns.rdataclass.IN,
546 dns.rdatatype.AAAA,
547 '::1')
548 response.answer.append(rrset)
549
550 expectedResponse = dns.message.make_response(query)
551 expectedResponse.set_rcode(dns.rcode.NOTIMP)
552
553 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
554 self.assertEqual(receivedResponse, expectedResponse)
555
556 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
557 self.assertTrue(receivedQuery)
558 self.assertTrue(receivedResponse)
559 receivedQuery.id = query.id
560 self.assertEqual(query, receivedQuery)
561 self.assertEqual(receivedResponse, response)
562
563 def testAOverUDPReturnsNotImplemented(self):
564 """
565 Advanced: A || UDP: A
566
567 dnsdist is configured to reply 'not implemented' for query
568 over UDP OR qtype A.
569 We send an A query over UDP and TCP, and check that the
570 response is 'not implemented' for both.
571 """
572 name = 'aorudp.advanced.tests.powerdns.com.'
573 query = dns.message.make_query(name, 'A', 'IN')
574 query.flags &= ~dns.flags.RD
575
576 expectedResponse = dns.message.make_response(query)
577 expectedResponse.set_rcode(dns.rcode.NOTIMP)
578
579 for method in ("sendUDPQuery", "sendTCPQuery"):
580 sender = getattr(self, method)
581 (_, receivedResponse) = sender(query, response=None, useQueue=False)
582 self.assertEqual(receivedResponse, expectedResponse)
583
584
585 class TestAdvancedLogAction(DNSDistTest):
586
587 _config_template = """
588 newServer{address="127.0.0.1:%s"}
589 addAction(AllRule(), LogAction("dnsdist.log", false))
590 """
591 def testAdvancedLogAction(self):
592 """
593 Advanced: Log all queries
594
595 """
596 count = 50
597 name = 'logaction.advanced.tests.powerdns.com.'
598 query = dns.message.make_query(name, 'A', 'IN')
599 response = dns.message.make_response(query)
600 rrset = dns.rrset.from_text(name,
601 3600,
602 dns.rdataclass.IN,
603 dns.rdatatype.A,
604 '127.0.0.1')
605 response.answer.append(rrset)
606
607 for _ in range(count):
608 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
609 self.assertTrue(receivedQuery)
610 self.assertTrue(receivedResponse)
611 receivedQuery.id = query.id
612 self.assertEqual(query, receivedQuery)
613 self.assertEqual(response, receivedResponse)
614
615 self.assertTrue(os.path.isfile('dnsdist.log'))
616 self.assertTrue(os.stat('dnsdist.log').st_size > 0)
617
618 class TestAdvancedDNSSEC(DNSDistTest):
619
620 _config_template = """
621 newServer{address="127.0.0.1:%s"}
622 addAction(DNSSECRule(), DropAction())
623 """
624 def testAdvancedDNSSECDrop(self):
625 """
626 Advanced: DNSSEC Rule
627
628 """
629 name = 'dnssec.advanced.tests.powerdns.com.'
630 query = dns.message.make_query(name, 'A', 'IN')
631 doquery = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
632 response = dns.message.make_response(query)
633 rrset = dns.rrset.from_text(name,
634 3600,
635 dns.rdataclass.IN,
636 dns.rdatatype.A,
637 '127.0.0.1')
638 response.answer.append(rrset)
639
640 for method in ("sendUDPQuery", "sendTCPQuery"):
641 sender = getattr(self, method)
642 (receivedQuery, receivedResponse) = sender(query, response)
643 self.assertTrue(receivedQuery)
644 self.assertTrue(receivedResponse)
645 receivedQuery.id = query.id
646 self.assertEqual(query, receivedQuery)
647 self.assertEqual(response, receivedResponse)
648
649 for method in ("sendUDPQuery", "sendTCPQuery"):
650 sender = getattr(self, method)
651 (_, receivedResponse) = sender(doquery, response=None, useQueue=False)
652 self.assertEqual(receivedResponse, None)
653
654 class TestAdvancedQClass(DNSDistTest):
655
656 _config_template = """
657 newServer{address="127.0.0.1:%s"}
658 addAction(QClassRule(DNSClass.CHAOS), DropAction())
659 """
660 def testAdvancedQClassChaosDrop(self):
661 """
662 Advanced: Drop QClass CHAOS
663
664 """
665 name = 'qclasschaos.advanced.tests.powerdns.com.'
666 query = dns.message.make_query(name, 'TXT', 'CHAOS')
667
668 for method in ("sendUDPQuery", "sendTCPQuery"):
669 sender = getattr(self, method)
670 (_, receivedResponse) = sender(query, response=None, useQueue=False)
671 self.assertEqual(receivedResponse, None)
672
673 def testAdvancedQClassINAllow(self):
674 """
675 Advanced: Allow QClass IN
676
677 """
678 name = 'qclassin.advanced.tests.powerdns.com.'
679 query = dns.message.make_query(name, 'A', 'IN')
680 response = dns.message.make_response(query)
681 rrset = dns.rrset.from_text(name,
682 3600,
683 dns.rdataclass.IN,
684 dns.rdatatype.A,
685 '127.0.0.1')
686 response.answer.append(rrset)
687
688 for method in ("sendUDPQuery", "sendTCPQuery"):
689 sender = getattr(self, method)
690 (receivedQuery, receivedResponse) = sender(query, response)
691 self.assertTrue(receivedQuery)
692 self.assertTrue(receivedResponse)
693 receivedQuery.id = query.id
694 self.assertEqual(query, receivedQuery)
695 self.assertEqual(response, receivedResponse)
696
697 class TestAdvancedOpcode(DNSDistTest):
698
699 _config_template = """
700 newServer{address="127.0.0.1:%s"}
701 addAction(OpcodeRule(DNSOpcode.Notify), DropAction())
702 """
703 def testAdvancedOpcodeNotifyDrop(self):
704 """
705 Advanced: Drop Opcode NOTIFY
706
707 """
708 name = 'opcodenotify.advanced.tests.powerdns.com.'
709 query = dns.message.make_query(name, 'A', 'IN')
710 query.set_opcode(dns.opcode.NOTIFY)
711
712 for method in ("sendUDPQuery", "sendTCPQuery"):
713 sender = getattr(self, method)
714 (_, receivedResponse) = sender(query, response=None, useQueue=False)
715 self.assertEqual(receivedResponse, None)
716
717 def testAdvancedOpcodeUpdateINAllow(self):
718 """
719 Advanced: Allow Opcode UPDATE
720
721 """
722 name = 'opcodeupdate.advanced.tests.powerdns.com.'
723 query = dns.message.make_query(name, 'SOA', 'IN')
724 query.set_opcode(dns.opcode.UPDATE)
725 response = dns.message.make_response(query)
726 rrset = dns.rrset.from_text(name,
727 3600,
728 dns.rdataclass.IN,
729 dns.rdatatype.A,
730 '127.0.0.1')
731 response.answer.append(rrset)
732
733 for method in ("sendUDPQuery", "sendTCPQuery"):
734 sender = getattr(self, method)
735 (receivedQuery, receivedResponse) = sender(query, response)
736 self.assertTrue(receivedQuery)
737 self.assertTrue(receivedResponse)
738 receivedQuery.id = query.id
739 self.assertEqual(query, receivedQuery)
740 self.assertEqual(response, receivedResponse)
741
742 class TestAdvancedNonTerminalRule(DNSDistTest):
743
744 _config_template = """
745 newServer{address="127.0.0.1:%s", pool="real"}
746 addAction(AllRule(), SetDisableValidationAction())
747 addAction(AllRule(), PoolAction("real"))
748 addAction(AllRule(), DropAction())
749 """
750 def testAdvancedNonTerminalRules(self):
751 """
752 Advanced: Non terminal rules
753
754 We check that SetDisableValidationAction() is applied
755 but does not stop the processing, then that
756 PoolAction() is applied _and_ stop the processing.
757 """
758 name = 'nonterminal.advanced.tests.powerdns.com.'
759 query = dns.message.make_query(name, 'A', 'IN')
760 expectedQuery = dns.message.make_query(name, 'A', 'IN')
761 expectedQuery.flags |= dns.flags.CD
762 response = dns.message.make_response(query)
763 rrset = dns.rrset.from_text(name,
764 3600,
765 dns.rdataclass.IN,
766 dns.rdatatype.A,
767 '192.0.2.1')
768 response.answer.append(rrset)
769
770 for method in ("sendUDPQuery", "sendTCPQuery"):
771 sender = getattr(self, method)
772 (receivedQuery, receivedResponse) = sender(query, response)
773 self.assertTrue(receivedQuery)
774 self.assertTrue(receivedResponse)
775 receivedQuery.id = expectedQuery.id
776 self.assertEqual(expectedQuery, receivedQuery)
777 self.assertEqual(response, receivedResponse)
778
779 class TestAdvancedStringOnlyServer(DNSDistTest):
780
781 _config_template = """
782 newServer("127.0.0.1:%s")
783 """
784
785 def testAdvancedStringOnlyServer(self):
786 """
787 Advanced: "string-only" server is placed in the default pool
788 """
789 name = 'string-only-server.advanced.tests.powerdns.com.'
790 query = dns.message.make_query(name, 'A', 'IN')
791 response = dns.message.make_response(query)
792 rrset = dns.rrset.from_text(name,
793 3600,
794 dns.rdataclass.IN,
795 dns.rdatatype.A,
796 '192.0.2.1')
797 response.answer.append(rrset)
798
799 for method in ("sendUDPQuery", "sendTCPQuery"):
800 sender = getattr(self, method)
801 (receivedQuery, receivedResponse) = sender(query, response)
802 self.assertTrue(receivedQuery)
803 self.assertTrue(receivedResponse)
804 receivedQuery.id = query.id
805 self.assertEqual(query, receivedQuery)
806 self.assertEqual(response, receivedResponse)
807
808 class TestAdvancedRestoreFlagsOnSelfResponse(DNSDistTest):
809
810 _config_template = """
811 addAction(AllRule(), SetDisableValidationAction())
812 addAction(AllRule(), SpoofAction("192.0.2.1"))
813 newServer{address="127.0.0.1:%s"}
814 """
815
816 def testAdvancedRestoreFlagsOnSpoofResponse(self):
817 """
818 Advanced: Restore flags on spoofed response
819
820 Send a query with CD flag cleared, dnsdist is
821 instructed to set it, then to spoof the response,
822 check that response has the flag cleared.
823 """
824 name = 'spoofed.restoreflags.advanced.tests.powerdns.com.'
825 query = dns.message.make_query(name, 'A', 'IN')
826 # dnsdist set RA = RD for spoofed responses
827 query.flags &= ~dns.flags.RD
828
829 response = dns.message.make_response(query)
830 rrset = dns.rrset.from_text(name,
831 60,
832 dns.rdataclass.IN,
833 dns.rdatatype.A,
834 '192.0.2.1')
835 response.answer.append(rrset)
836
837 for method in ("sendUDPQuery", "sendTCPQuery"):
838 sender = getattr(self, method)
839 (_, receivedResponse) = sender(query, response=None, useQueue=False)
840 self.assertTrue(receivedResponse)
841 self.assertEqual(response, receivedResponse)
842
843 class TestAdvancedQPS(DNSDistTest):
844
845 _config_template = """
846 addAction("qps.advanced.tests.powerdns.com", QPSAction(10))
847 newServer{address="127.0.0.1:%s"}
848 """
849
850 def testAdvancedQPSLimit(self):
851 """
852 Advanced: QPS Limit
853
854 Send queries to "qps.advanced.tests.powerdns.com."
855 check that dnsdist drops queries when the max QPS has been reached.
856 """
857 maxQPS = 10
858 name = 'qps.advanced.tests.powerdns.com.'
859 query = dns.message.make_query(name, 'A', 'IN')
860 response = dns.message.make_response(query)
861 rrset = dns.rrset.from_text(name,
862 60,
863 dns.rdataclass.IN,
864 dns.rdatatype.A,
865 '192.0.2.1')
866 response.answer.append(rrset)
867
868 for _ in range(maxQPS):
869 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
870 receivedQuery.id = query.id
871 self.assertEqual(query, receivedQuery)
872 self.assertEqual(response, receivedResponse)
873
874 # we should now be dropped
875 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
876 self.assertEqual(receivedResponse, None)
877
878 time.sleep(1)
879
880 # again, over TCP this time
881 for _ in range(maxQPS):
882 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
883 receivedQuery.id = query.id
884 self.assertEqual(query, receivedQuery)
885 self.assertEqual(response, receivedResponse)
886
887
888 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
889 self.assertEqual(receivedResponse, None)
890
891 class TestAdvancedQPSNone(DNSDistTest):
892
893 _config_template = """
894 addAction("qpsnone.advanced.tests.powerdns.com", QPSAction(100))
895 addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
896 newServer{address="127.0.0.1:%s"}
897 """
898
899 def testAdvancedQPSNone(self):
900 """
901 Advanced: Not matching QPS returns None, not Allow
902
903 Send queries to "qps.advanced.tests.powerdns.com."
904 check that the rule returns None when the QPS has not been
905 reached, not Allow.
906 """
907 name = 'qpsnone.advanced.tests.powerdns.com.'
908 query = dns.message.make_query(name, 'A', 'IN')
909 query.flags &= ~dns.flags.RD
910 expectedResponse = dns.message.make_response(query)
911 expectedResponse.set_rcode(dns.rcode.REFUSED)
912
913 for method in ("sendUDPQuery", "sendTCPQuery"):
914 sender = getattr(self, method)
915 (_, receivedResponse) = sender(query, response=None, useQueue=False)
916 self.assertEqual(receivedResponse, expectedResponse)
917
918 class TestAdvancedNMGRule(DNSDistTest):
919
920 _config_template = """
921 allowed = newNMG()
922 allowed:addMask("192.0.2.1/32")
923 addAction(NotRule(NetmaskGroupRule(allowed)), RCodeAction(DNSRCode.REFUSED))
924 newServer{address="127.0.0.1:%s"}
925 """
926
927 def testAdvancedNMGRule(self):
928 """
929 Advanced: NMGRule should refuse our queries
930
931 Send queries to "nmgrule.advanced.tests.powerdns.com.",
932 check that we are getting a REFUSED response.
933 """
934 name = 'nmgrule.advanced.tests.powerdns.com.'
935 query = dns.message.make_query(name, 'A', 'IN')
936 query.flags &= ~dns.flags.RD
937 expectedResponse = dns.message.make_response(query)
938 expectedResponse.set_rcode(dns.rcode.REFUSED)
939
940 for method in ("sendUDPQuery", "sendTCPQuery"):
941 sender = getattr(self, method)
942 (_, receivedResponse) = sender(query, response=None, useQueue=False)
943 self.assertEqual(receivedResponse, expectedResponse)
944
945 class TestDSTPortRule(DNSDistTest):
946
947 _config_params = ['_dnsDistPort', '_testServerPort']
948 _config_template = """
949 addAction(DSTPortRule(%d), RCodeAction(DNSRCode.REFUSED))
950 newServer{address="127.0.0.1:%s"}
951 """
952
953 def testDSTPortRule(self):
954 """
955 Advanced: DSTPortRule should capture our queries
956
957 Send queries to "dstportrule.advanced.tests.powerdns.com.",
958 check that we are getting a REFUSED response.
959 """
960
961 name = 'dstportrule.advanced.tests.powerdns.com.'
962 query = dns.message.make_query(name, 'A', 'IN')
963 query.flags &= ~dns.flags.RD
964 expectedResponse = dns.message.make_response(query)
965 expectedResponse.set_rcode(dns.rcode.REFUSED)
966
967 for method in ("sendUDPQuery", "sendTCPQuery"):
968 sender = getattr(self, method)
969 (_, receivedResponse) = sender(query, response=None, useQueue=False)
970 self.assertEqual(receivedResponse, expectedResponse)
971
972 class TestAdvancedLabelsCountRule(DNSDistTest):
973
974 _config_template = """
975 addAction(QNameLabelsCountRule(5,6), RCodeAction(DNSRCode.REFUSED))
976 newServer{address="127.0.0.1:%s"}
977 """
978
979 def testAdvancedLabelsCountRule(self):
980 """
981 Advanced: QNameLabelsCountRule(5,6)
982 """
983 # 6 labels, we should be fine
984 name = 'ok.labelscount.advanced.tests.powerdns.com.'
985 query = dns.message.make_query(name, 'A', 'IN')
986 response = dns.message.make_response(query)
987 rrset = dns.rrset.from_text(name,
988 3600,
989 dns.rdataclass.IN,
990 dns.rdatatype.A,
991 '192.0.2.1')
992 response.answer.append(rrset)
993
994 for method in ("sendUDPQuery", "sendTCPQuery"):
995 sender = getattr(self, method)
996 (receivedQuery, receivedResponse) = sender(query, response)
997 self.assertTrue(receivedQuery)
998 self.assertTrue(receivedResponse)
999 receivedQuery.id = query.id
1000 self.assertEqual(query, receivedQuery)
1001 self.assertEqual(response, receivedResponse)
1002
1003 # more than 6 labels, the query should be refused
1004 name = 'not.ok.labelscount.advanced.tests.powerdns.com.'
1005 query = dns.message.make_query(name, 'A', 'IN')
1006 query.flags &= ~dns.flags.RD
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.assertEqual(receivedResponse, expectedResponse)
1014
1015 # less than 5 labels, the query should be refused
1016 name = 'labelscountadvanced.tests.powerdns.com.'
1017 query = dns.message.make_query(name, 'A', 'IN')
1018 query.flags &= ~dns.flags.RD
1019 expectedResponse = dns.message.make_response(query)
1020 expectedResponse.set_rcode(dns.rcode.REFUSED)
1021
1022 for method in ("sendUDPQuery", "sendTCPQuery"):
1023 sender = getattr(self, method)
1024 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1025 self.assertEqual(receivedResponse, expectedResponse)
1026
1027 class TestAdvancedWireLengthRule(DNSDistTest):
1028
1029 _config_template = """
1030 addAction(QNameWireLengthRule(54,56), RCodeAction(DNSRCode.REFUSED))
1031 newServer{address="127.0.0.1:%s"}
1032 """
1033
1034 def testAdvancedWireLengthRule(self):
1035 """
1036 Advanced: QNameWireLengthRule(54,56)
1037 """
1038 name = 'longenough.qnamewirelength.advanced.tests.powerdns.com.'
1039 query = dns.message.make_query(name, 'A', 'IN')
1040 response = dns.message.make_response(query)
1041 rrset = dns.rrset.from_text(name,
1042 3600,
1043 dns.rdataclass.IN,
1044 dns.rdatatype.A,
1045 '192.0.2.1')
1046 response.answer.append(rrset)
1047
1048 for method in ("sendUDPQuery", "sendTCPQuery"):
1049 sender = getattr(self, method)
1050 (receivedQuery, receivedResponse) = sender(query, response)
1051 self.assertTrue(receivedQuery)
1052 self.assertTrue(receivedResponse)
1053 receivedQuery.id = query.id
1054 self.assertEqual(query, receivedQuery)
1055 self.assertEqual(response, receivedResponse)
1056
1057 # too short, the query should be refused
1058 name = 'short.qnamewirelength.advanced.tests.powerdns.com.'
1059 query = dns.message.make_query(name, 'A', 'IN')
1060 query.flags &= ~dns.flags.RD
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.assertEqual(receivedResponse, expectedResponse)
1068
1069 # too long, the query should be refused
1070 name = 'toolongtobevalid.qnamewirelength.advanced.tests.powerdns.com.'
1071 query = dns.message.make_query(name, 'A', 'IN')
1072 query.flags &= ~dns.flags.RD
1073 expectedResponse = dns.message.make_response(query)
1074 expectedResponse.set_rcode(dns.rcode.REFUSED)
1075
1076 for method in ("sendUDPQuery", "sendTCPQuery"):
1077 sender = getattr(self, method)
1078 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1079 self.assertEqual(receivedResponse, expectedResponse)
1080
1081 class TestAdvancedIncludeDir(DNSDistTest):
1082
1083 _config_template = """
1084 -- this directory contains a file allowing includedir.advanced.tests.powerdns.com.
1085 includeDirectory('test-include-dir')
1086 newServer{address="127.0.0.1:%s"}
1087 """
1088
1089 def testAdvancedIncludeDirAllowed(self):
1090 """
1091 Advanced: includeDirectory()
1092 """
1093 name = 'includedir.advanced.tests.powerdns.com.'
1094 query = dns.message.make_query(name, 'A', 'IN')
1095 response = dns.message.make_response(query)
1096 rrset = dns.rrset.from_text(name,
1097 3600,
1098 dns.rdataclass.IN,
1099 dns.rdatatype.A,
1100 '192.0.2.1')
1101 response.answer.append(rrset)
1102
1103 for method in ("sendUDPQuery", "sendTCPQuery"):
1104 sender = getattr(self, method)
1105 (receivedQuery, receivedResponse) = sender(query, response)
1106 self.assertTrue(receivedQuery)
1107 self.assertTrue(receivedResponse)
1108 receivedQuery.id = query.id
1109 self.assertEqual(query, receivedQuery)
1110 self.assertEqual(response, receivedResponse)
1111
1112 # this one should be refused
1113 name = 'notincludedir.advanced.tests.powerdns.com.'
1114 query = dns.message.make_query(name, 'A', 'IN')
1115 query.flags &= ~dns.flags.RD
1116 expectedResponse = dns.message.make_response(query)
1117 expectedResponse.set_rcode(dns.rcode.REFUSED)
1118
1119 for method in ("sendUDPQuery", "sendTCPQuery"):
1120 sender = getattr(self, method)
1121 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1122 self.assertEqual(receivedResponse, expectedResponse)
1123
1124 class TestAdvancedLuaDO(DNSDistTest):
1125
1126 _config_template = """
1127 function nxDOLua(dq)
1128 if dq:getDO() then
1129 return DNSAction.Nxdomain, ""
1130 end
1131 return DNSAction.None, ""
1132 end
1133 addAction(AllRule(), LuaAction(nxDOLua))
1134 newServer{address="127.0.0.1:%s"}
1135 """
1136
1137 def testNxDOViaLua(self):
1138 """
1139 Advanced: Nx DO queries via Lua
1140 """
1141 name = 'nxdo.advanced.tests.powerdns.com.'
1142 query = dns.message.make_query(name, 'A', 'IN')
1143 response = dns.message.make_response(query)
1144 rrset = dns.rrset.from_text(name,
1145 3600,
1146 dns.rdataclass.IN,
1147 dns.rdatatype.AAAA,
1148 '::1')
1149 response.answer.append(rrset)
1150 queryWithDO = dns.message.make_query(name, 'A', 'IN', want_dnssec=True)
1151 doResponse = dns.message.make_response(queryWithDO)
1152 doResponse.set_rcode(dns.rcode.NXDOMAIN)
1153
1154 # without DO
1155 for method in ("sendUDPQuery", "sendTCPQuery"):
1156 sender = getattr(self, method)
1157 (receivedQuery, receivedResponse) = sender(query, response)
1158 self.assertTrue(receivedQuery)
1159 self.assertTrue(receivedResponse)
1160 receivedQuery.id = query.id
1161 self.assertEqual(query, receivedQuery)
1162 self.assertEqual(receivedResponse, response)
1163
1164 # with DO
1165 for method in ("sendUDPQuery", "sendTCPQuery"):
1166 sender = getattr(self, method)
1167 (_, receivedResponse) = sender(queryWithDO, response=None, useQueue=False)
1168 self.assertTrue(receivedResponse)
1169 doResponse.id = receivedResponse.id
1170 self.assertEqual(receivedResponse, doResponse)
1171
1172 class TestAdvancedLuaRefused(DNSDistTest):
1173
1174 _config_template = """
1175 function refuse(dq)
1176 return DNSAction.Refused, ""
1177 end
1178 addAction(AllRule(), LuaAction(refuse))
1179 newServer{address="127.0.0.1:%s"}
1180 """
1181
1182 def testRefusedViaLua(self):
1183 """
1184 Advanced: Refused via Lua
1185 """
1186 name = 'refused.advanced.tests.powerdns.com.'
1187 query = dns.message.make_query(name, 'A', 'IN')
1188 response = dns.message.make_response(query)
1189 rrset = dns.rrset.from_text(name,
1190 3600,
1191 dns.rdataclass.IN,
1192 dns.rdatatype.AAAA,
1193 '::1')
1194 response.answer.append(rrset)
1195 refusedResponse = dns.message.make_response(query)
1196 refusedResponse.set_rcode(dns.rcode.REFUSED)
1197
1198 for method in ("sendUDPQuery", "sendTCPQuery"):
1199 sender = getattr(self, method)
1200 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1201 self.assertTrue(receivedResponse)
1202 refusedResponse.id = receivedResponse.id
1203 self.assertEqual(receivedResponse, refusedResponse)
1204
1205 class TestAdvancedLuaActionReturnSyntax(DNSDistTest):
1206
1207 _config_template = """
1208 function refuse(dq)
1209 return DNSAction.Refused
1210 end
1211 addAction(AllRule(), LuaAction(refuse))
1212 newServer{address="127.0.0.1:%s"}
1213 """
1214
1215 def testRefusedWithEmptyRule(self):
1216 """
1217 Advanced: Short syntax for LuaAction return values
1218 """
1219 name = 'short.refused.advanced.tests.powerdns.com.'
1220 query = dns.message.make_query(name, 'A', 'IN')
1221 response = dns.message.make_response(query)
1222 rrset = dns.rrset.from_text(name,
1223 3600,
1224 dns.rdataclass.IN,
1225 dns.rdatatype.AAAA,
1226 '::1')
1227 response.answer.append(rrset)
1228 refusedResponse = dns.message.make_response(query)
1229 refusedResponse.set_rcode(dns.rcode.REFUSED)
1230
1231 for method in ("sendUDPQuery", "sendTCPQuery"):
1232 sender = getattr(self, method)
1233 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1234 self.assertTrue(receivedResponse)
1235 refusedResponse.id = receivedResponse.id
1236 self.assertEqual(receivedResponse, refusedResponse)
1237
1238 class TestAdvancedLuaTruncated(DNSDistTest):
1239
1240 _config_template = """
1241 function trunc(dq)
1242 if not dq.tcp then
1243 return DNSAction.Truncate, ""
1244 end
1245 return DNSAction.None, ""
1246 end
1247 addAction(AllRule(), LuaAction(trunc))
1248 newServer{address="127.0.0.1:%s"}
1249 """
1250
1251 def testTCViaLua(self):
1252 """
1253 Advanced: TC via Lua
1254 """
1255 name = 'tc.advanced.tests.powerdns.com.'
1256 query = dns.message.make_query(name, 'A', 'IN')
1257 # dnsdist sets RA = RD for TC responses
1258 query.flags &= ~dns.flags.RD
1259 response = dns.message.make_response(query)
1260 rrset = dns.rrset.from_text(name,
1261 3600,
1262 dns.rdataclass.IN,
1263 dns.rdatatype.AAAA,
1264 '::1')
1265 response.answer.append(rrset)
1266
1267 truncatedResponse = dns.message.make_response(query)
1268 truncatedResponse.flags |= dns.flags.TC
1269
1270 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
1271 self.assertTrue(receivedResponse)
1272 truncatedResponse.id = receivedResponse.id
1273 self.assertEqual(receivedResponse, truncatedResponse)
1274
1275 # no truncation over TCP
1276 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
1277 self.assertTrue(receivedQuery)
1278 self.assertTrue(receivedResponse)
1279 receivedQuery.id = query.id
1280 self.assertEqual(query, receivedQuery)
1281 self.assertEqual(receivedResponse, response)
1282
1283 class TestStatNodeRespRingSince(DNSDistTest):
1284
1285 _consoleKey = DNSDistTest.generateConsoleKey()
1286 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
1287 _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
1288 _config_template = """
1289 setKey("%s")
1290 controlSocket("127.0.0.1:%s")
1291 s1 = newServer{address="127.0.0.1:%s"}
1292 s1:setUp()
1293 function visitor(node, self, childstat)
1294 table.insert(nodesSeen, node.fullname)
1295 end
1296 """
1297
1298 def testStatNodeRespRingSince(self):
1299 """
1300 Advanced: StatNodeRespRing with optional since parameter
1301
1302 """
1303 name = 'statnodesince.advanced.tests.powerdns.com.'
1304 query = dns.message.make_query(name, 'A', 'IN')
1305 response = dns.message.make_response(query)
1306 rrset = dns.rrset.from_text(name,
1307 1,
1308 dns.rdataclass.IN,
1309 dns.rdatatype.A,
1310 '127.0.0.1')
1311 response.answer.append(rrset)
1312
1313 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1314 self.assertTrue(receivedQuery)
1315 self.assertTrue(receivedResponse)
1316 receivedQuery.id = query.id
1317 self.assertEqual(query, receivedQuery)
1318 self.assertEqual(response, receivedResponse)
1319
1320 self.sendConsoleCommand("nodesSeen = {}")
1321 self.sendConsoleCommand("statNodeRespRing(visitor)")
1322 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1323 nodes = nodes.strip("\n")
1324 self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
1325 advanced.tests.powerdns.com.
1326 tests.powerdns.com.
1327 powerdns.com.
1328 com.""")
1329
1330 self.sendConsoleCommand("nodesSeen = {}")
1331 self.sendConsoleCommand("statNodeRespRing(visitor, 0)")
1332 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1333 nodes = nodes.strip("\n")
1334 self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
1335 advanced.tests.powerdns.com.
1336 tests.powerdns.com.
1337 powerdns.com.
1338 com.""")
1339
1340 time.sleep(5)
1341
1342 self.sendConsoleCommand("nodesSeen = {}")
1343 self.sendConsoleCommand("statNodeRespRing(visitor)")
1344 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1345 nodes = nodes.strip("\n")
1346 self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
1347 advanced.tests.powerdns.com.
1348 tests.powerdns.com.
1349 powerdns.com.
1350 com.""")
1351
1352 self.sendConsoleCommand("nodesSeen = {}")
1353 self.sendConsoleCommand("statNodeRespRing(visitor, 5)")
1354 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1355 nodes = nodes.strip("\n")
1356 self.assertEqual(nodes, """""")
1357
1358 self.sendConsoleCommand("nodesSeen = {}")
1359 self.sendConsoleCommand("statNodeRespRing(visitor, 10)")
1360 nodes = self.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
1361 nodes = nodes.strip("\n")
1362 self.assertEqual(nodes, """statnodesince.advanced.tests.powerdns.com.
1363 advanced.tests.powerdns.com.
1364 tests.powerdns.com.
1365 powerdns.com.
1366 com.""")
1367
1368 class TestAdvancedRD(DNSDistTest):
1369
1370 _config_template = """
1371 addAction(RDRule(), RCodeAction(DNSRCode.REFUSED))
1372 newServer{address="127.0.0.1:%s"}
1373 """
1374
1375 def testAdvancedRDRefused(self):
1376 """
1377 Advanced: RD query is refused
1378 """
1379 name = 'rd.advanced.tests.powerdns.com.'
1380 query = dns.message.make_query(name, 'A', 'IN')
1381 expectedResponse = dns.message.make_response(query)
1382 expectedResponse.set_rcode(dns.rcode.REFUSED)
1383 expectedResponse.flags |= dns.flags.RA
1384
1385 for method in ("sendUDPQuery", "sendTCPQuery"):
1386 sender = getattr(self, method)
1387 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1388 self.assertEqual(receivedResponse, expectedResponse)
1389
1390 def testAdvancedNoRDAllowed(self):
1391 """
1392 Advanced: No-RD query is allowed
1393 """
1394 name = 'no-rd.advanced.tests.powerdns.com.'
1395 query = dns.message.make_query(name, 'A', 'IN')
1396 query.flags &= ~dns.flags.RD
1397 response = dns.message.make_response(query)
1398
1399 for method in ("sendUDPQuery", "sendTCPQuery"):
1400 sender = getattr(self, method)
1401 (receivedQuery, receivedResponse) = sender(query, response)
1402 receivedQuery.id = query.id
1403 self.assertEqual(receivedQuery, query)
1404 self.assertEqual(receivedResponse, response)
1405
1406 class TestAdvancedGetLocalPort(DNSDistTest):
1407
1408 _config_template = """
1409 function answerBasedOnLocalPort(dq)
1410 local port = dq.localaddr:getPort()
1411 return DNSAction.Spoof, "port-was-"..port..".local-port.advanced.tests.powerdns.com."
1412 end
1413 addAction("local-port.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
1414 newServer{address="127.0.0.1:%s"}
1415 """
1416
1417 def testAdvancedGetLocalPort(self):
1418 """
1419 Advanced: Return CNAME containing the local port
1420 """
1421 name = 'local-port.advanced.tests.powerdns.com.'
1422 query = dns.message.make_query(name, 'A', 'IN')
1423 # dnsdist set RA = RD for spoofed responses
1424 query.flags &= ~dns.flags.RD
1425
1426 response = dns.message.make_response(query)
1427 rrset = dns.rrset.from_text(name,
1428 60,
1429 dns.rdataclass.IN,
1430 dns.rdatatype.CNAME,
1431 'port-was-{}.local-port.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
1432 response.answer.append(rrset)
1433
1434 for method in ("sendUDPQuery", "sendTCPQuery"):
1435 sender = getattr(self, method)
1436 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1437 self.assertEqual(receivedResponse, response)
1438
1439 class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest):
1440
1441 _config_template = """
1442 function answerBasedOnLocalPort(dq)
1443 local port = dq.localaddr:getPort()
1444 return DNSAction.Spoof, "port-was-"..port..".local-port-any.advanced.tests.powerdns.com."
1445 end
1446 addAction("local-port-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
1447 newServer{address="127.0.0.1:%s"}
1448 """
1449 _dnsDistListeningAddr = "0.0.0.0"
1450
1451 def testAdvancedGetLocalPortOnAnyBind(self):
1452 """
1453 Advanced: Return CNAME containing the local port for an ANY bind
1454 """
1455 name = 'local-port-any.advanced.tests.powerdns.com.'
1456 query = dns.message.make_query(name, 'A', 'IN')
1457 # dnsdist set RA = RD for spoofed responses
1458 query.flags &= ~dns.flags.RD
1459
1460 response = dns.message.make_response(query)
1461 rrset = dns.rrset.from_text(name,
1462 60,
1463 dns.rdataclass.IN,
1464 dns.rdatatype.CNAME,
1465 'port-was-{}.local-port-any.advanced.tests.powerdns.com.'.format(self._dnsDistPort))
1466 response.answer.append(rrset)
1467
1468 for method in ("sendUDPQuery", "sendTCPQuery"):
1469 sender = getattr(self, method)
1470 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1471 self.assertEqual(receivedResponse, response)
1472
1473 class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest):
1474
1475 _config_template = """
1476 function answerBasedOnLocalAddress(dq)
1477 local dest = tostring(dq.localaddr)
1478 local i, j = string.find(dest, "[0-9.]+")
1479 local addr = string.sub(dest, i, j)
1480 local dashAddr = string.gsub(addr, "[.]", "-")
1481 return DNSAction.Spoof, "address-was-"..dashAddr..".local-address-any.advanced.tests.powerdns.com."
1482 end
1483 addAction("local-address-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalAddress))
1484 newServer{address="127.0.0.1:%s"}
1485 """
1486 _dnsDistListeningAddr = "0.0.0.0"
1487
1488 def testAdvancedGetLocalAddressOnAnyBind(self):
1489 """
1490 Advanced: Return CNAME containing the local address for an ANY bind
1491 """
1492 name = 'local-address-any.advanced.tests.powerdns.com.'
1493 query = dns.message.make_query(name, 'A', 'IN')
1494 # dnsdist set RA = RD for spoofed responses
1495 query.flags &= ~dns.flags.RD
1496
1497 response = dns.message.make_response(query)
1498 rrset = dns.rrset.from_text(name,
1499 60,
1500 dns.rdataclass.IN,
1501 dns.rdatatype.CNAME,
1502 'address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.')
1503 response.answer.append(rrset)
1504
1505 for method in ("sendUDPQuery", "sendTCPQuery"):
1506 sender = getattr(self, method)
1507 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1508 self.assertEqual(receivedResponse, response)
1509
1510 class TestAdvancedLuaTempFailureTTL(DNSDistTest):
1511
1512 _config_template = """
1513 function testAction(dq)
1514 if dq.tempFailureTTL ~= nil then
1515 return DNSAction.Spoof, "initially.not.nil.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1516 end
1517 dq.tempFailureTTL = 30
1518 if dq.tempFailureTTL ~= 30 then
1519 return DNSAction.Spoof, "after.set.not.expected.value.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1520 end
1521 dq.tempFailureTTL = nil
1522 if dq.tempFailureTTL ~= nil then
1523 return DNSAction.Spoof, "after.unset.not.nil.but." + dq.tempFailureTTL + ".tests.powerdns.com."
1524 end
1525 return DNSAction.None, ""
1526 end
1527 addAction(AllRule(), LuaAction(testAction))
1528 newServer{address="127.0.0.1:%s"}
1529 """
1530
1531 def testTempFailureTTLBinding(self):
1532 """
1533 Advanced: Exercise dq.tempFailureTTL Lua binding
1534 """
1535 name = 'tempfailurettlbinding.advanced.tests.powerdns.com.'
1536 query = dns.message.make_query(name, 'A', 'IN')
1537 response = dns.message.make_response(query)
1538 rrset = dns.rrset.from_text(name,
1539 3600,
1540 dns.rdataclass.IN,
1541 dns.rdatatype.AAAA,
1542 '::1')
1543 response.answer.append(rrset)
1544
1545 for method in ("sendUDPQuery", "sendTCPQuery"):
1546 sender = getattr(self, method)
1547 (receivedQuery, receivedResponse) = sender(query, response)
1548 self.assertTrue(receivedQuery)
1549 self.assertTrue(receivedResponse)
1550 receivedQuery.id = query.id
1551 self.assertEqual(query, receivedQuery)
1552 self.assertEqual(receivedResponse, response)
1553
1554 class TestAdvancedEDNSOptionRule(DNSDistTest):
1555
1556 _config_template = """
1557 newServer{address="127.0.0.1:%s"}
1558 addAction(EDNSOptionRule(EDNSOptionCode.ECS), DropAction())
1559 """
1560
1561 def testDropped(self):
1562 """
1563 Advanced: A question with ECS is dropped
1564 """
1565
1566 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1567
1568 ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
1569 query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso], payload=512)
1570
1571 for method in ("sendUDPQuery", "sendTCPQuery"):
1572 sender = getattr(self, method)
1573 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1574 self.assertEqual(receivedResponse, None)
1575
1576 def testReplied(self):
1577 """
1578 Advanced: A question without ECS is answered
1579 """
1580
1581 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1582
1583 # both with EDNS
1584 query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[], payload=512)
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.assertEqual(query, receivedQuery)
1595 self.assertEqual(receivedResponse, response)
1596
1597 # and with no EDNS at all
1598 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1599 response = dns.message.make_response(query)
1600
1601 for method in ("sendUDPQuery", "sendTCPQuery"):
1602 sender = getattr(self, method)
1603 (receivedQuery, receivedResponse) = sender(query, response)
1604 self.assertTrue(receivedQuery)
1605 self.assertTrue(receivedResponse)
1606
1607 receivedQuery.id = query.id
1608 self.assertEqual(query, receivedQuery)
1609 self.assertEqual(receivedResponse, response)
1610
1611 class TestAdvancedAllowHeaderOnly(DNSDistTest):
1612
1613 _config_template = """
1614 newServer{address="127.0.0.1:%s"}
1615 setAllowEmptyResponse(true)
1616 """
1617
1618 def testHeaderOnlyRefused(self):
1619 """
1620 Advanced: Header-only refused response
1621 """
1622 name = 'header-only-refused-response.advanced.tests.powerdns.com.'
1623 query = dns.message.make_query(name, 'A', 'IN')
1624 response = dns.message.make_response(query)
1625 response.set_rcode(dns.rcode.REFUSED)
1626 response.question = []
1627
1628 for method in ("sendUDPQuery", "sendTCPQuery"):
1629 sender = getattr(self, method)
1630 (receivedQuery, receivedResponse) = sender(query, response)
1631 self.assertTrue(receivedQuery)
1632 receivedQuery.id = query.id
1633 self.assertEqual(query, receivedQuery)
1634 self.assertEqual(receivedResponse, response)
1635
1636 def testHeaderOnlyNoErrorResponse(self):
1637 """
1638 Advanced: Header-only NoError response should be allowed
1639 """
1640 name = 'header-only-noerror-response.advanced.tests.powerdns.com.'
1641 query = dns.message.make_query(name, 'A', 'IN')
1642 response = dns.message.make_response(query)
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.assertEqual(query, receivedQuery)
1651 self.assertEqual(receivedResponse, response)
1652
1653 def testHeaderOnlyNXDResponse(self):
1654 """
1655 Advanced: Header-only NXD response should be allowed
1656 """
1657 name = 'header-only-nxd-response.advanced.tests.powerdns.com.'
1658 query = dns.message.make_query(name, 'A', 'IN')
1659 response = dns.message.make_response(query)
1660 response.set_rcode(dns.rcode.NXDOMAIN)
1661 response.question = []
1662
1663 for method in ("sendUDPQuery", "sendTCPQuery"):
1664 sender = getattr(self, method)
1665 (receivedQuery, receivedResponse) = sender(query, response)
1666 self.assertTrue(receivedQuery)
1667 receivedQuery.id = query.id
1668 self.assertEqual(query, receivedQuery)
1669 self.assertEqual(receivedResponse, response)
1670
1671 class TestAdvancedEDNSVersionRule(DNSDistTest):
1672
1673 _config_template = """
1674 newServer{address="127.0.0.1:%s"}
1675 addAction(EDNSVersionRule(0), ERCodeAction(DNSRCode.BADVERS))
1676 """
1677
1678 def testBadVers(self):
1679 """
1680 Advanced: A question with ECS version larger than 0 yields BADVERS
1681 """
1682
1683 name = 'ednsversionrule.advanced.tests.powerdns.com.'
1684
1685 query = dns.message.make_query(name, 'A', 'IN', use_edns=1)
1686 query.flags &= ~dns.flags.RD
1687 expectedResponse = dns.message.make_response(query)
1688 expectedResponse.set_rcode(dns.rcode.BADVERS)
1689
1690 for method in ("sendUDPQuery", "sendTCPQuery"):
1691 sender = getattr(self, method)
1692 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1693 self.assertEqual(receivedResponse, expectedResponse)
1694
1695 def testNoEDNS0Pass(self):
1696 """
1697 Advanced: A question with ECS version 0 goes through
1698 """
1699
1700 name = 'ednsversionrule.advanced.tests.powerdns.com.'
1701
1702 query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
1703 response = dns.message.make_response(query)
1704
1705 for method in ("sendUDPQuery", "sendTCPQuery"):
1706 sender = getattr(self, method)
1707 (receivedQuery, receivedResponse) = sender(query, response)
1708 receivedQuery.id = query.id
1709 self.assertEqual(query, receivedQuery)
1710 self.assertEqual(receivedResponse, response)
1711
1712 def testReplied(self):
1713 """
1714 Advanced: A question without ECS goes through
1715 """
1716
1717 name = 'ednsoptionrule.advanced.tests.powerdns.com.'
1718
1719 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1720 response = dns.message.make_response(query)
1721
1722 for method in ("sendUDPQuery", "sendTCPQuery"):
1723 sender = getattr(self, method)
1724 (receivedQuery, receivedResponse) = sender(query, response)
1725 receivedQuery.id = query.id
1726 self.assertEqual(query, receivedQuery)
1727 self.assertEqual(receivedResponse, response)
1728
1729 class TestSetRules(DNSDistTest):
1730
1731 _consoleKey = DNSDistTest.generateConsoleKey()
1732 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
1733 _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort']
1734 _config_template = """
1735 setKey("%s")
1736 controlSocket("127.0.0.1:%s")
1737 newServer{address="127.0.0.1:%s"}
1738 addAction(AllRule(), SpoofAction("192.0.2.1"))
1739 """
1740
1741 def testClearThenSetRules(self):
1742 """
1743 Advanced: Clear rules, set rules
1744
1745 """
1746 name = 'clearthensetrules.advanced.tests.powerdns.com.'
1747 query = dns.message.make_query(name, 'A', 'IN')
1748 # dnsdist set RA = RD for spoofed responses
1749 query.flags &= ~dns.flags.RD
1750 expectedResponse = dns.message.make_response(query)
1751 rrset = dns.rrset.from_text(name,
1752 60,
1753 dns.rdataclass.IN,
1754 dns.rdatatype.A,
1755 '192.0.2.1')
1756 expectedResponse.answer.append(rrset)
1757
1758 for method in ("sendUDPQuery", "sendTCPQuery"):
1759 sender = getattr(self, method)
1760
1761 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1762 self.assertTrue(receivedResponse)
1763 self.assertEqual(expectedResponse, receivedResponse)
1764
1765 # clear all the rules, we should not be spoofing and get a SERVFAIL from the responder instead
1766 self.sendConsoleCommand("clearRules()")
1767
1768 expectedResponse = dns.message.make_response(query)
1769 expectedResponse.set_rcode(dns.rcode.SERVFAIL)
1770
1771 for method in ("sendUDPQuery", "sendTCPQuery"):
1772 sender = getattr(self, method)
1773
1774 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1775 self.assertTrue(receivedResponse)
1776 self.assertEqual(expectedResponse, receivedResponse)
1777
1778 # insert a new spoofing rule
1779 self.sendConsoleCommand("setRules({ newRuleAction(AllRule(), SpoofAction(\"192.0.2.2\")) })")
1780
1781 expectedResponse = dns.message.make_response(query)
1782 rrset = dns.rrset.from_text(name,
1783 60,
1784 dns.rdataclass.IN,
1785 dns.rdatatype.A,
1786 '192.0.2.2')
1787 expectedResponse.answer.append(rrset)
1788
1789 for method in ("sendUDPQuery", "sendTCPQuery"):
1790 sender = getattr(self, method)
1791
1792 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1793 self.assertTrue(receivedResponse)
1794 self.assertEqual(expectedResponse, receivedResponse)
1795
1796 class TestAdvancedContinueAction(DNSDistTest):
1797
1798 _config_template = """
1799 newServer{address="127.0.0.1:%s", pool="mypool"}
1800 addAction("nocontinue.continue-action.advanced.tests.powerdns.com.", PoolAction("mypool"))
1801 addAction("continue.continue-action.advanced.tests.powerdns.com.", ContinueAction(PoolAction("mypool")))
1802 addAction(AllRule(), SetDisableValidationAction())
1803 """
1804
1805 def testNoContinue(self):
1806 """
1807 Advanced: Query routed to pool, PoolAction should be terminal
1808 """
1809
1810 name = 'nocontinue.continue-action.advanced.tests.powerdns.com.'
1811
1812 query = dns.message.make_query(name, 'A', 'IN')
1813 expectedQuery = dns.message.make_query(name, 'A', 'IN')
1814
1815 response = dns.message.make_response(query)
1816 expectedResponse = dns.message.make_response(query)
1817
1818 for method in ("sendUDPQuery", "sendTCPQuery"):
1819 sender = getattr(self, method)
1820 (receivedQuery, receivedResponse) = sender(query, response)
1821 self.assertEqual(receivedQuery, expectedQuery)
1822 self.assertEqual(receivedResponse, expectedResponse)
1823
1824 def testNoContinue(self):
1825 """
1826 Advanced: Query routed to pool, ContinueAction() should not stop the processing
1827 """
1828
1829 name = 'continue.continue-action.advanced.tests.powerdns.com.'
1830
1831 query = dns.message.make_query(name, 'A', 'IN')
1832 expectedQuery = dns.message.make_query(name, 'A', 'IN')
1833 expectedQuery.flags |= dns.flags.CD
1834
1835 response = dns.message.make_response(query)
1836 expectedResponse = dns.message.make_response(query)
1837
1838 for method in ("sendUDPQuery", "sendTCPQuery"):
1839 sender = getattr(self, method)
1840 (receivedQuery, receivedResponse) = sender(query, response)
1841 expectedQuery.id = receivedQuery.id
1842 self.assertEqual(receivedQuery, expectedQuery)
1843 self.assertEqual(receivedResponse, expectedResponse)
1844
1845 class TestAdvancedNegativeAndSOA(DNSDistTest):
1846
1847 _selfGeneratedPayloadSize = 1232
1848 _config_template = """
1849 addAction("nxd.negativeandsoa.advanced.tests.powerdns.com.", NegativeAndSOAAction(true, "auth.", 42, "mname", "rname", 5, 4, 3, 2, 1))
1850 addAction("nodata.negativeandsoa.advanced.tests.powerdns.com.", NegativeAndSOAAction(false, "another-auth.", 42, "mname", "rname", 1, 2, 3, 4, 5))
1851 setPayloadSizeOnSelfGeneratedAnswers(%d)
1852 newServer{address="127.0.0.1:%s"}
1853 """
1854 _config_params = ['_selfGeneratedPayloadSize', '_testServerPort']
1855
1856
1857 def testAdvancedNegativeAndSOANXD(self):
1858 """
1859 Advanced: NegativeAndSOAAction NXD
1860 """
1861 name = 'nxd.negativeandsoa.advanced.tests.powerdns.com.'
1862 # no EDNS
1863 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1864 query.flags &= ~dns.flags.RD
1865 expectedResponse = dns.message.make_response(query)
1866 expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
1867 soa = dns.rrset.from_text("auth.",
1868 42,
1869 dns.rdataclass.IN,
1870 dns.rdatatype.SOA,
1871 'mname. rname. 5 4 3 2 1')
1872 expectedResponse.additional.append(soa)
1873
1874 for method in ("sendUDPQuery", "sendTCPQuery"):
1875 sender = getattr(self, method)
1876 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1877 self.checkMessageNoEDNS(expectedResponse, receivedResponse)
1878
1879 # withEDNS
1880 query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
1881 query.flags &= ~dns.flags.RD
1882 expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize)
1883 expectedResponse.set_rcode(dns.rcode.NXDOMAIN)
1884 soa = dns.rrset.from_text("auth.",
1885 42,
1886 dns.rdataclass.IN,
1887 dns.rdatatype.SOA,
1888 'mname. rname. 5 4 3 2 1')
1889 expectedResponse.additional.append(soa)
1890
1891 for method in ("sendUDPQuery", "sendTCPQuery"):
1892 sender = getattr(self, method)
1893 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1894 self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
1895
1896 def testAdvancedNegativeAndSOANoData(self):
1897 """
1898 Advanced: NegativeAndSOAAction NoData
1899 """
1900 name = 'nodata.negativeandsoa.advanced.tests.powerdns.com.'
1901 # no EDNS
1902 query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
1903 query.flags &= ~dns.flags.RD
1904 expectedResponse = dns.message.make_response(query)
1905 expectedResponse.set_rcode(dns.rcode.NOERROR)
1906 soa = dns.rrset.from_text("another-auth.",
1907 42,
1908 dns.rdataclass.IN,
1909 dns.rdatatype.SOA,
1910 'mname. rname. 1 2 3 4 5')
1911 expectedResponse.additional.append(soa)
1912
1913 for method in ("sendUDPQuery", "sendTCPQuery"):
1914 sender = getattr(self, method)
1915 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1916 self.checkMessageNoEDNS(expectedResponse, receivedResponse)
1917
1918 # with EDNS
1919 query = dns.message.make_query(name, 'A', 'IN', use_edns=True)
1920 query.flags &= ~dns.flags.RD
1921 expectedResponse = dns.message.make_response(query, our_payload=self._selfGeneratedPayloadSize)
1922 expectedResponse.set_rcode(dns.rcode.NOERROR)
1923 soa = dns.rrset.from_text("another-auth.",
1924 42,
1925 dns.rdataclass.IN,
1926 dns.rdatatype.SOA,
1927 'mname. rname. 1 2 3 4 5')
1928 expectedResponse.additional.append(soa)
1929
1930 for method in ("sendUDPQuery", "sendTCPQuery"):
1931 sender = getattr(self, method)
1932 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1933 self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
1934
1935 class TestAdvancedLuaRule(DNSDistTest):
1936
1937 _config_template = """
1938
1939 function luarulefunction(dq)
1940 if dq:getTag('a-tag') ~= 'a-value' then
1941 print('invalid tag value')
1942 return false
1943 end
1944
1945 if tostring(dq.qname) ~= 'lua-rule.advanced.tests.powerdns.com.' then
1946 print('invalid qname')
1947 return false
1948 end
1949
1950 return true
1951 end
1952
1953 addAction(AllRule(), SetTagAction('a-tag', 'a-value'))
1954 addAction(LuaRule(luarulefunction), RCodeAction(DNSRCode.NOTIMP))
1955 addAction(AllRule(), RCodeAction(DNSRCode.REFUSED))
1956 -- newServer{address="127.0.0.1:%s"}
1957 """
1958
1959 def testAdvancedLuaRule(self):
1960 """
1961 Advanced: Test the LuaRule rule
1962 """
1963 name = 'lua-rule.advanced.tests.powerdns.com.'
1964 query = dns.message.make_query(name, 'A', 'IN')
1965 # dnsdist set RA = RD for spoofed responses
1966 query.flags &= ~dns.flags.RD
1967 notimplResponse = dns.message.make_response(query)
1968 notimplResponse.set_rcode(dns.rcode.NOTIMP)
1969
1970 for method in ("sendUDPQuery", "sendTCPQuery"):
1971 sender = getattr(self, method)
1972 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1973 self.assertEqual(receivedResponse, notimplResponse)
1974
1975 name = 'not-lua-rule.advanced.tests.powerdns.com.'
1976 query = dns.message.make_query(name, 'A', 'IN')
1977 # dnsdist set RA = RD for spoofed responses
1978 query.flags &= ~dns.flags.RD
1979 refusedResponse = dns.message.make_response(query)
1980 refusedResponse.set_rcode(dns.rcode.REFUSED)
1981
1982 for method in ("sendUDPQuery", "sendTCPQuery"):
1983 sender = getattr(self, method)
1984 (_, receivedResponse) = sender(query, response=None, useQueue=False)
1985 self.assertEqual(receivedResponse, refusedResponse)
1986
1987 class TestAdvancedLuaFFI(DNSDistTest):
1988
1989 _config_template = """
1990 local ffi = require("ffi")
1991
1992 local expectingUDP = true
1993
1994 function luaffirulefunction(dq)
1995 local qtype = ffi.C.dnsdist_ffi_dnsquestion_get_qtype(dq)
1996 if qtype ~= DNSQType.A and qtype ~= DNSQType.SOA then
1997 print('invalid qtype')
1998 return false
1999 end
2000
2001 local qclass = ffi.C.dnsdist_ffi_dnsquestion_get_qclass(dq)
2002 if qclass ~= DNSClass.IN then
2003 print('invalid qclass')
2004 return false
2005 end
2006
2007 local ret_ptr = ffi.new("char *[1]")
2008 local ret_ptr_param = ffi.cast("const char **", ret_ptr)
2009 local ret_size = ffi.new("size_t[1]")
2010 local ret_size_param = ffi.cast("size_t*", ret_size)
2011 ffi.C.dnsdist_ffi_dnsquestion_get_qname_raw(dq, ret_ptr_param, ret_size_param)
2012 if ret_size[0] ~= 36 then
2013 print('invalid length for the qname ')
2014 print(ret_size[0])
2015 return false
2016 end
2017
2018 local expectedQname = string.char(6)..'luaffi'..string.char(8)..'advanced'..string.char(5)..'tests'..string.char(8)..'powerdns'..string.char(3)..'com'
2019 if ffi.string(ret_ptr[0]) ~= expectedQname then
2020 print('invalid qname')
2021 print(ffi.string(ret_ptr[0]))
2022 return false
2023 end
2024
2025 local rcode = ffi.C.dnsdist_ffi_dnsquestion_get_rcode(dq)
2026 if rcode ~= 0 then
2027 print('invalid rcode')
2028 return false
2029 end
2030
2031 local opcode = ffi.C.dnsdist_ffi_dnsquestion_get_opcode(dq)
2032 if qtype == DNSQType.A and opcode ~= DNSOpcode.Query then
2033 print('invalid opcode')
2034 return false
2035 elseif qtype == DNSQType.SOA and opcode ~= DNSOpcode.Update then
2036 print('invalid opcode')
2037 return false
2038 end
2039
2040 local tcp = ffi.C.dnsdist_ffi_dnsquestion_get_tcp(dq)
2041 if expectingUDP == tcp then
2042 print('invalid tcp')
2043 return false
2044 end
2045 expectingUDP = expectingUDP == false
2046
2047 local dnssecok = ffi.C.dnsdist_ffi_dnsquestion_get_do(dq)
2048 if dnssecok ~= false then
2049 print('invalid DNSSEC OK')
2050 return false
2051 end
2052
2053 local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
2054 if len ~= 52 then
2055 print('invalid length')
2056 print(len)
2057 return false
2058 end
2059
2060 local tag = ffi.C.dnsdist_ffi_dnsquestion_get_tag(dq, 'a-tag')
2061 if ffi.string(tag) ~= 'a-value' then
2062 print('invalid tag value')
2063 print(ffi.string(tag))
2064 return false
2065 end
2066 return true
2067 end
2068
2069 function luaffiactionfunction(dq)
2070 local qtype = ffi.C.dnsdist_ffi_dnsquestion_get_qtype(dq)
2071 if qtype == DNSQType.A then
2072 local str = "192.0.2.1"
2073 local buf = ffi.new("char[?]", #str + 1)
2074 ffi.copy(buf, str)
2075 ffi.C.dnsdist_ffi_dnsquestion_set_result(dq, buf, #str)
2076 return DNSAction.Spoof
2077 elseif qtype == DNSQType.SOA then
2078 ffi.C.dnsdist_ffi_dnsquestion_set_rcode(dq, DNSRCode.REFUSED)
2079 return DNSAction.Refused
2080 end
2081 end
2082
2083 function luaffiactionsettag(dq)
2084 ffi.C.dnsdist_ffi_dnsquestion_set_tag(dq, 'a-tag', 'a-value')
2085 return DNSAction.None
2086 end
2087
2088 addAction(AllRule(), LuaFFIAction(luaffiactionsettag))
2089 addAction(LuaFFIRule(luaffirulefunction), LuaFFIAction(luaffiactionfunction))
2090 -- newServer{address="127.0.0.1:%s"}
2091 """
2092
2093 def testAdvancedLuaFFI(self):
2094 """
2095 Advanced: Test the Lua FFI interface
2096 """
2097 name = 'luaffi.advanced.tests.powerdns.com.'
2098 query = dns.message.make_query(name, 'A', 'IN')
2099 # dnsdist set RA = RD for spoofed responses
2100 query.flags &= ~dns.flags.RD
2101
2102 response = dns.message.make_response(query)
2103 rrset = dns.rrset.from_text(name,
2104 60,
2105 dns.rdataclass.IN,
2106 dns.rdatatype.A,
2107 '192.0.2.1')
2108 response.answer.append(rrset)
2109
2110 for method in ("sendUDPQuery", "sendTCPQuery"):
2111 sender = getattr(self, method)
2112 (_, receivedResponse) = sender(query, response=None, useQueue=False)
2113 self.assertEqual(receivedResponse, response)
2114
2115 def testAdvancedLuaFFIUpdate(self):
2116 """
2117 Advanced: Test the Lua FFI interface via an update
2118 """
2119 name = 'luaffi.advanced.tests.powerdns.com.'
2120 query = dns.message.make_query(name, 'SOA', 'IN')
2121 query.set_opcode(dns.opcode.UPDATE)
2122 # dnsdist set RA = RD for spoofed responses
2123 query.flags &= ~dns.flags.RD
2124
2125 response = dns.message.make_response(query)
2126 response.set_rcode(dns.rcode.REFUSED)
2127
2128 for method in ("sendUDPQuery", "sendTCPQuery"):
2129 sender = getattr(self, method)
2130 (_, receivedResponse) = sender(query, response=None, useQueue=False)
2131 self.assertEqual(receivedResponse, response)
2132
2133 class TestAdvancedLuaFFIPerThread(DNSDistTest):
2134
2135 _config_template = """
2136
2137 local rulefunction = [[
2138 local ffi = require("ffi")
2139
2140 return function(dq)
2141 local qtype = ffi.C.dnsdist_ffi_dnsquestion_get_qtype(dq)
2142 if qtype ~= DNSQType.A and qtype ~= DNSQType.SOA then
2143 print('invalid qtype')
2144 return false
2145 end
2146
2147 local qclass = ffi.C.dnsdist_ffi_dnsquestion_get_qclass(dq)
2148 if qclass ~= DNSClass.IN then
2149 print('invalid qclass')
2150 return false
2151 end
2152
2153 local ret_ptr = ffi.new("char *[1]")
2154 local ret_ptr_param = ffi.cast("const char **", ret_ptr)
2155 local ret_size = ffi.new("size_t[1]")
2156 local ret_size_param = ffi.cast("size_t*", ret_size)
2157 ffi.C.dnsdist_ffi_dnsquestion_get_qname_raw(dq, ret_ptr_param, ret_size_param)
2158 if ret_size[0] ~= 45 then
2159 print('invalid length for the qname ')
2160 print(ret_size[0])
2161 return false
2162 end
2163
2164 local expectedQname = string.char(15)..'luaffiperthread'..string.char(8)..'advanced'..string.char(5)..'tests'..string.char(8)..'powerdns'..string.char(3)..'com'
2165 if ffi.string(ret_ptr[0]) ~= expectedQname then
2166 print('invalid qname')
2167 print(ffi.string(ret_ptr[0]))
2168 return false
2169 end
2170
2171 local rcode = ffi.C.dnsdist_ffi_dnsquestion_get_rcode(dq)
2172 if rcode ~= 0 then
2173 print('invalid rcode')
2174 return false
2175 end
2176
2177 local opcode = ffi.C.dnsdist_ffi_dnsquestion_get_opcode(dq)
2178 if qtype == DNSQType.A and opcode ~= DNSOpcode.Query then
2179 print('invalid opcode')
2180 return false
2181 elseif qtype == DNSQType.SOA and opcode ~= DNSOpcode.Update then
2182 print('invalid opcode')
2183 return false
2184 end
2185
2186 local dnssecok = ffi.C.dnsdist_ffi_dnsquestion_get_do(dq)
2187 if dnssecok ~= false then
2188 print('invalid DNSSEC OK')
2189 return false
2190 end
2191
2192 local len = ffi.C.dnsdist_ffi_dnsquestion_get_len(dq)
2193 if len ~= 61 then
2194 print('invalid length')
2195 print(len)
2196 return false
2197 end
2198
2199 local tag = ffi.C.dnsdist_ffi_dnsquestion_get_tag(dq, 'a-tag')
2200 if ffi.string(tag) ~= 'a-value' then
2201 print('invalid tag value')
2202 print(ffi.string(tag))
2203 return false
2204 end
2205
2206 return true
2207 end
2208 ]]
2209
2210 local actionfunction = [[
2211 local ffi = require("ffi")
2212
2213 return function(dq)
2214 local qtype = ffi.C.dnsdist_ffi_dnsquestion_get_qtype(dq)
2215 if qtype == DNSQType.A then
2216 local str = "192.0.2.1"
2217 local buf = ffi.new("char[?]", #str + 1)
2218 ffi.copy(buf, str)
2219 ffi.C.dnsdist_ffi_dnsquestion_set_result(dq, buf, #str)
2220 return DNSAction.Spoof
2221 elseif qtype == DNSQType.SOA then
2222 ffi.C.dnsdist_ffi_dnsquestion_set_rcode(dq, DNSRCode.REFUSED)
2223 return DNSAction.Refused
2224 end
2225 end
2226 ]]
2227
2228 local settagfunction = [[
2229 local ffi = require("ffi")
2230
2231 return function(dq)
2232 ffi.C.dnsdist_ffi_dnsquestion_set_tag(dq, 'a-tag', 'a-value')
2233 return DNSAction.None
2234 end
2235 ]]
2236
2237 addAction(AllRule(), LuaFFIPerThreadAction(settagfunction))
2238 addAction(LuaFFIPerThreadRule(rulefunction), LuaFFIPerThreadAction(actionfunction))
2239 -- newServer{address="127.0.0.1:%s"}
2240 """
2241
2242 def testAdvancedLuaPerthreadFFI(self):
2243 """
2244 Advanced: Test the Lua FFI per-thread interface
2245 """
2246 name = 'luaffiperthread.advanced.tests.powerdns.com.'
2247 query = dns.message.make_query(name, 'A', 'IN')
2248 # dnsdist set RA = RD for spoofed responses
2249 query.flags &= ~dns.flags.RD
2250
2251 response = dns.message.make_response(query)
2252 rrset = dns.rrset.from_text(name,
2253 60,
2254 dns.rdataclass.IN,
2255 dns.rdatatype.A,
2256 '192.0.2.1')
2257 response.answer.append(rrset)
2258
2259 for method in ("sendUDPQuery", "sendTCPQuery"):
2260 sender = getattr(self, method)
2261 (_, receivedResponse) = sender(query, response=None, useQueue=False)
2262 self.assertEqual(receivedResponse, response)
2263
2264 def testAdvancedLuaFFIPerThreadUpdate(self):
2265 """
2266 Advanced: Test the Lua FFI per-thread interface via an update
2267 """
2268 name = 'luaffiperthread.advanced.tests.powerdns.com.'
2269 query = dns.message.make_query(name, 'SOA', 'IN')
2270 query.set_opcode(dns.opcode.UPDATE)
2271 # dnsdist set RA = RD for spoofed responses
2272 query.flags &= ~dns.flags.RD
2273
2274 response = dns.message.make_response(query)
2275 response.set_rcode(dns.rcode.REFUSED)
2276
2277 for method in ("sendUDPQuery", "sendTCPQuery"):
2278 sender = getattr(self, method)
2279 (_, receivedResponse) = sender(query, response=None, useQueue=False)
2280 self.assertEqual(receivedResponse, response)
2281
2282 class TestAdvancedDropEmptyQueries(DNSDistTest):
2283
2284 _config_template = """
2285 setDropEmptyQueries(true)
2286 newServer{address="127.0.0.1:%s"}
2287 """
2288
2289 def testAdvancedDropEmptyQueries(self):
2290 """
2291 Advanced: Drop empty queries
2292 """
2293 name = 'drop-empty-queries.advanced.tests.powerdns.com.'
2294 query = dns.message.Message()
2295
2296 for method in ("sendUDPQuery", "sendTCPQuery"):
2297 sender = getattr(self, method)
2298 (_, receivedResponse) = sender(query, response=None, useQueue=False)
2299 self.assertEqual(receivedResponse, None)
2300
2301 class TestProtocols(DNSDistTest):
2302 _config_template = """
2303 function checkUDP(dq)
2304 if dq:getProtocol() ~= "Do53 UDP" then
2305 return DNSAction.Spoof, '1.2.3.4'
2306 end
2307 return DNSAction.None
2308 end
2309
2310 function checkTCP(dq)
2311 if dq:getProtocol() ~= "Do53 TCP" then
2312 return DNSAction.Spoof, '1.2.3.4'
2313 end
2314 return DNSAction.None
2315 end
2316
2317 addAction("udp.protocols.advanced.tests.powerdns.com.", LuaAction(checkUDP))
2318 addAction("tcp.protocols.advanced.tests.powerdns.com.", LuaAction(checkTCP))
2319 newServer{address="127.0.0.1:%s"}
2320 """
2321
2322 def testProtocolUDP(self):
2323 """
2324 Advanced: Test DNSQuestion.Protocol over UDP
2325 """
2326 name = 'udp.protocols.advanced.tests.powerdns.com.'
2327 query = dns.message.make_query(name, 'A', 'IN')
2328 response = dns.message.make_response(query)
2329
2330 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
2331 receivedQuery.id = query.id
2332 self.assertEqual(receivedQuery, query)
2333 self.assertEqual(receivedResponse, response)
2334
2335 def testProtocolTCP(self):
2336 """
2337 Advanced: Test DNSQuestion.Protocol over TCP
2338 """
2339 name = 'tcp.protocols.advanced.tests.powerdns.com.'
2340 query = dns.message.make_query(name, 'A', 'IN')
2341 response = dns.message.make_response(query)
2342
2343 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
2344 receivedQuery.id = query.id
2345 self.assertEqual(receivedQuery, query)
2346 self.assertEqual(receivedResponse, response)