]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Advanced.py
8 from dnsdisttests
import DNSDistTest
10 class TestAdvancedFixupCase(DNSDistTest
):
12 _config_template
= """
15 newServer{address="127.0.0.1:%s"}
18 def testAdvancedFixupCase(self
):
22 Send a query with lower and upper chars,
23 make the backend return a lowercase version,
24 check that dnsdist fixes the response.
26 name
= 'fiXuPCasE.advanced.tests.powerdns.com.'
27 query
= dns
.message
.make_query(name
, 'A', 'IN')
28 lowercasequery
= dns
.message
.make_query(name
.lower(), 'A', 'IN')
29 response
= dns
.message
.make_response(lowercasequery
)
30 expectedResponse
= dns
.message
.make_response(query
)
31 rrset
= dns
.rrset
.from_text(name
,
36 response
.answer
.append(rrset
)
37 expectedResponse
.answer
.append(rrset
)
39 for method
in ("sendUDPQuery", "sendTCPQuery"):
40 sender
= getattr(self
, method
)
41 (receivedQuery
, receivedResponse
) = sender(query
, response
)
42 self
.assertTrue(receivedQuery
)
43 self
.assertTrue(receivedResponse
)
44 receivedQuery
.id = query
.id
45 self
.assertEqual(query
, receivedQuery
)
46 self
.assertEqual(expectedResponse
, receivedResponse
)
48 class TestAdvancedACL(DNSDistTest
):
50 _config_template
= """
51 newServer{address="127.0.0.1:%s"}
53 _acl
= ['192.0.2.1/32']
55 def testACLBlocked(self
):
59 Send an A query to "tests.powerdns.com.",
60 we expect no response since 127.0.0.1 is not on the
63 name
= 'tests.powerdns.com.'
64 query
= dns
.message
.make_query(name
, 'A', 'IN')
66 for method
in ("sendUDPQuery", "sendTCPQuery"):
67 sender
= getattr(self
, method
)
68 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
69 self
.assertEqual(receivedResponse
, None)
71 class TestAdvancedStringOnlyServer(DNSDistTest
):
73 _config_template
= """
74 newServer("127.0.0.1:%s")
77 def testAdvancedStringOnlyServer(self
):
79 Advanced: "string-only" server is placed in the default pool
81 name
= 'string-only-server.advanced.tests.powerdns.com.'
82 query
= dns
.message
.make_query(name
, 'A', 'IN')
83 response
= dns
.message
.make_response(query
)
84 rrset
= dns
.rrset
.from_text(name
,
89 response
.answer
.append(rrset
)
91 for method
in ("sendUDPQuery", "sendTCPQuery"):
92 sender
= getattr(self
, method
)
93 (receivedQuery
, receivedResponse
) = sender(query
, response
)
94 self
.assertTrue(receivedQuery
)
95 self
.assertTrue(receivedResponse
)
96 receivedQuery
.id = query
.id
97 self
.assertEqual(query
, receivedQuery
)
98 self
.assertEqual(response
, receivedResponse
)
100 @unittest.skipIf('SKIP_INCLUDEDIR_TESTS' in os
.environ
, 'IncludeDir tests are disabled')
101 class TestAdvancedIncludeDir(DNSDistTest
):
103 _config_template
= """
104 -- this directory contains a file allowing includedir.advanced.tests.powerdns.com.
105 includeDirectory('test-include-dir')
106 newServer{address="127.0.0.1:%s"}
109 def testAdvancedIncludeDirAllowed(self
):
111 Advanced: includeDirectory()
113 name
= 'includedir.advanced.tests.powerdns.com.'
114 query
= dns
.message
.make_query(name
, 'A', 'IN')
115 response
= dns
.message
.make_response(query
)
116 rrset
= dns
.rrset
.from_text(name
,
121 response
.answer
.append(rrset
)
123 for method
in ("sendUDPQuery", "sendTCPQuery"):
124 sender
= getattr(self
, method
)
125 (receivedQuery
, receivedResponse
) = sender(query
, response
)
126 self
.assertTrue(receivedQuery
)
127 self
.assertTrue(receivedResponse
)
128 receivedQuery
.id = query
.id
129 self
.assertEqual(query
, receivedQuery
)
130 self
.assertEqual(response
, receivedResponse
)
132 # this one should be refused
133 name
= 'notincludedir.advanced.tests.powerdns.com.'
134 query
= dns
.message
.make_query(name
, 'A', 'IN')
135 query
.flags
&= ~dns
.flags
.RD
136 expectedResponse
= dns
.message
.make_response(query
)
137 expectedResponse
.set_rcode(dns
.rcode
.REFUSED
)
139 for method
in ("sendUDPQuery", "sendTCPQuery"):
140 sender
= getattr(self
, method
)
141 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
142 self
.assertEqual(receivedResponse
, expectedResponse
)
144 class TestStatNodeRespRingSince(DNSDistTest
):
146 _consoleKey
= DNSDistTest
.generateConsoleKey()
147 _consoleKeyB64
= base64
.b64encode(_consoleKey
).decode('ascii')
148 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort']
149 _config_template
= """
151 controlSocket("127.0.0.1:%s")
152 s1 = newServer{address="127.0.0.1:%s"}
154 function visitor(node, self, childstat)
155 table.insert(nodesSeen, node.fullname)
159 def testStatNodeRespRingSince(self
):
161 Advanced: StatNodeRespRing with optional since parameter
164 name
= 'statnodesince.advanced.tests.powerdns.com.'
165 query
= dns
.message
.make_query(name
, 'A', 'IN')
166 response
= dns
.message
.make_response(query
)
167 rrset
= dns
.rrset
.from_text(name
,
172 response
.answer
.append(rrset
)
174 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
175 self
.assertTrue(receivedQuery
)
176 self
.assertTrue(receivedResponse
)
177 receivedQuery
.id = query
.id
178 self
.assertEqual(query
, receivedQuery
)
179 self
.assertEqual(response
, receivedResponse
)
181 self
.sendConsoleCommand("nodesSeen = {}")
182 self
.sendConsoleCommand("statNodeRespRing(visitor)")
183 nodes
= self
.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
184 nodes
= nodes
.strip("\n")
185 self
.assertEqual(nodes
, """statnodesince.advanced.tests.powerdns.com.
186 advanced.tests.powerdns.com.
191 self
.sendConsoleCommand("nodesSeen = {}")
192 self
.sendConsoleCommand("statNodeRespRing(visitor, 0)")
193 nodes
= self
.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
194 nodes
= nodes
.strip("\n")
195 self
.assertEqual(nodes
, """statnodesince.advanced.tests.powerdns.com.
196 advanced.tests.powerdns.com.
203 self
.sendConsoleCommand("nodesSeen = {}")
204 self
.sendConsoleCommand("statNodeRespRing(visitor)")
205 nodes
= self
.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
206 nodes
= nodes
.strip("\n")
207 self
.assertEqual(nodes
, """statnodesince.advanced.tests.powerdns.com.
208 advanced.tests.powerdns.com.
213 self
.sendConsoleCommand("nodesSeen = {}")
214 self
.sendConsoleCommand("statNodeRespRing(visitor, 5)")
215 nodes
= self
.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
216 nodes
= nodes
.strip("\n")
217 self
.assertEqual(nodes
, """""")
219 self
.sendConsoleCommand("nodesSeen = {}")
220 self
.sendConsoleCommand("statNodeRespRing(visitor, 10)")
221 nodes
= self
.sendConsoleCommand("str = '' for key,value in pairs(nodesSeen) do str = str..value..\"\\n\" end return str")
222 nodes
= nodes
.strip("\n")
223 self
.assertEqual(nodes
, """statnodesince.advanced.tests.powerdns.com.
224 advanced.tests.powerdns.com.
229 class TestAdvancedGetLocalPort(DNSDistTest
):
231 _config_template
= """
232 function answerBasedOnLocalPort(dq)
233 local port = dq.localaddr:getPort()
234 return DNSAction.Spoof, "port-was-"..port..".local-port.advanced.tests.powerdns.com."
236 addAction("local-port.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
237 newServer{address="127.0.0.1:%s"}
240 def testAdvancedGetLocalPort(self
):
242 Advanced: Return CNAME containing the local port
244 name
= 'local-port.advanced.tests.powerdns.com.'
245 query
= dns
.message
.make_query(name
, 'A', 'IN')
246 # dnsdist set RA = RD for spoofed responses
247 query
.flags
&= ~dns
.flags
.RD
249 response
= dns
.message
.make_response(query
)
250 rrset
= dns
.rrset
.from_text(name
,
254 'port-was-{}.local-port.advanced.tests.powerdns.com.'.format(self
._dnsDistPort
))
255 response
.answer
.append(rrset
)
257 for method
in ("sendUDPQuery", "sendTCPQuery"):
258 sender
= getattr(self
, method
)
259 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
260 self
.assertEqual(receivedResponse
, response
)
262 class TestAdvancedGetLocalPortOnAnyBind(DNSDistTest
):
264 _config_template
= """
265 function answerBasedOnLocalPort(dq)
266 local port = dq.localaddr:getPort()
267 return DNSAction.Spoof, "port-was-"..port..".local-port-any.advanced.tests.powerdns.com."
269 addAction("local-port-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalPort))
270 newServer{address="127.0.0.1:%d"}
272 _dnsDistListeningAddr
= '0.0.0.0'
274 def testAdvancedGetLocalPortOnAnyBind(self
):
276 Advanced: Return CNAME containing the local port for an ANY bind
278 name
= 'local-port-any.advanced.tests.powerdns.com.'
279 query
= dns
.message
.make_query(name
, 'A', 'IN')
280 # dnsdist set RA = RD for spoofed responses
281 query
.flags
&= ~dns
.flags
.RD
283 response
= dns
.message
.make_response(query
)
284 rrset
= dns
.rrset
.from_text(name
,
288 'port-was-{}.local-port-any.advanced.tests.powerdns.com.'.format(self
._dnsDistPort
))
289 response
.answer
.append(rrset
)
291 for method
in ("sendUDPQuery", "sendTCPQuery"):
292 sender
= getattr(self
, method
)
293 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
294 self
.assertEqual(receivedResponse
, response
)
296 class TestAdvancedGetLocalAddressOnAnyBind(DNSDistTest
):
298 _config_template
= """
299 function answerBasedOnLocalAddress(dq)
300 local dest = tostring(dq.localaddr)
301 local i, j = string.find(dest, "[0-9.]+")
302 local addr = string.sub(dest, i, j)
303 local dashAddr = string.gsub(addr, "[.]", "-")
304 return DNSAction.Spoof, "address-was-"..dashAddr..".local-address-any.advanced.tests.powerdns.com."
306 addAction("local-address-any.advanced.tests.powerdns.com.", LuaAction(answerBasedOnLocalAddress))
307 newServer{address="127.0.0.1:%s"}
308 addLocal('0.0.0.0:%d')
311 _config_params
= ['_testServerPort', '_dnsDistPort', '_dnsDistPort']
312 _acl
= ['127.0.0.1/32', '::1/128']
313 _skipListeningOnCL
= True
315 def testAdvancedGetLocalAddressOnAnyBind(self
):
317 Advanced: Return CNAME containing the local address for an ANY bind
319 name
= 'local-address-any.advanced.tests.powerdns.com.'
320 query
= dns
.message
.make_query(name
, 'A', 'IN')
321 # dnsdist set RA = RD for spoofed responses
322 query
.flags
&= ~dns
.flags
.RD
324 response
= dns
.message
.make_response(query
)
325 rrset
= dns
.rrset
.from_text(name
,
329 'address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.')
330 response
.answer
.append(rrset
)
332 for method
in ("sendUDPQuery", "sendTCPQuery"):
333 sender
= getattr(self
, method
)
334 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
335 self
.assertEqual(receivedResponse
, response
)
337 # now a bit more tricky, UDP-only IPv4
338 response
= dns
.message
.make_response(query
)
339 rrset
= dns
.rrset
.from_text(name
,
343 'address-was-127-0-0-2.local-address-any.advanced.tests.powerdns.com.')
344 response
.answer
.append(rrset
)
345 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
347 sock
.connect(('127.0.0.2', self
._dnsDistPort
))
349 query
= query
.to_wire()
351 (data
, remote
) = sock
.recvfrom(4096)
352 self
.assertEquals(remote
[0], '127.0.0.2')
353 except socket
.timeout
:
356 self
.assertTrue(data
)
357 receivedResponse
= dns
.message
.from_wire(data
)
358 self
.assertEqual(receivedResponse
, response
)
360 def testAdvancedCheckSourceAddrOnAnyBind(self
):
362 Advanced: Check the source address on responses for an ANY bind
364 name
= 'source-addr-any.advanced.tests.powerdns.com.'
365 query
= dns
.message
.make_query(name
, 'A', 'IN')
366 # dnsdist set RA = RD for spoofed responses
367 query
.flags
&= ~dns
.flags
.RD
369 response
= dns
.message
.make_response(query
)
370 rrset
= dns
.rrset
.from_text(name
,
375 response
.answer
.append(rrset
)
377 # a bit more tricky, UDP-only IPv4
378 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
380 sock
.connect(('127.0.0.2', self
._dnsDistPort
))
381 self
._toResponderQueue
.put(response
, True, 1.0)
383 data
= query
.to_wire()
385 (data
, remote
) = sock
.recvfrom(4096)
386 self
.assertEquals(remote
[0], '127.0.0.2')
387 except socket
.timeout
:
390 self
.assertTrue(data
)
391 receivedResponse
= dns
.message
.from_wire(data
)
392 receivedQuery
= self
._fromResponderQueue
.get(True, 1.0)
393 receivedQuery
.id = query
.id
394 self
.assertEqual(receivedQuery
, query
)
395 self
.assertEqual(receivedResponse
, response
)
397 if 'SKIP_IPV6_TESTS' in os
.environ
:
400 # a bit more tricky, UDP-only IPv6
401 sock
= socket
.socket(socket
.AF_INET6
, socket
.SOCK_DGRAM
)
403 sock
.connect(('::1', self
._dnsDistPort
))
404 self
._toResponderQueue
.put(response
, True, 1.0)
406 data
= query
.to_wire()
408 (data
, remote
) = sock
.recvfrom(4096)
409 self
.assertEquals(remote
[0], '::1')
410 except socket
.timeout
:
413 self
.assertTrue(data
)
414 receivedResponse
= dns
.message
.from_wire(data
)
415 receivedQuery
= self
._fromResponderQueue
.get(True, 1.0)
416 receivedQuery
.id = query
.id
417 self
.assertEqual(receivedQuery
, query
)
418 self
.assertEqual(receivedResponse
, response
)
420 class TestAdvancedGetLocalAddressOnNonDefaultLoopbackBind(DNSDistTest
):
421 # this one is tricky: on the loopback interface we cannot harvest the destination
422 # address, so we exercise a different code path when we bind on a different address
423 # than the default 127.0.0.1 one
424 _config_template
= """
425 newServer{address="127.0.0.1:%s"}
426 addLocal('127.0.1.19:%d')
428 _config_params
= ['_testServerPort', '_dnsDistPort']
429 _acl
= ['127.0.0.1/32']
430 _skipListeningOnCL
= True
431 _alternateListeningAddr
= '127.0.1.19'
432 _alternateListeningPort
= DNSDistTest
._dnsDistPort
434 def testAdvancedCheckSourceAddrOnNonDefaultLoopbackBind(self
):
436 Advanced: Check the source address used to reply on a non-default loopback bind
438 name
= 'source-addr-non-default-loopback.advanced.tests.powerdns.com.'
439 query
= dns
.message
.make_query(name
, 'A', 'IN')
440 response
= dns
.message
.make_response(query
)
441 rrset
= dns
.rrset
.from_text(name
,
446 response
.answer
.append(rrset
)
448 # a bit more tricky, UDP-only IPv4
449 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
451 sock
.connect(('127.0.1.19', self
._dnsDistPort
))
452 self
._toResponderQueue
.put(response
, True, 1.0)
454 data
= query
.to_wire()
456 (data
, remote
) = sock
.recvfrom(4096)
457 self
.assertEquals(remote
[0], '127.0.1.19')
458 except socket
.timeout
:
461 self
.assertTrue(data
)
462 receivedResponse
= dns
.message
.from_wire(data
)
463 receivedQuery
= self
._fromResponderQueue
.get(True, 1.0)
464 receivedQuery
.id = query
.id
465 self
.assertEqual(receivedQuery
, query
)
466 self
.assertEqual(receivedResponse
, response
)
468 class TestAdvancedAllowHeaderOnly(DNSDistTest
):
470 _config_template
= """
471 newServer{address="127.0.0.1:%s"}
472 setAllowEmptyResponse(true)
475 def testHeaderOnlyRefused(self
):
477 Advanced: Header-only refused response
479 name
= 'header-only-refused-response.advanced.tests.powerdns.com.'
480 query
= dns
.message
.make_query(name
, 'A', 'IN')
481 response
= dns
.message
.make_response(query
)
482 response
.set_rcode(dns
.rcode
.REFUSED
)
483 response
.question
= []
485 for method
in ("sendUDPQuery", "sendTCPQuery"):
486 sender
= getattr(self
, method
)
487 (receivedQuery
, receivedResponse
) = sender(query
, response
)
488 self
.assertTrue(receivedQuery
)
489 receivedQuery
.id = query
.id
490 self
.assertEqual(query
, receivedQuery
)
491 self
.assertEqual(receivedResponse
, response
)
493 def testHeaderOnlyNoErrorResponse(self
):
495 Advanced: Header-only NoError response should be allowed
497 name
= 'header-only-noerror-response.advanced.tests.powerdns.com.'
498 query
= dns
.message
.make_query(name
, 'A', 'IN')
499 response
= dns
.message
.make_response(query
)
500 response
.question
= []
502 for method
in ("sendUDPQuery", "sendTCPQuery"):
503 sender
= getattr(self
, method
)
504 (receivedQuery
, receivedResponse
) = sender(query
, response
)
505 self
.assertTrue(receivedQuery
)
506 receivedQuery
.id = query
.id
507 self
.assertEqual(query
, receivedQuery
)
508 self
.assertEqual(receivedResponse
, response
)
510 def testHeaderOnlyNXDResponse(self
):
512 Advanced: Header-only NXD response should be allowed
514 name
= 'header-only-nxd-response.advanced.tests.powerdns.com.'
515 query
= dns
.message
.make_query(name
, 'A', 'IN')
516 response
= dns
.message
.make_response(query
)
517 response
.set_rcode(dns
.rcode
.NXDOMAIN
)
518 response
.question
= []
520 for method
in ("sendUDPQuery", "sendTCPQuery"):
521 sender
= getattr(self
, method
)
522 (receivedQuery
, receivedResponse
) = sender(query
, response
)
523 self
.assertTrue(receivedQuery
)
524 receivedQuery
.id = query
.id
525 self
.assertEqual(query
, receivedQuery
)
526 self
.assertEqual(receivedResponse
, response
)
528 class TestAdvancedDropEmptyQueries(DNSDistTest
):
530 _config_template
= """
531 setDropEmptyQueries(true)
532 newServer{address="127.0.0.1:%s"}
535 def testAdvancedDropEmptyQueries(self
):
537 Advanced: Drop empty queries
539 name
= 'drop-empty-queries.advanced.tests.powerdns.com.'
540 query
= dns
.message
.Message()
542 for method
in ("sendUDPQuery", "sendTCPQuery"):
543 sender
= getattr(self
, method
)
544 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
545 self
.assertEqual(receivedResponse
, None)
547 class TestProtocols(DNSDistTest
):
548 _config_template
= """
549 function checkUDP(dq)
550 if dq:getProtocol() ~= "Do53 UDP" then
551 return DNSAction.Spoof, '1.2.3.4'
553 return DNSAction.None
556 function checkTCP(dq)
557 if dq:getProtocol() ~= "Do53 TCP" then
558 return DNSAction.Spoof, '1.2.3.4'
560 return DNSAction.None
563 addAction("udp.protocols.advanced.tests.powerdns.com.", LuaAction(checkUDP))
564 addAction("tcp.protocols.advanced.tests.powerdns.com.", LuaAction(checkTCP))
565 newServer{address="127.0.0.1:%s"}
568 def testProtocolUDP(self
):
570 Advanced: Test DNSQuestion.Protocol over UDP
572 name
= 'udp.protocols.advanced.tests.powerdns.com.'
573 query
= dns
.message
.make_query(name
, 'A', 'IN')
574 response
= dns
.message
.make_response(query
)
576 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
577 receivedQuery
.id = query
.id
578 self
.assertEqual(receivedQuery
, query
)
579 self
.assertEqual(receivedResponse
, response
)
581 def testProtocolTCP(self
):
583 Advanced: Test DNSQuestion.Protocol over TCP
585 name
= 'tcp.protocols.advanced.tests.powerdns.com.'
586 query
= dns
.message
.make_query(name
, 'A', 'IN')
587 response
= dns
.message
.make_response(query
)
589 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
590 receivedQuery
.id = query
.id
591 self
.assertEqual(receivedQuery
, query
)
592 self
.assertEqual(receivedResponse
, response
)
594 class TestCustomMetrics(DNSDistTest
):
595 _config_template
= """
596 function custommetrics(dq)
597 initialCounter = getMetric("my-custom-counter")
598 initialGauge = getMetric("my-custom-gauge")
599 incMetric("my-custom-counter")
600 incMetric("my-custom-counter", 41)
601 setMetric("my-custom-gauge", initialGauge + 1.3)
602 if getMetric("my-custom-counter") ~= (initialCounter + 42) or getMetric("my-custom-gauge") ~= (initialGauge + 1.3) then
603 return DNSAction.Spoof, '1.2.3.5'
605 return DNSAction.Spoof, '4.3.2.1'
608 function declareNewMetric(dq)
609 if declareMetric("new-runtime-metric", "counter", "Metric declaration at runtime should work fine") then
610 return DNSAction.None
612 return DNSAction.Spoof, '1.2.3.4'
615 declareMetric("my-custom-counter", "counter", "Number of tests run")
616 declareMetric("my-custom-gauge", "gauge", "Temperature of the tests")
617 addAction("declare.metric.advanced.tests.powerdns.com.", LuaAction(declareNewMetric))
618 addAction("operations.metric.advanced.tests.powerdns.com.", LuaAction(custommetrics))
619 newServer{address="127.0.0.1:%s"}
622 def testDeclareAfterConfig(self
):
624 Advanced: Test custom metric declaration after config done
626 name
= 'declare.metric.advanced.tests.powerdns.com.'
627 query
= dns
.message
.make_query(name
, 'A', 'IN')
628 response
= dns
.message
.make_response(query
)
630 for method
in ("sendUDPQuery", "sendTCPQuery"):
631 sender
= getattr(self
, method
)
632 (receivedQuery
, receivedResponse
) = sender(query
, response
)
633 receivedQuery
.id = query
.id
634 self
.assertEqual(receivedQuery
, query
)
635 self
.assertEqual(receivedResponse
, response
)
637 def testMetricOperations(self
):
639 Advanced: Test basic operations on custom metrics
641 name
= 'operations.metric.advanced.tests.powerdns.com.'
642 query
= dns
.message
.make_query(name
, 'A', 'IN')
643 # dnsdist set RA = RD for spoofed responses
644 query
.flags
&= ~dns
.flags
.RD
645 response
= dns
.message
.make_response(query
)
646 rrset
= dns
.rrset
.from_text(name
,
651 response
.answer
.append(rrset
)
653 for method
in ("sendUDPQuery", "sendTCPQuery"):
654 sender
= getattr(self
, method
)
655 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
656 self
.assertEqual(receivedResponse
, response
)
658 class TestDNSQuestionTime(DNSDistTest
):
659 _config_template
= """
660 local queryTime = nil
662 function luaquery(dq)
664 errlog('Error, the time variable is already set')
665 return DNSAction.Drop
667 queryTime = dq:getQueryTime()
668 local currentTime = getCurrentTime()
669 if queryTime.tv_sec > currentTime.tv_sec then
670 errlog('Error, query time is higher than current time')
671 return DNSAction.Drop
673 if queryTime.tv_sec == currentTime.tv_sec and queryTime.tv_nsec > currentTime.tv_nsec then
674 errlog('Error, query time NS is higher than current time')
675 return DNSAction.Drop
677 return DNSAction.None
680 function luaresponse(dr)
681 if queryTime == nil then
682 errlog('Error, the time variable is NOT set')
683 return DNSAction.Drop
685 local currentTime = getCurrentTime()
686 local queryTimeFromResponse = dr:getQueryTime()
687 if queryTime.tv_sec ~= queryTimeFromResponse.tv_sec or queryTime.tv_nsec ~= queryTimeFromResponse.tv_nsec then
688 errlog('Error, the query time in the response does NOT match the one from the query')
689 return DNSAction.Drop
691 if queryTime.tv_sec > currentTime.tv_sec then
692 errlog('Error, query time is higher than current time')
693 return DNSAction.Drop
695 if queryTime.tv_sec == currentTime.tv_sec and queryTime.tv_nsec > currentTime.tv_nsec then
696 errlog('Error, query time (NS) is higher than current time')
697 return DNSAction.Drop
701 return DNSAction.None
704 addAction(AllRule(), LuaAction(luaquery))
705 addResponseAction(AllRule(), LuaResponseAction(luaresponse))
706 newServer{address="127.0.0.1:%s"}
709 def testQueryTime(self
):
711 Advanced: Test query time
713 name
= 'query.time.advanced.tests.powerdns.com.'
714 query
= dns
.message
.make_query(name
, 'A', 'IN')
715 response
= dns
.message
.make_response(query
)
716 rrset
= dns
.rrset
.from_text(name
,
721 response
.answer
.append(rrset
)
723 for method
in ("sendUDPQuery", "sendTCPQuery"):
724 sender
= getattr(self
, method
)
725 (receivedQuery
, receivedResponse
) = sender(query
, response
)
726 receivedQuery
.id = query
.id
727 self
.assertEqual(receivedQuery
, query
)
728 self
.assertEqual(receivedResponse
, response
)
730 class TestChangeName(DNSDistTest
):
731 _config_template
= """
732 local tagName = 'initial-name'
733 function luaChangeNamequery(dq)
734 dq:setTag(tagName, dq.qname:toString())
735 if not dq:changeName(newDNSName('changeName.advanced.tests.dnsdist.org')) then
736 errlog('Error rebasing the query')
737 return DNSAction.Drop
739 return DNSAction.None
742 function luaChangeNameresponse(dr)
743 local initialName = dr:getTag(tagName)
744 if not dr:changeName(newDNSName(initialName)) then
745 errlog('Error rebasing the response')
746 return DNSAction.Drop
748 return DNSAction.None
751 addAction('changeName.advanced.tests.powerdns.com', LuaAction(luaChangeNamequery))
752 addResponseAction('changeName.advanced.tests.dnsdist.org', LuaResponseAction(luaChangeNameresponse))
753 newServer{address="127.0.0.1:%s"}
756 def testChangeName(self
):
758 Advanced: ChangeName the query name
760 name
= 'changeName.advanced.tests.powerdns.com.'
761 query
= dns
.message
.make_query(name
, 'A', 'IN')
763 changedName
= 'changeName.advanced.tests.dnsdist.org.'
764 changedQuery
= dns
.message
.make_query(changedName
, 'A', 'IN')
765 changedQuery
.id = query
.id
767 response
= dns
.message
.make_response(changedQuery
)
768 rrset
= dns
.rrset
.from_text(changedName
,
773 response
.answer
.append(rrset
)
774 rrset
= dns
.rrset
.from_text('sub.sub2.changeName.advanced.tests.dnsdist.org.',
778 'This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.')
779 response
.additional
.append(rrset
)
781 expectedResponse
= dns
.message
.make_response(query
)
782 rrset
= dns
.rrset
.from_text(name
,
787 expectedResponse
.answer
.append(rrset
)
788 # we only rewrite records if the owner name matches the new target, nothing else
789 rrset
= dns
.rrset
.from_text('sub.sub2.changeName.advanced.tests.dnsdist.org.',
793 'This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.')
794 expectedResponse
.additional
.append(rrset
)
796 for method
in ("sendUDPQuery", "sendTCPQuery"):
797 sender
= getattr(self
, method
)
798 (receivedQuery
, receivedResponse
) = sender(query
, response
)
799 receivedQuery
.id = query
.id
800 self
.assertEqual(receivedQuery
, changedQuery
)
801 self
.assertEqual(receivedResponse
, expectedResponse
)
803 class TestFlagsOnTimeout(DNSDistTest
):
805 _consoleKey
= DNSDistTest
.generateConsoleKey()
806 _consoleKeyB64
= base64
.b64encode(_consoleKey
).decode('ascii')
807 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort']
808 _config_template
= """
810 controlSocket("127.0.0.1:%s")
811 -- this server is not going to answer, resulting in a timeout
812 newServer{address="192.0.2.1:%s"}:setUp()
817 Advanced: Test that we record the correct incoming flags on a timeout
819 name
= 'timeout-flags.advanced.tests.powerdns.com.'
822 query
= dns
.message
.make_query(name
, 'A', 'IN')
824 query
.flags |
= dns
.flags
.RD
826 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
827 self
.assertFalse(receivedResponse
)
830 query
= dns
.message
.make_query(name
, 'A', 'IN')
832 query
.flags
&= ~dns
.flags
.RD
834 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
835 self
.assertFalse(receivedResponse
)
837 # make sure that the timeouts have been detected and recorded
839 content
= self
.sendConsoleCommand("grepq('')")
840 lines
= content
.splitlines()
843 # and otherwise sleep for a short while
847 self
.assertEqual(len(lines
), 5)
849 self
.assertIn('TC RD AA', lines
[0])
854 for line
in lines
[1:]:
855 self
.assertIn('DoUDP', line
)
857 queryID
= int(line
.split()[4])
858 timeouts
[queryID
] = line
860 queryID
= int(line
.split()[3])
861 queries
[queryID
] = line
863 self
.assertIn('RD', line
)
865 self
.assertNotIn('RD', line
)
867 self
.assertEqual(len(timeouts
), 2)
868 self
.assertEqual(len(queries
), 2)