]> git.ipfire.org Git - thirdparty/pdns.git/blame - regression-tests.dnsdist/test_Advanced.py
dnsdist: More regression tests cleanups
[thirdparty/pdns.git] / regression-tests.dnsdist / test_Advanced.py
CommitLineData
ec5f5c6b
RG
1#!/usr/bin/env python
2from datetime import datetime, timedelta
3import dns
4import os
5import subprocess
6import threading
7import time
8import unittest
9from dnsdisttests import DNSDistTest
10
11class TestAdvancedFixupCase(DNSDistTest):
12
ec5f5c6b
RG
13 _config_template = """
14 truncateTC(true)
15 fixupCase(true)
16 newServer{address="127.0.0.1:%s"}
17 """
18
ec5f5c6b
RG
19 def testAdvancedFixupCase(self):
20 """
617dfe22
RG
21 Advanced: Fixup Case
22
ec5f5c6b
RG
23 Send a query with lower and upper chars,
24 make the backend return a lowercase version,
25 check that dnsdist fixes the response.
26 """
27 name = 'fiXuPCasE.advanced.tests.powerdns.com.'
28 query = dns.message.make_query(name, 'A', 'IN')
29 lowercasequery = dns.message.make_query(name.lower(), 'A', 'IN')
30 response = dns.message.make_response(lowercasequery)
31 expectedResponse = dns.message.make_response(query)
32 rrset = dns.rrset.from_text(name,
33 3600,
34 dns.rdataclass.IN,
35 dns.rdatatype.A,
36 '127.0.0.1')
37 response.answer.append(rrset)
38 expectedResponse.answer.append(rrset)
39
40 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
41 self.assertTrue(receivedQuery)
42 self.assertTrue(receivedResponse)
43 receivedQuery.id = query.id
44 receivedResponse.id = expectedResponse.id
45 self.assertEquals(query, receivedQuery)
46 self.assertEquals(expectedResponse, receivedResponse)
47
48 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
49 self.assertTrue(receivedQuery)
50 self.assertTrue(receivedResponse)
51 receivedQuery.id = query.id
52 receivedResponse.id = expectedResponse.id
53 self.assertEquals(query, receivedQuery)
54 self.assertEquals(expectedResponse, receivedResponse)
55
56
57class TestAdvancedRemoveRD(DNSDistTest):
58
ec5f5c6b
RG
59 _config_template = """
60 addNoRecurseRule("norecurse.advanced.tests.powerdns.com.")
61 newServer{address="127.0.0.1:%s"}
62 """
63
ec5f5c6b
RG
64 def testAdvancedNoRD(self):
65 """
617dfe22
RG
66 Advanced: No RD
67
ec5f5c6b
RG
68 Send a query with RD,
69 check that dnsdist clears the RD flag.
70 """
71 name = 'norecurse.advanced.tests.powerdns.com.'
72 query = dns.message.make_query(name, 'A', 'IN')
73 expectedQuery = dns.message.make_query(name, 'A', 'IN')
74 expectedQuery.flags &= ~dns.flags.RD
75
76 response = dns.message.make_response(query)
77 rrset = dns.rrset.from_text(name,
78 3600,
79 dns.rdataclass.IN,
80 dns.rdatatype.A,
81 '127.0.0.1')
82 response.answer.append(rrset)
83
84 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
85 self.assertTrue(receivedQuery)
86 self.assertTrue(receivedResponse)
87 receivedQuery.id = expectedQuery.id
88 receivedResponse.id = response.id
89 self.assertEquals(expectedQuery, receivedQuery)
90 self.assertEquals(response, receivedResponse)
91
92 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
93 self.assertTrue(receivedQuery)
94 self.assertTrue(receivedResponse)
95 receivedQuery.id = expectedQuery.id
96 receivedResponse.id = response.id
97 self.assertEquals(expectedQuery, receivedQuery)
98 self.assertEquals(response, receivedResponse)
99
100 def testAdvancedKeepRD(self):
101 """
617dfe22
RG
102 Advanced: No RD canary
103
ec5f5c6b
RG
104 Send a query with RD for a canary domain,
105 check that dnsdist does not clear the RD flag.
106 """
107 name = 'keeprecurse.advanced.tests.powerdns.com.'
108 query = dns.message.make_query(name, 'A', 'IN')
109
110 response = dns.message.make_response(query)
111 rrset = dns.rrset.from_text(name,
112 3600,
113 dns.rdataclass.IN,
114 dns.rdatatype.A,
115 '127.0.0.1')
116 response.answer.append(rrset)
117
118 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
119 self.assertTrue(receivedQuery)
120 self.assertTrue(receivedResponse)
121 receivedQuery.id = query.id
122 receivedResponse.id = response.id
123 self.assertEquals(query, receivedQuery)
124 self.assertEquals(response, receivedResponse)
125
126 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
127 self.assertTrue(receivedQuery)
128 self.assertTrue(receivedResponse)
129 receivedQuery.id = query.id
130 receivedResponse.id = response.id
131 self.assertEquals(query, receivedQuery)
132 self.assertEquals(response, receivedResponse)
133
134
135class TestAdvancedAddCD(DNSDistTest):
136
ec5f5c6b
RG
137 _config_template = """
138 addDisableValidationRule("setcd.advanced.tests.powerdns.com.")
139 newServer{address="127.0.0.1:%s"}
140 """
141
ec5f5c6b
RG
142 def testAdvancedSetCD(self):
143 """
617dfe22
RG
144 Advanced: Set CD
145
ec5f5c6b
RG
146 Send a query with CD cleared,
147 check that dnsdist set the CD flag.
148 """
149 name = 'setcd.advanced.tests.powerdns.com.'
150 query = dns.message.make_query(name, 'A', 'IN')
151 expectedQuery = dns.message.make_query(name.lower(), 'A', 'IN')
152 expectedQuery.flags |= dns.flags.CD
153
154 response = dns.message.make_response(query)
155 rrset = dns.rrset.from_text(name,
156 3600,
157 dns.rdataclass.IN,
158 dns.rdatatype.A,
159 '127.0.0.1')
160 response.answer.append(rrset)
161
162 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
163 self.assertTrue(receivedQuery)
164 self.assertTrue(receivedResponse)
165 receivedQuery.id = expectedQuery.id
166 receivedResponse.id = response.id
167 self.assertEquals(expectedQuery, receivedQuery)
168 self.assertEquals(response, receivedResponse)
169
170 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
171 self.assertTrue(receivedQuery)
172 self.assertTrue(receivedResponse)
173 receivedQuery.id = expectedQuery.id
174 receivedResponse.id = response.id
175 self.assertEquals(expectedQuery, receivedQuery)
176 self.assertEquals(response, receivedResponse)
177
178 def testAdvancedKeepNoCD(self):
179 """
617dfe22
RG
180 Advanced: Preserve CD canary
181
ec5f5c6b
RG
182 Send a query without CD for a canary domain,
183 check that dnsdist does not set the CD flag.
184 """
185 name = 'keepnocd.advanced.tests.powerdns.com.'
186 query = dns.message.make_query(name, 'A', 'IN')
187
188 response = dns.message.make_response(query)
189 rrset = dns.rrset.from_text(name,
190 3600,
191 dns.rdataclass.IN,
192 dns.rdatatype.A,
193 '127.0.0.1')
194 response.answer.append(rrset)
195
196 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
197 self.assertTrue(receivedQuery)
198 self.assertTrue(receivedResponse)
199 receivedQuery.id = query.id
200 receivedResponse.id = response.id
201 self.assertEquals(query, receivedQuery)
202 self.assertEquals(response, receivedResponse)
203
204 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
205 self.assertTrue(receivedQuery)
206 self.assertTrue(receivedResponse)
207 receivedQuery.id = query.id
208 receivedResponse.id = response.id
209 self.assertEquals(query, receivedQuery)
210 self.assertEquals(response, receivedResponse)
211
212class TestAdvancedSpoof(DNSDistTest):
213
ec5f5c6b
RG
214 _config_template = """
215 addDomainSpoof("spoof.tests.powerdns.com.", "192.0.2.1", "2001:DB8::1")
87c605c4 216 addDomainCNAMESpoof("cnamespoof.tests.powerdns.com.", "cname.tests.powerdns.com.")
ec5f5c6b
RG
217 newServer{address="127.0.0.1:%s"}
218 """
219
ec5f5c6b
RG
220 def testSpoofA(self):
221 """
617dfe22
RG
222 Advanced: Spoof A
223
ec5f5c6b
RG
224 Send an A query to "spoof.tests.powerdns.com.",
225 check that dnsdist sends a spoofed result.
226 """
227 name = 'spoof.tests.powerdns.com.'
228 query = dns.message.make_query(name, 'A', 'IN')
229 # dnsdist set RA = RD for spoofed responses
230 query.flags &= ~dns.flags.RD
231 expectedResponse = dns.message.make_response(query)
232 rrset = dns.rrset.from_text(name,
233 60,
234 dns.rdataclass.IN,
235 dns.rdatatype.A,
236 '192.0.2.1')
237 expectedResponse.answer.append(rrset)
238
0a2087eb 239 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
240 self.assertTrue(receivedResponse)
241 receivedResponse.id = expectedResponse.id
242 self.assertEquals(expectedResponse, receivedResponse)
243
0a2087eb 244 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
245 self.assertTrue(receivedResponse)
246 receivedResponse.id = expectedResponse.id
247 self.assertEquals(expectedResponse, receivedResponse)
248
249 def testSpoofAAAA(self):
250 """
617dfe22
RG
251 Advanced: Spoof AAAA
252
ec5f5c6b
RG
253 Send an AAAA query to "spoof.tests.powerdns.com.",
254 check that dnsdist sends a spoofed result.
255 """
256 name = 'spoof.tests.powerdns.com.'
257 query = dns.message.make_query(name, 'AAAA', 'IN')
258 # dnsdist set RA = RD for spoofed responses
259 query.flags &= ~dns.flags.RD
260 expectedResponse = dns.message.make_response(query)
261 rrset = dns.rrset.from_text(name,
262 60,
263 dns.rdataclass.IN,
264 dns.rdatatype.AAAA,
265 '2001:DB8::1')
266 expectedResponse.answer.append(rrset)
267
0a2087eb 268 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
269 self.assertTrue(receivedResponse)
270 receivedResponse.id = expectedResponse.id
271 self.assertEquals(expectedResponse, receivedResponse)
272
0a2087eb 273 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
274 self.assertTrue(receivedResponse)
275 receivedResponse.id = expectedResponse.id
276 self.assertEquals(expectedResponse, receivedResponse)
277
87c605c4
RG
278 def testSpoofCNAME(self):
279 """
617dfe22
RG
280 Advanced: Spoof CNAME
281
87c605c4
RG
282 Send an A query for "cnamespoof.tests.powerdns.com.",
283 check that dnsdist sends a spoofed result.
284 """
285 name = 'cnamespoof.tests.powerdns.com.'
286 query = dns.message.make_query(name, 'A', 'IN')
287 # dnsdist set RA = RD for spoofed responses
288 query.flags &= ~dns.flags.RD
289 expectedResponse = dns.message.make_response(query)
290 rrset = dns.rrset.from_text(name,
291 60,
292 dns.rdataclass.IN,
293 dns.rdatatype.CNAME,
294 'cname.tests.powerdns.com.')
295 expectedResponse.answer.append(rrset)
296
0a2087eb 297 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
87c605c4
RG
298 self.assertTrue(receivedResponse)
299 receivedResponse.id = expectedResponse.id
300 self.assertEquals(expectedResponse, receivedResponse)
301
0a2087eb 302 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
87c605c4
RG
303 self.assertTrue(receivedResponse)
304 receivedResponse.id = expectedResponse.id
305 self.assertEquals(expectedResponse, receivedResponse)
ec5f5c6b
RG
306
307class TestAdvancedPoolRouting(DNSDistTest):
308
ec5f5c6b
RG
309 _config_template = """
310 newServer{address="127.0.0.1:%s", pool="real"}
311 addPoolRule("pool.tests.powerdns.com", "real")
312 """
313
ec5f5c6b
RG
314 def testPolicyPool(self):
315 """
617dfe22
RG
316 Advanced: Set pool by qname
317
ec5f5c6b
RG
318 Send an A query to "pool.tests.powerdns.com.",
319 check that dnsdist routes the query to the "real" pool.
320 """
321 name = 'pool.tests.powerdns.com.'
322 query = dns.message.make_query(name, 'A', 'IN')
323 response = dns.message.make_response(query)
324 rrset = dns.rrset.from_text(name,
325 60,
326 dns.rdataclass.IN,
327 dns.rdatatype.A,
328 '192.0.2.1')
329 response.answer.append(rrset)
330
331 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
332 receivedQuery.id = query.id
333 receivedResponse.id = response.id
334 self.assertEquals(query, receivedQuery)
335 self.assertEquals(response, receivedResponse)
336
337 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
338 receivedQuery.id = query.id
339 receivedResponse.id = response.id
340 self.assertEquals(query, receivedQuery)
341 self.assertEquals(response, receivedResponse)
342
343 def testDefaultPool(self):
344 """
617dfe22
RG
345 Advanced: Set pool by qname canary
346
ec5f5c6b
RG
347 Send an A query to "notpool.tests.powerdns.com.",
348 check that dnsdist sends no response (no servers
349 in the default pool).
350 """
351 name = 'notpool.tests.powerdns.com.'
352 query = dns.message.make_query(name, 'A', 'IN')
353
0a2087eb 354 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
355 self.assertEquals(receivedResponse, None)
356
0a2087eb 357 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
358 self.assertEquals(receivedResponse, None)
359
360class TestAdvancedRoundRobinLB(DNSDistTest):
361
ec5f5c6b 362 _testServer2Port = 5351
18a0e7c6 363 _config_params = ['_testServerPort', '_testServer2Port']
ec5f5c6b
RG
364 _config_template = """
365 setServerPolicy(roundrobin)
366 s1 = newServer{address="127.0.0.1:%s"}
367 s1:setUp()
368 s2 = newServer{address="127.0.0.1:%s"}
369 s2:setUp()
370 """
371
ec5f5c6b
RG
372 @classmethod
373 def startResponders(cls):
374 print("Launching responders..")
375 cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort])
376 cls._UDPResponder.setDaemon(True)
377 cls._UDPResponder.start()
378 cls._UDPResponder2 = threading.Thread(name='UDP Responder 2', target=cls.UDPResponder, args=[cls._testServer2Port])
379 cls._UDPResponder2.setDaemon(True)
380 cls._UDPResponder2.start()
381
382 cls._TCPResponder = threading.Thread(name='TCP Responder', target=cls.TCPResponder, args=[cls._testServerPort])
383 cls._TCPResponder.setDaemon(True)
384 cls._TCPResponder.start()
385
386 cls._TCPResponder2 = threading.Thread(name='TCP Responder 2', target=cls.TCPResponder, args=[cls._testServer2Port])
387 cls._TCPResponder2.setDaemon(True)
388 cls._TCPResponder2.start()
389
390 def testRR(self):
391 """
617dfe22
RG
392 Advanced: Round Robin
393
ec5f5c6b
RG
394 Send 100 A queries to "rr.tests.powerdns.com.",
395 check that dnsdist routes half of it to each backend.
396 """
397 numberOfQueries = 10
398 name = 'rr.tests.powerdns.com.'
399 query = dns.message.make_query(name, 'A', 'IN')
400 response = dns.message.make_response(query)
401 rrset = dns.rrset.from_text(name,
402 60,
403 dns.rdataclass.IN,
404 dns.rdatatype.A,
405 '192.0.2.1')
406 response.answer.append(rrset)
407
ec5f5c6b
RG
408 # the round robin counter is shared for UDP and TCP,
409 # so we need to do UDP then TCP to have a clean count
410 for idx in range(numberOfQueries):
411 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
412 receivedQuery.id = query.id
413 receivedResponse.id = response.id
414 self.assertEquals(query, receivedQuery)
415 self.assertEquals(response, receivedResponse)
416
417 for idx in range(numberOfQueries):
418 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
419 receivedQuery.id = query.id
420 receivedResponse.id = response.id
421 self.assertEquals(query, receivedQuery)
422 self.assertEquals(response, receivedResponse)
423
424 for key in TestAdvancedRoundRobinLB._responsesCounter:
425 value = TestAdvancedRoundRobinLB._responsesCounter[key]
426 self.assertEquals(value, numberOfQueries / 2)
427
428class TestAdvancedRoundRobinLBOneDown(DNSDistTest):
429
ec5f5c6b 430 _testServer2Port = 5351
18a0e7c6 431 _config_params = ['_testServerPort', '_testServer2Port']
ec5f5c6b
RG
432 _config_template = """
433 setServerPolicy(roundrobin)
434 s1 = newServer{address="127.0.0.1:%s"}
435 s1:setUp()
436 s2 = newServer{address="127.0.0.1:%s"}
437 s2:setDown()
438 """
439
ec5f5c6b
RG
440 def testRRWithOneDown(self):
441 """
617dfe22
RG
442 Advanced: Round Robin with one server down
443
ec5f5c6b
RG
444 Send 100 A queries to "rr.tests.powerdns.com.",
445 check that dnsdist routes all of it to the only backend up.
446 """
447 numberOfQueries = 10
448 name = 'rr.tests.powerdns.com.'
449 query = dns.message.make_query(name, 'A', 'IN')
450 response = dns.message.make_response(query)
451 rrset = dns.rrset.from_text(name,
452 60,
453 dns.rdataclass.IN,
454 dns.rdatatype.A,
455 '192.0.2.1')
456 response.answer.append(rrset)
457
458 # the round robin counter is shared for UDP and TCP,
459 # so we need to do UDP then TCP to have a clean count
460 for idx in range(numberOfQueries):
461 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
462 receivedQuery.id = query.id
463 receivedResponse.id = response.id
464 self.assertEquals(query, receivedQuery)
465 self.assertEquals(response, receivedResponse)
466
467 for idx in range(numberOfQueries):
468 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
469 receivedQuery.id = query.id
470 receivedResponse.id = response.id
471 self.assertEquals(query, receivedQuery)
472 self.assertEquals(response, receivedResponse)
473
ec5f5c6b
RG
474 total = 0
475 for key in TestAdvancedRoundRobinLB._responsesCounter:
476 value = TestAdvancedRoundRobinLB._responsesCounter[key]
477 self.assertTrue(value == numberOfQueries or value == 0)
478 total += value
479
480 self.assertEquals(total, numberOfQueries * 2)
481
482class TestAdvancedACL(DNSDistTest):
483
ec5f5c6b
RG
484 _config_template = """
485 newServer{address="127.0.0.1:%s"}
486 """
18a0e7c6 487 _acl = ['192.0.2.1/32']
ec5f5c6b
RG
488
489 def testACLBlocked(self):
490 """
617dfe22
RG
491 Advanced: ACL blocked
492
ec5f5c6b
RG
493 Send an A query to "tests.powerdns.com.",
494 we expect no response since 127.0.0.1 is not on the
495 ACL.
496 """
497 name = 'tests.powerdns.com.'
498 query = dns.message.make_query(name, 'A', 'IN')
499
0a2087eb 500 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
501 self.assertEquals(receivedResponse, None)
502
0a2087eb 503 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
ec5f5c6b
RG
504 self.assertEquals(receivedResponse, None)
505
506class TestAdvancedDelay(DNSDistTest):
507
ec5f5c6b
RG
508 _config_template = """
509 addAction(AllRule(), DelayAction(1000))
510 newServer{address="127.0.0.1:%s"}
511 """
512
ec5f5c6b
RG
513 def testDelayed(self):
514 """
617dfe22
RG
515 Advanced: Delayed
516
ec5f5c6b
RG
517 Send an A query to "tests.powerdns.com.",
518 check that the response delay is longer than 1000 ms
519 over UDP, less than that over TCP.
520 """
521 name = 'tests.powerdns.com.'
522 query = dns.message.make_query(name, 'A', 'IN')
523 response = dns.message.make_response(query)
524 rrset = dns.rrset.from_text(name,
525 60,
526 dns.rdataclass.IN,
527 dns.rdatatype.A,
528 '192.0.2.1')
529 response.answer.append(rrset)
530
531 begin = datetime.now()
532 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
533 end = datetime.now()
534 receivedQuery.id = query.id
535 receivedResponse.id = response.id
536 self.assertEquals(query, receivedQuery)
537 self.assertEquals(response, receivedResponse)
538 self.assertTrue((end - begin) > timedelta(0, 1));
539
540 begin = datetime.now()
541 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
542 end = datetime.now()
543 receivedQuery.id = query.id
544 receivedResponse.id = response.id
545 self.assertEquals(query, receivedQuery)
546 self.assertEquals(response, receivedResponse)
547 self.assertTrue((end - begin) < timedelta(0, 1));