]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_DynBlocksGroup.py
6 from dnsdisttests
import DNSDistTest
7 from dnsdistDynBlockTests
import DynBlocksTest
, waitForMaintenanceToRun
, _maintenanceWaitTime
9 class TestDynBlockGroupQPS(DynBlocksTest
):
11 _config_template
= """
12 local dbr = dynBlockRulesGroup()
13 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
15 function maintenance()
18 newServer{address="127.0.0.1:%s"}
19 webserver("127.0.0.1:%s")
20 setWebserverConfig({password="%s", apiKey="%s"})
22 _config_params
= ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
24 def testDynBlocksQRate(self
):
26 Dyn Blocks (Group): QRate
28 name
= 'qrate.group.dynblocks.tests.powerdns.com.'
29 self
.doTestQRate(name
)
31 class TestDynBlockGroupQPSRefused(DynBlocksTest
):
33 _config_template
= """
34 local dbr = dynBlockRulesGroup()
35 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
37 function maintenance()
40 setDynBlocksAction(DNSAction.Refused)
41 newServer{address="127.0.0.1:%s"}
44 def testDynBlocksQRate(self
):
46 Dyn Blocks (Group): QRate refused
48 name
= 'qraterefused.group.dynblocks.tests.powerdns.com.'
49 self
.doTestQRateRCode(name
, dns
.rcode
.REFUSED
)
51 class TestDynBlockGroupQPSActionRefused(DynBlocksTest
):
53 _config_template
= """
54 local dbr = dynBlockRulesGroup()
55 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.Refused)
57 function maintenance()
60 setDynBlocksAction(DNSAction.Drop)
61 newServer{address="127.0.0.1:%s"}
64 def testDynBlocksQRate(self
):
66 Dyn Blocks (group): QRate refused (action)
68 name
= 'qrateactionrefused.group.dynblocks.tests.powerdns.com.'
69 self
.doTestQRateRCode(name
, dns
.rcode
.REFUSED
)
71 class TestDynBlockGroupExcluded(DynBlocksTest
):
73 _config_template
= """
74 local dbr = dynBlockRulesGroup()
75 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
76 dbr:excludeRange("127.0.0.1/32")
78 function maintenance()
82 newServer{address="127.0.0.1:%s"}
85 def testExcluded(self
):
87 Dyn Blocks (group) : Excluded from the dynamic block rules
89 name
= 'excluded.group.dynblocks.tests.powerdns.com.'
90 query
= dns
.message
.make_query(name
, 'A', 'IN')
91 response
= dns
.message
.make_response(query
)
92 rrset
= dns
.rrset
.from_text(name
,
97 response
.answer
.append(rrset
)
101 for _
in range((self
._dynBlockQPS
* self
._dynBlockPeriod
) + 1):
102 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
105 receivedQuery
.id = query
.id
106 self
.assertEqual(query
, receivedQuery
)
107 self
.assertEqual(response
, receivedResponse
)
108 allowed
= allowed
+ 1
110 # the query has not reached the responder,
111 # let's clear the response queue
112 self
.clearToResponderQueue()
114 # we should not have been blocked
115 self
.assertEqual(allowed
, sent
)
117 waitForMaintenanceToRun()
119 # we should still not be blocked
120 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
121 receivedQuery
.id = query
.id
122 self
.assertEqual(query
, receivedQuery
)
123 self
.assertEqual(receivedResponse
, receivedResponse
)
125 class TestDynBlockGroupExcludedViaNMG(DynBlocksTest
):
127 _config_template
= """
129 nmg:addMask("127.0.0.1/32")
131 local dbr = dynBlockRulesGroup()
132 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
133 dbr:excludeRange(nmg)
135 function maintenance()
139 newServer{address="127.0.0.1:%s"}
142 def testExcluded(self
):
144 Dyn Blocks (group) : Excluded (via NMG) from the dynamic block rules
146 name
= 'excluded-nmg.group.dynblocks.tests.powerdns.com.'
147 query
= dns
.message
.make_query(name
, 'A', 'IN')
148 response
= dns
.message
.make_response(query
)
149 rrset
= dns
.rrset
.from_text(name
,
154 response
.answer
.append(rrset
)
158 for _
in range((self
._dynBlockQPS
* self
._dynBlockPeriod
) + 1):
159 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
162 receivedQuery
.id = query
.id
163 self
.assertEqual(query
, receivedQuery
)
164 self
.assertEqual(response
, receivedResponse
)
165 allowed
= allowed
+ 1
167 # the query has not reached the responder,
168 # let's clear the response queue
169 self
.clearToResponderQueue()
171 # we should not have been blocked
172 self
.assertEqual(allowed
, sent
)
174 waitForMaintenanceToRun()
176 # we should still not be blocked
177 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
178 receivedQuery
.id = query
.id
179 self
.assertEqual(query
, receivedQuery
)
180 self
.assertEqual(receivedResponse
, receivedResponse
)
182 class TestDynBlockGroupNoOp(DynBlocksTest
):
184 _config_template
= """
185 local dbr = dynBlockRulesGroup()
186 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.NoOp)
188 function maintenance()
192 newServer{address="127.0.0.1:%s"}
193 webserver("127.0.0.1:%s")
194 setWebserverConfig({password="%s", apiKey="%s"})
196 _config_params
= ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
200 Dyn Blocks (group) : NoOp
202 name
= 'noop.group.dynblocks.tests.powerdns.com.'
203 query
= dns
.message
.make_query(name
, 'A', 'IN')
204 response
= dns
.message
.make_response(query
)
205 rrset
= dns
.rrset
.from_text(name
,
210 response
.answer
.append(rrset
)
214 for _
in range((self
._dynBlockQPS
* self
._dynBlockPeriod
) + 1):
215 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
218 receivedQuery
.id = query
.id
219 self
.assertEqual(query
, receivedQuery
)
220 self
.assertEqual(response
, receivedResponse
)
221 allowed
= allowed
+ 1
223 # the query has not reached the responder,
224 # let's clear the response queue
225 self
.clearToResponderQueue()
227 # a dynamic rule should have been inserted, but the queries should still go on
228 self
.assertEqual(allowed
, sent
)
230 waitForMaintenanceToRun()
232 # the rule should still be present, but the queries pass through anyway
233 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
234 receivedQuery
.id = query
.id
235 self
.assertEqual(query
, receivedQuery
)
236 self
.assertEqual(receivedResponse
, receivedResponse
)
238 # check that the rule has been inserted
239 self
.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', 1, self
._dynBlockDuration
, 0, sent
)
241 class TestDynBlockGroupWarning(DynBlocksTest
):
243 _dynBlockWarningQPS
= 5
245 _config_template
= """
246 local dbr = dynBlockRulesGroup()
247 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.Drop, %d)
249 function maintenance()
253 newServer{address="127.0.0.1:%s"}
254 webserver("127.0.0.1:%s")
255 setWebserverConfig({password="%s", apiKey="%s"})
257 _config_params
= ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_dynBlockWarningQPS', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
259 def testWarning(self
):
261 Dyn Blocks (group) : Warning
263 name
= 'warning.group.dynblocks.tests.powerdns.com.'
264 query
= dns
.message
.make_query(name
, 'A', 'IN')
265 response
= dns
.message
.make_response(query
)
266 rrset
= dns
.rrset
.from_text(name
,
271 response
.answer
.append(rrset
)
275 for _
in range((self
._dynBlockWarningQPS
* self
._dynBlockPeriod
) + 1):
276 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
279 receivedQuery
.id = query
.id
280 self
.assertEqual(query
, receivedQuery
)
281 self
.assertEqual(response
, receivedResponse
)
282 allowed
= allowed
+ 1
284 # the query has not reached the responder,
285 # let's clear the response queue
286 self
.clearToResponderQueue()
288 # a dynamic rule should have been inserted, but the queries should
289 # still go on because we are still at warning level
290 self
.assertEqual(allowed
, sent
)
292 waitForMaintenanceToRun()
294 # the rule should still be present, but the queries pass through anyway
295 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
296 receivedQuery
.id = query
.id
297 self
.assertEqual(query
, receivedQuery
)
298 self
.assertEqual(receivedResponse
, receivedResponse
)
300 # check that the rule has been inserted
301 self
.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', 1, self
._dynBlockDuration
, 0, sent
)
303 self
.doTestQRate(name
)
305 class TestDynBlockGroupPort(DNSDistTest
):
309 # this needs to be greater than maintenanceWaitTime
310 _dynBlockDuration
= _maintenanceWaitTime
+ 1
311 _config_template
= """
312 local dbr = dynBlockRulesGroup()
313 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.Drop)
314 -- take the exact port into account
315 dbr:setMasks(32, 128, 16)
317 function maintenance()
320 newServer{address="127.0.0.1:%d"}
322 _config_params
= ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
326 Dyn Blocks (group): Exact port matching
328 name
= 'port.group.dynblocks.tests.powerdns.com.'
329 query
= dns
.message
.make_query(name
, 'A', 'IN')
330 response
= dns
.message
.make_response(query
)
331 rrset
= dns
.rrset
.from_text(name
,
336 response
.answer
.append(rrset
)
340 for _
in range((self
._dynBlockQPS
* self
._dynBlockPeriod
) + 1):
341 (receivedQuery
, receivedResponse
) = self
.sendUDPQuery(query
, response
)
344 receivedQuery
.id = query
.id
345 self
.assertEqual(query
, receivedQuery
)
346 self
.assertEqual(response
, receivedResponse
)
347 allowed
= allowed
+ 1
349 # the query has not reached the responder,
350 # let's clear the response queue
351 self
.clearToResponderQueue()
353 # we might be already blocked, but we should have been able to send
354 # at least self._dynBlockQPS queries
355 self
.assertGreaterEqual(allowed
, self
._dynBlockQPS
)
358 waitForMaintenanceToRun()
360 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
361 (_
, receivedResponse
) = self
.sendUDPQuery(query
, response
=None, useQueue
=False)
362 self
.assertEqual(receivedResponse
, None)
364 # use a new socket, so a new port
365 self
._toResponderQueue
.put(response
, True, 1.0)
366 newsock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
367 newsock
.settimeout(1.0)
368 newsock
.connect(("127.0.0.1", self
._dnsDistPort
))
369 newsock
.send(query
.to_wire())
370 receivedResponse
= newsock
.recv(4096)
372 receivedResponse
= dns
.message
.from_wire(receivedResponse
)
373 receivedQuery
= self
._fromResponderQueue
.get(True, 1.0)
374 receivedQuery
.id = query
.id
375 self
.assertEqual(query
, receivedQuery
)
376 self
.assertEqual(response
, receivedResponse
)