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