]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_DynBlocks.py
6 from dnsdisttests
import DNSDistTest
7 from dnsdistDynBlockTests
import DynBlocksTest
, waitForMaintenanceToRun
, _maintenanceWaitTime
9 class TestDynBlockQPS(DynBlocksTest
):
11 _config_template
= """
12 function maintenance()
13 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d)
15 newServer{address="127.0.0.1:%s"}
16 webserver("127.0.0.1:%s")
17 setWebserverConfig({password="%s", apiKey="%s"})
19 _config_params
= ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
21 def testDynBlocksQRate(self
):
25 name
= 'qrate.dynblocks.tests.powerdns.com.'
26 self
.doTestQRate(name
)
28 class TestDynBlockQPSRefused(DynBlocksTest
):
30 _config_template
= """
31 function maintenance()
32 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d)
34 setDynBlocksAction(DNSAction.Refused)
35 newServer{address="127.0.0.1:%s"}
38 def testDynBlocksQRate(self
):
40 Dyn Blocks: QRate refused
42 name
= 'qraterefused.dynblocks.tests.powerdns.com.'
43 self
.doTestQRateRCode(name
, dns
.rcode
.REFUSED
)
45 class TestDynBlockQPSActionRefused(DynBlocksTest
):
47 _config_template
= """
48 function maintenance()
49 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Refused)
51 setDynBlocksAction(DNSAction.Drop)
52 newServer{address="127.0.0.1:%s"}
55 def testDynBlocksQRate(self
):
57 Dyn Blocks: QRate refused (action)
59 name
= 'qrateactionrefused.dynblocks.tests.powerdns.com.'
60 self
.doTestQRateRCode(name
, dns
.rcode
.REFUSED
)
62 class TestDynBlockQPSActionNXD(DynBlocksTest
):
64 _config_template
= """
65 function maintenance()
66 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Nxdomain)
68 setDynBlocksAction(DNSAction.Drop)
69 newServer{address="127.0.0.1:%s"}
72 def testDynBlocksQRate(self
):
74 Dyn Blocks: QRate NXD (action)
76 name
= 'qrateactionnxd.dynblocks.tests.powerdns.com.'
77 self
.doTestQRateRCode(name
, dns
.rcode
.NXDOMAIN
)
79 class TestDynBlockQPSActionTruncated(DNSDistTest
):
83 # this needs to be greater than maintenanceWaitTime
84 _dynBlockDuration
= _maintenanceWaitTime
+ 1
85 _config_params
= ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
86 _config_template
= """
87 function maintenance()
88 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Truncate)
90 setDynBlocksAction(DNSAction.Drop)
91 newServer{address="127.0.0.1:%s"}
94 def testDynBlocksQRate(self
):
96 Dyn Blocks: QRate truncated (action)
98 name
= 'qrateactiontruncated.dynblocks.tests.powerdns.com.'
99 query
= dns
.message
.make_query(name
, 'A', 'IN')
100 # dnsdist sets RA = RD for TC responses
101 query
.flags
&= ~dns
.flags
.RD
102 response
= dns
.message
.make_response(query
)
103 rrset
= dns
.rrset
.from_text(name
,
108 response
.answer
.append(rrset
)
109 truncatedResponse
= dns
.message
.make_response(query
)
110 truncatedResponse
.flags |
= dns
.flags
.TC
114 for _
in range((self
._dynBlockQPS
* self
._dynBlockPeriod
) + 1):
115 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
118 receivedQuery
.id = query
.id
119 self
.assertEqual(query
, receivedQuery
)
120 self
.assertEqual(receivedResponse
, response
)
121 allowed
= allowed
+ 1
123 self
.assertEqual(receivedResponse
, truncatedResponse
)
124 # the query has not reached the responder,
125 # let's clear the response queue
126 self
.clearToResponderQueue()
128 # we might be already truncated, but we should have been able to send
129 # at least self._dynBlockQPS queries
130 self
.assertGreaterEqual(allowed
, self
._dynBlockQPS
)
133 waitForMaintenanceToRun()
135 # we should now be 'truncated' for up to self._dynBlockDuration + self._dynBlockPeriod
136 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
137 self
.assertEqual(receivedResponse
, truncatedResponse
)
139 # check over TCP, which should not be truncated
140 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
142 receivedQuery
.id = query
.id
143 self
.assertEqual(query
, receivedQuery
)
144 self
.assertEqual(receivedResponse
, response
)
146 # wait until we are not blocked anymore
147 time
.sleep(self
._dynBlockDuration
+ self
._dynBlockPeriod
)
149 # this one should succeed
150 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
151 receivedQuery
.id = query
.id
152 self
.assertEqual(query
, receivedQuery
)
153 self
.assertEqual(response
, receivedResponse
)
157 # again, over TCP this time, we should never get truncated!
158 for _
in range((self
._dynBlockQPS
* self
._dynBlockPeriod
) + 1):
159 (receivedQuery
, receivedResponse
) = self
.sendTCPQuery(query
, response
)
161 receivedQuery
.id = query
.id
162 self
.assertEqual(query
, receivedQuery
)
163 self
.assertEqual(receivedResponse
, response
)
164 receivedQuery
.id = query
.id
165 allowed
= allowed
+ 1
167 self
.assertEqual(allowed
, sent
)
169 class TestDynBlockAllowlist(DynBlocksTest
):
171 _config_template
= """
173 function maintenance()
174 toBlock = exceedQRate(%d, %d)
175 for addr, count in pairs(toBlock) do
176 if tostring(addr) == "127.0.0.1" then
181 addDynBlocks(toBlock, "Exceeded query rate", %d)
184 function spoofrule(dq)
187 return DNSAction.Spoof, "192.0.2.42"
189 return DNSAction.None, ""
192 addAction("allowlisted-test.dynblocks.tests.powerdns.com.", LuaAction(spoofrule))
194 newServer{address="127.0.0.1:%s"}
197 def testAllowlisted(self
):
199 Dyn Blocks: Allowlisted from the dynamic blocks
201 name
= 'allowlisted.dynblocks.tests.powerdns.com.'
202 query
= dns
.message
.make_query(name
, 'A', 'IN')
203 response
= dns
.message
.make_response(query
)
204 rrset
= dns
.rrset
.from_text(name
,
209 response
.answer
.append(rrset
)
213 for _
in range((self
._dynBlockQPS
* self
._dynBlockPeriod
) + 1):
214 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
217 receivedQuery
.id = query
.id
218 self
.assertEqual(query
, receivedQuery
)
219 self
.assertEqual(response
, receivedResponse
)
220 allowed
= allowed
+ 1
222 # the query has not reached the responder,
223 # let's clear the response queue
224 self
.clearToResponderQueue()
226 # we should not have been blocked
227 self
.assertEqual(allowed
, sent
)
229 waitForMaintenanceToRun()
231 # we should still not be blocked
232 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
233 receivedQuery
.id = query
.id
234 self
.assertEqual(query
, receivedQuery
)
235 self
.assertEqual(receivedResponse
, receivedResponse
)
237 # check that we would have been blocked without the allowlisting
238 name
= 'allowlisted-test.dynblocks.tests.powerdns.com.'
239 query
= dns
.message
.make_query(name
, 'A', 'IN')
240 # dnsdist set RA = RD for spoofed responses
241 query
.flags
&= ~dns
.flags
.RD
242 expectedResponse
= dns
.message
.make_response(query
)
243 rrset
= dns
.rrset
.from_text(name
,
248 expectedResponse
.answer
.append(rrset
)
249 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
250 self
.assertEqual(receivedResponse
, expectedResponse
)