]>
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
316 def testAdvancedGetLocalAddressOnAnyBind(self
):
318 Advanced: Return CNAME containing the local address for an ANY bind
320 name
= 'local-address-any.advanced.tests.powerdns.com.'
321 query
= dns
.message
.make_query(name
, 'A', 'IN')
322 # dnsdist set RA = RD for spoofed responses
323 query
.flags
&= ~dns
.flags
.RD
325 response
= dns
.message
.make_response(query
)
326 rrset
= dns
.rrset
.from_text(name
,
330 'address-was-127-0-0-1.local-address-any.advanced.tests.powerdns.com.')
331 response
.answer
.append(rrset
)
333 for method
in ("sendUDPQuery", "sendTCPQuery"):
334 sender
= getattr(self
, method
)
335 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
336 self
.assertEqual(receivedResponse
, response
)
338 # now a bit more tricky, UDP-only IPv4
339 response
= dns
.message
.make_response(query
)
340 rrset
= dns
.rrset
.from_text(name
,
344 'address-was-127-0-0-2.local-address-any.advanced.tests.powerdns.com.')
345 response
.answer
.append(rrset
)
346 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
348 sock
.connect(('127.0.0.2', self
._dnsDistPort
))
350 query
= query
.to_wire()
352 (data
, remote
) = sock
.recvfrom(4096)
353 self
.assertEqual(remote
[0], '127.0.0.2')
354 except socket
.timeout
:
357 self
.assertTrue(data
)
358 receivedResponse
= dns
.message
.from_wire(data
)
359 self
.assertEqual(receivedResponse
, response
)
361 def testAdvancedCheckSourceAddrOnAnyBind(self
):
363 Advanced: Check the source address on responses for an ANY bind
365 name
= 'source-addr-any.advanced.tests.powerdns.com.'
366 query
= dns
.message
.make_query(name
, 'A', 'IN')
367 # dnsdist set RA = RD for spoofed responses
368 query
.flags
&= ~dns
.flags
.RD
370 response
= dns
.message
.make_response(query
)
371 rrset
= dns
.rrset
.from_text(name
,
376 response
.answer
.append(rrset
)
378 # a bit more tricky, UDP-only IPv4
379 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
381 sock
.connect(('127.0.0.2', self
._dnsDistPort
))
382 self
._toResponderQueue
.put(response
, True, 1.0)
384 data
= query
.to_wire()
386 (data
, remote
) = sock
.recvfrom(4096)
387 self
.assertEqual(remote
[0], '127.0.0.2')
388 except socket
.timeout
:
391 self
.assertTrue(data
)
392 receivedResponse
= dns
.message
.from_wire(data
)
393 receivedQuery
= self
._fromResponderQueue
.get(True, 1.0)
394 receivedQuery
.id = query
.id
395 self
.assertEqual(receivedQuery
, query
)
396 self
.assertEqual(receivedResponse
, response
)
398 if 'SKIP_IPV6_TESTS' in os
.environ
:
401 # a bit more tricky, UDP-only IPv6
402 sock
= socket
.socket(socket
.AF_INET6
, socket
.SOCK_DGRAM
)
404 sock
.connect(('::1', self
._dnsDistPort
))
405 self
._toResponderQueue
.put(response
, True, 1.0)
407 data
= query
.to_wire()
409 (data
, remote
) = sock
.recvfrom(4096)
410 self
.assertEqual(remote
[0], '::1')
411 except socket
.timeout
:
414 self
.assertTrue(data
)
415 receivedResponse
= dns
.message
.from_wire(data
)
416 receivedQuery
= self
._fromResponderQueue
.get(True, 1.0)
417 receivedQuery
.id = query
.id
418 self
.assertEqual(receivedQuery
, query
)
419 self
.assertEqual(receivedResponse
, response
)
421 class TestAdvancedGetLocalAddressOnNonDefaultLoopbackBind(DNSDistTest
):
422 # this one is tricky: on the loopback interface we cannot harvest the destination
423 # address, so we exercise a different code path when we bind on a different address
424 # than the default 127.0.0.1 one
425 _config_template
= """
426 newServer{address="127.0.0.1:%s"}
427 addLocal('127.0.1.19:%d')
429 _config_params
= ['_testServerPort', '_dnsDistPort']
430 _acl
= ['127.0.0.1/32']
431 _skipListeningOnCL
= True
432 _alternateListeningAddr
= '127.0.1.19'
433 _alternateListeningPort
= DNSDistTest
._dnsDistPort
435 def testAdvancedCheckSourceAddrOnNonDefaultLoopbackBind(self
):
437 Advanced: Check the source address used to reply on a non-default loopback bind
439 name
= 'source-addr-non-default-loopback.advanced.tests.powerdns.com.'
440 query
= dns
.message
.make_query(name
, 'A', 'IN')
441 response
= dns
.message
.make_response(query
)
442 rrset
= dns
.rrset
.from_text(name
,
447 response
.answer
.append(rrset
)
449 # a bit more tricky, UDP-only IPv4
450 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
452 sock
.connect(('127.0.1.19', self
._dnsDistPort
))
453 self
._toResponderQueue
.put(response
, True, 1.0)
455 data
= query
.to_wire()
457 (data
, remote
) = sock
.recvfrom(4096)
458 self
.assertEqual(remote
[0], '127.0.1.19')
459 except socket
.timeout
:
462 self
.assertTrue(data
)
463 receivedResponse
= dns
.message
.from_wire(data
)
464 receivedQuery
= self
._fromResponderQueue
.get(True, 1.0)
465 receivedQuery
.id = query
.id
466 self
.assertEqual(receivedQuery
, query
)
467 self
.assertEqual(receivedResponse
, response
)
469 class TestAdvancedAllowHeaderOnly(DNSDistTest
):
471 _config_template
= """
472 newServer{address="127.0.0.1:%s"}
473 setAllowEmptyResponse(true)
476 def testHeaderOnlyRefused(self
):
478 Advanced: Header-only refused response
480 name
= 'header-only-refused-response.advanced.tests.powerdns.com.'
481 query
= dns
.message
.make_query(name
, 'A', 'IN')
482 response
= dns
.message
.make_response(query
)
483 response
.set_rcode(dns
.rcode
.REFUSED
)
484 response
.question
= []
486 for method
in ("sendUDPQuery", "sendTCPQuery"):
487 sender
= getattr(self
, method
)
488 (receivedQuery
, receivedResponse
) = sender(query
, response
)
489 self
.assertTrue(receivedQuery
)
490 receivedQuery
.id = query
.id
491 self
.assertEqual(query
, receivedQuery
)
492 self
.assertEqual(receivedResponse
, response
)
494 def testHeaderOnlyNoErrorResponse(self
):
496 Advanced: Header-only NoError response should be allowed
498 name
= 'header-only-noerror-response.advanced.tests.powerdns.com.'
499 query
= dns
.message
.make_query(name
, 'A', 'IN')
500 response
= dns
.message
.make_response(query
)
501 response
.question
= []
503 for method
in ("sendUDPQuery", "sendTCPQuery"):
504 sender
= getattr(self
, method
)
505 (receivedQuery
, receivedResponse
) = sender(query
, response
)
506 self
.assertTrue(receivedQuery
)
507 receivedQuery
.id = query
.id
508 self
.assertEqual(query
, receivedQuery
)
509 self
.assertEqual(receivedResponse
, response
)
511 def testHeaderOnlyNXDResponse(self
):
513 Advanced: Header-only NXD response should be allowed
515 name
= 'header-only-nxd-response.advanced.tests.powerdns.com.'
516 query
= dns
.message
.make_query(name
, 'A', 'IN')
517 response
= dns
.message
.make_response(query
)
518 response
.set_rcode(dns
.rcode
.NXDOMAIN
)
519 response
.question
= []
521 for method
in ("sendUDPQuery", "sendTCPQuery"):
522 sender
= getattr(self
, method
)
523 (receivedQuery
, receivedResponse
) = sender(query
, response
)
524 self
.assertTrue(receivedQuery
)
525 receivedQuery
.id = query
.id
526 self
.assertEqual(query
, receivedQuery
)
527 self
.assertEqual(receivedResponse
, response
)
529 class TestAdvancedDropEmptyQueries(DNSDistTest
):
531 _config_template
= """
532 setDropEmptyQueries(true)
533 newServer{address="127.0.0.1:%s"}
536 def testAdvancedDropEmptyQueries(self
):
538 Advanced: Drop empty queries
540 name
= 'drop-empty-queries.advanced.tests.powerdns.com.'
541 query
= dns
.message
.Message()
543 for method
in ("sendUDPQuery", "sendTCPQuery"):
544 sender
= getattr(self
, method
)
545 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
546 self
.assertEqual(receivedResponse
, None)
548 class TestProtocols(DNSDistTest
):
549 _config_template
= """
550 function checkUDP(dq)
551 if dq:getProtocol() ~= "Do53 UDP" then
552 return DNSAction.Spoof, '1.2.3.4'
554 return DNSAction.None
557 function checkTCP(dq)
558 if dq:getProtocol() ~= "Do53 TCP" then
559 return DNSAction.Spoof, '1.2.3.4'
561 return DNSAction.None
564 addAction("udp.protocols.advanced.tests.powerdns.com.", LuaAction(checkUDP))
565 addAction("tcp.protocols.advanced.tests.powerdns.com.", LuaAction(checkTCP))
566 newServer{address="127.0.0.1:%s"}
569 def testProtocolUDP(self
):
571 Advanced: Test DNSQuestion.Protocol over UDP
573 name
= 'udp.protocols.advanced.tests.powerdns.com.'
574 query
= dns
.message
.make_query(name
, 'A', 'IN')
575 response
= dns
.message
.make_response(query
)
577 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
578 receivedQuery
.id = query
.id
579 self
.assertEqual(receivedQuery
, query
)
580 self
.assertEqual(receivedResponse
, response
)
582 def testProtocolTCP(self
):
584 Advanced: Test DNSQuestion.Protocol over TCP
586 name
= 'tcp.protocols.advanced.tests.powerdns.com.'
587 query
= dns
.message
.make_query(name
, 'A', 'IN')
588 response
= dns
.message
.make_response(query
)
590 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
591 receivedQuery
.id = query
.id
592 self
.assertEqual(receivedQuery
, query
)
593 self
.assertEqual(receivedResponse
, response
)
595 class TestCustomMetrics(DNSDistTest
):
596 _config_template
= """
597 function custommetrics(dq)
598 initialCounter = getMetric("my-custom-counter")
599 initialGauge = getMetric("my-custom-gauge")
600 incMetric("my-custom-counter")
601 incMetric("my-custom-counter", 41)
602 setMetric("my-custom-gauge", initialGauge + 1.3)
603 if getMetric("my-custom-counter") ~= (initialCounter + 42) or getMetric("my-custom-gauge") ~= (initialGauge + 1.3) then
604 return DNSAction.Spoof, '1.2.3.5'
606 return DNSAction.Spoof, '4.3.2.1'
609 function declareNewMetric(dq)
610 if declareMetric("new-runtime-metric", "counter", "Metric declaration at runtime should work fine") then
611 return DNSAction.None
613 return DNSAction.Spoof, '1.2.3.4'
616 declareMetric("my-custom-counter", "counter", "Number of tests run")
617 declareMetric("my-custom-gauge", "gauge", "Temperature of the tests")
618 addAction("declare.metric.advanced.tests.powerdns.com.", LuaAction(declareNewMetric))
619 addAction("operations.metric.advanced.tests.powerdns.com.", LuaAction(custommetrics))
620 newServer{address="127.0.0.1:%s"}
623 def testDeclareAfterConfig(self
):
625 Advanced: Test custom metric declaration after config done
627 name
= 'declare.metric.advanced.tests.powerdns.com.'
628 query
= dns
.message
.make_query(name
, 'A', 'IN')
629 response
= dns
.message
.make_response(query
)
631 for method
in ("sendUDPQuery", "sendTCPQuery"):
632 sender
= getattr(self
, method
)
633 (receivedQuery
, receivedResponse
) = sender(query
, response
)
634 receivedQuery
.id = query
.id
635 self
.assertEqual(receivedQuery
, query
)
636 self
.assertEqual(receivedResponse
, response
)
638 def testMetricOperations(self
):
640 Advanced: Test basic operations on custom metrics
642 name
= 'operations.metric.advanced.tests.powerdns.com.'
643 query
= dns
.message
.make_query(name
, 'A', 'IN')
644 # dnsdist set RA = RD for spoofed responses
645 query
.flags
&= ~dns
.flags
.RD
646 response
= dns
.message
.make_response(query
)
647 rrset
= dns
.rrset
.from_text(name
,
652 response
.answer
.append(rrset
)
654 for method
in ("sendUDPQuery", "sendTCPQuery"):
655 sender
= getattr(self
, method
)
656 (_
, receivedResponse
) = sender(query
, response
=None, useQueue
=False)
657 self
.assertEqual(receivedResponse
, response
)
659 class TestDNSQuestionTime(DNSDistTest
):
660 _config_template
= """
661 local queryTime = nil
663 function luaquery(dq)
665 errlog('Error, the time variable is already set')
666 return DNSAction.Drop
668 queryTime = dq:getQueryTime()
669 local currentTime = getCurrentTime()
670 if queryTime.tv_sec > currentTime.tv_sec then
671 errlog('Error, query time is higher than current time')
672 return DNSAction.Drop
674 if queryTime.tv_sec == currentTime.tv_sec and queryTime.tv_nsec > currentTime.tv_nsec then
675 errlog('Error, query time NS is higher than current time')
676 return DNSAction.Drop
678 return DNSAction.None
681 function luaresponse(dr)
682 if queryTime == nil then
683 errlog('Error, the time variable is NOT set')
684 return DNSAction.Drop
686 local currentTime = getCurrentTime()
687 local queryTimeFromResponse = dr:getQueryTime()
688 if queryTime.tv_sec ~= queryTimeFromResponse.tv_sec or queryTime.tv_nsec ~= queryTimeFromResponse.tv_nsec then
689 errlog('Error, the query time in the response does NOT match the one from the query')
690 return DNSAction.Drop
692 if queryTime.tv_sec > currentTime.tv_sec then
693 errlog('Error, query time is higher than current time')
694 return DNSAction.Drop
696 if queryTime.tv_sec == currentTime.tv_sec and queryTime.tv_nsec > currentTime.tv_nsec then
697 errlog('Error, query time (NS) is higher than current time')
698 return DNSAction.Drop
702 return DNSAction.None
705 addAction(AllRule(), LuaAction(luaquery))
706 addResponseAction(AllRule(), LuaResponseAction(luaresponse))
707 newServer{address="127.0.0.1:%s"}
710 def testQueryTime(self
):
712 Advanced: Test query time
714 name
= 'query.time.advanced.tests.powerdns.com.'
715 query
= dns
.message
.make_query(name
, 'A', 'IN')
716 response
= dns
.message
.make_response(query
)
717 rrset
= dns
.rrset
.from_text(name
,
722 response
.answer
.append(rrset
)
724 for method
in ("sendUDPQuery", "sendTCPQuery"):
725 sender
= getattr(self
, method
)
726 (receivedQuery
, receivedResponse
) = sender(query
, response
)
727 receivedQuery
.id = query
.id
728 self
.assertEqual(receivedQuery
, query
)
729 self
.assertEqual(receivedResponse
, response
)
731 class TestChangeName(DNSDistTest
):
732 _config_template
= """
733 local tagName = 'initial-name'
734 function luaChangeNamequery(dq)
735 dq:setTag(tagName, dq.qname:toString())
736 if not dq:changeName(newDNSName('changeName.advanced.tests.dnsdist.org')) then
737 errlog('Error rebasing the query')
738 return DNSAction.Drop
740 return DNSAction.None
743 function luaChangeNameresponse(dr)
744 local initialName = dr:getTag(tagName)
745 if not dr:changeName(newDNSName(initialName)) then
746 errlog('Error rebasing the response')
747 return DNSAction.Drop
749 return DNSAction.None
752 addAction('changeName.advanced.tests.powerdns.com', LuaAction(luaChangeNamequery))
753 addResponseAction('changeName.advanced.tests.dnsdist.org', LuaResponseAction(luaChangeNameresponse))
754 newServer{address="127.0.0.1:%s"}
757 def testChangeName(self
):
759 Advanced: ChangeName the query name
761 name
= 'changeName.advanced.tests.powerdns.com.'
762 query
= dns
.message
.make_query(name
, 'A', 'IN')
764 changedName
= 'changeName.advanced.tests.dnsdist.org.'
765 changedQuery
= dns
.message
.make_query(changedName
, 'A', 'IN')
766 changedQuery
.id = query
.id
768 response
= dns
.message
.make_response(changedQuery
)
769 rrset
= dns
.rrset
.from_text(changedName
,
774 response
.answer
.append(rrset
)
775 rrset
= dns
.rrset
.from_text('sub.sub2.changeName.advanced.tests.dnsdist.org.',
779 'This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.')
780 response
.additional
.append(rrset
)
782 expectedResponse
= dns
.message
.make_response(query
)
783 rrset
= dns
.rrset
.from_text(name
,
788 expectedResponse
.answer
.append(rrset
)
789 # we only rewrite records if the owner name matches the new target, nothing else
790 rrset
= dns
.rrset
.from_text('sub.sub2.changeName.advanced.tests.dnsdist.org.',
794 'This text contains sub.sub2.changeName.advanced.tests.dnsdist.org.')
795 expectedResponse
.additional
.append(rrset
)
797 for method
in ("sendUDPQuery", "sendTCPQuery"):
798 sender
= getattr(self
, method
)
799 (receivedQuery
, receivedResponse
) = sender(query
, response
)
800 receivedQuery
.id = query
.id
801 self
.assertEqual(receivedQuery
, changedQuery
)
802 self
.assertEqual(receivedResponse
, expectedResponse
)
804 class TestFlagsOnTimeout(DNSDistTest
):
806 _consoleKey
= DNSDistTest
.generateConsoleKey()
807 _consoleKeyB64
= base64
.b64encode(_consoleKey
).decode('ascii')
808 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort']
809 _config_template
= """
811 controlSocket("127.0.0.1:%s")
812 -- this server is not going to answer, resulting in a timeout
813 newServer{address="192.0.2.1:%s"}:setUp()
818 Advanced: Test that we record the correct incoming flags on a timeout
820 name
= 'timeout-flags.advanced.tests.powerdns.com.'
823 query
= dns
.message
.make_query(name
, 'A', 'IN')
825 query
.flags |
= dns
.flags
.RD
827 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
828 self
.assertFalse(receivedResponse
)
831 query
= dns
.message
.make_query(name
, 'A', 'IN')
833 query
.flags
&= ~dns
.flags
.RD
835 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
836 self
.assertFalse(receivedResponse
)
838 # make sure that the timeouts have been detected and recorded
840 content
= self
.sendConsoleCommand("grepq('')")
841 lines
= content
.splitlines()
844 # and otherwise sleep for a short while
848 self
.assertEqual(len(lines
), 5)
850 self
.assertIn('TC RD AA', lines
[0])
855 for line
in lines
[1:]:
856 self
.assertIn('DoUDP', line
)
858 queryID
= int(line
.split()[4])
859 timeouts
[queryID
] = line
861 queryID
= int(line
.split()[3])
862 queries
[queryID
] = line
864 self
.assertIn('RD', line
)
866 self
.assertNotIn('RD', line
)
868 self
.assertEqual(len(timeouts
), 2)
869 self
.assertEqual(len(queries
), 2)
871 class TestTruncatedUDPLargeAnswers(DNSDistTest
):
872 _config_template
= """
873 newServer{address="127.0.0.1:%d"}
875 def testVeryLargeAnswer(self
):
877 Advanced: Check that UDP responses that are too large for our buffer are dismissed
879 name
= 'very-large-answer-dismissed.advanced.tests.powerdns.com.'
880 query
= dns
.message
.make_query(name
, 'TXT', 'IN')
881 response
= dns
.message
.make_response(query
)
882 # we prepare a large answer
886 content
= content
+ ' '
887 content
= content
+ 'A' * 255
889 content
= content
+ ' ' + 'B' * 170
891 rrset
= dns
.rrset
.from_text(name
,
896 response
.answer
.append(rrset
)
897 self
.assertEqual(len(response
.to_wire()), 8192)
900 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
901 self
.assertTrue(receivedQuery
)
902 self
.assertTrue(receivedResponse
)
903 receivedQuery
.id = query
.id
904 self
.assertEqual(query
, receivedQuery
)
905 self
.assertEqual(receivedResponse
, response
)
907 # UDP should never get an answer, because dnsdist will not be able to get it from the backend
908 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
909 self
.assertTrue(receivedQuery
)
910 self
.assertFalse(receivedResponse
)
911 receivedQuery
.id = query
.id
912 self
.assertEqual(query
, receivedQuery
)