]> git.ipfire.org Git - thirdparty/pdns.git/blame - regression-tests.dnsdist/test_DynBlocks.py
Merge pull request #8795 from omoerbeek/rec-lua-docs-policytag
[thirdparty/pdns.git] / regression-tests.dnsdist / test_DynBlocks.py
CommitLineData
d354e773 1#!/usr/bin/env python
87b0577d 2import base64
d3473b8c
RG
3import json
4import requests
d354e773
RG
5import time
6import dns
06b0e003
RG
7from dnsdisttests import DNSDistTest
8try:
9 range = xrange
10except NameError:
11 pass
d354e773 12
dc2fd93a 13class DynBlocksTest(DNSDistTest):
d354e773 14
d3473b8c
RG
15 _webTimeout = 2.0
16 _webServerPort = 8083
17 _webServerBasicAuthPassword = 'secret'
18 _webServerAPIKey = 'apisecret'
19
20 def doTestDynBlockViaAPI(self, range, reason, minSeconds, maxSeconds, minBlocks, maxBlocks):
21 headers = {'x-api-key': self._webServerAPIKey}
22 url = 'http://127.0.0.1:' + str(self._webServerPort) + '/jsonstat?command=dynblocklist'
23 r = requests.get(url, headers=headers, timeout=self._webTimeout)
24 self.assertTrue(r)
25 self.assertEquals(r.status_code, 200)
26
27 content = r.json()
28 self.assertIsNotNone(content)
29 self.assertIn(range, content)
30
31 values = content[range]
477c86a0 32 for key in ['reason', 'seconds', 'blocks', 'action']:
d3473b8c
RG
33 self.assertIn(key, values)
34
35 self.assertEqual(values['reason'], reason)
b8753918 36 self.assertGreaterEqual(values['seconds'], minSeconds)
d3473b8c
RG
37 self.assertLessEqual(values['seconds'], maxSeconds)
38 self.assertGreaterEqual(values['blocks'], minBlocks)
39 self.assertLessEqual(values['blocks'], maxBlocks)
40
e44df0f1 41 def doTestQRate(self, name, testViaAPI=True):
d354e773
RG
42 query = dns.message.make_query(name, 'A', 'IN')
43 response = dns.message.make_response(query)
44 rrset = dns.rrset.from_text(name,
45 60,
46 dns.rdataclass.IN,
47 dns.rdatatype.A,
48 '192.0.2.1')
49 response.answer.append(rrset)
50
3bef39c3
RG
51 allowed = 0
52 sent = 0
b4f23783 53 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
d354e773 54 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
3bef39c3
RG
55 sent = sent + 1
56 if receivedQuery:
57 receivedQuery.id = query.id
58 self.assertEquals(query, receivedQuery)
59 self.assertEquals(response, receivedResponse)
60 allowed = allowed + 1
61 else:
62 # the query has not reached the responder,
63 # let's clear the response queue
98883b8f 64 self.clearToResponderQueue()
3bef39c3
RG
65
66 # we might be already blocked, but we should have been able to send
67 # at least self._dynBlockQPS queries
68 self.assertGreaterEqual(allowed, self._dynBlockQPS)
69
70 if allowed == sent:
71 # wait for the maintenance function to run
72 time.sleep(2)
d354e773
RG
73
74 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
75 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
76 self.assertEquals(receivedResponse, None)
77
d3473b8c
RG
78 if testViaAPI:
79 self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', self._dynBlockDuration - 4, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1)
80
3bef39c3 81 # wait until we are not blocked anymore
d354e773
RG
82 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
83
84 # this one should succeed
85 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
86 receivedQuery.id = query.id
87 self.assertEquals(query, receivedQuery)
88 self.assertEquals(response, receivedResponse)
89
90 # again, over TCP this time
3bef39c3
RG
91 allowed = 0
92 sent = 0
b4f23783 93 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
d354e773 94 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
3bef39c3
RG
95 sent = sent + 1
96 if receivedQuery:
97 receivedQuery.id = query.id
98 self.assertEquals(query, receivedQuery)
99 self.assertEquals(response, receivedResponse)
100 allowed = allowed + 1
101 else:
102 # the query has not reached the responder,
103 # let's clear the response queue
98883b8f 104 self.clearToResponderQueue()
3bef39c3
RG
105
106 # we might be already blocked, but we should have been able to send
107 # at least self._dynBlockQPS queries
108 self.assertGreaterEqual(allowed, self._dynBlockQPS)
109
110 if allowed == sent:
111 # wait for the maintenance function to run
112 time.sleep(2)
d354e773
RG
113
114 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
115 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
116 self.assertEquals(receivedResponse, None)
117
3bef39c3 118 # wait until we are not blocked anymore
d354e773
RG
119 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
120
121 # this one should succeed
122 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
123 receivedQuery.id = query.id
124 self.assertEquals(query, receivedQuery)
125 self.assertEquals(response, receivedResponse)
126
dc2fd93a 127 def doTestQRateRCode(self, name, rcode):
d354e773
RG
128 query = dns.message.make_query(name, 'A', 'IN')
129 response = dns.message.make_response(query)
130 rrset = dns.rrset.from_text(name,
131 60,
132 dns.rdataclass.IN,
133 dns.rdatatype.A,
134 '192.0.2.1')
135 response.answer.append(rrset)
dc2fd93a
RG
136 expectedResponse = dns.message.make_response(query)
137 expectedResponse.set_rcode(rcode)
d354e773 138
3bef39c3
RG
139 allowed = 0
140 sent = 0
b4f23783 141 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
d354e773 142 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
7b925432
RG
143 sent = sent + 1
144 if receivedQuery:
145 receivedQuery.id = query.id
146 self.assertEquals(query, receivedQuery)
147 self.assertEquals(receivedResponse, response)
148 allowed = allowed + 1
149 else:
dc2fd93a 150 self.assertEquals(receivedResponse, expectedResponse)
7b925432
RG
151 # the query has not reached the responder,
152 # let's clear the response queue
153 self.clearToResponderQueue()
154
155 # we might be already blocked, but we should have been able to send
156 # at least self._dynBlockQPS queries
157 self.assertGreaterEqual(allowed, self._dynBlockQPS)
158
159 if allowed == sent:
160 # wait for the maintenance function to run
161 time.sleep(2)
162
dc2fd93a 163 # we should now be 'rcode' for up to self._dynBlockDuration + self._dynBlockPeriod
7b925432 164 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
dc2fd93a 165 self.assertEquals(receivedResponse, expectedResponse)
7b925432
RG
166
167 # wait until we are not blocked anymore
168 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
169
170 # this one should succeed
171 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
172 receivedQuery.id = query.id
173 self.assertEquals(query, receivedQuery)
174 self.assertEquals(response, receivedResponse)
175
176 allowed = 0
177 sent = 0
178 # again, over TCP this time
b4f23783 179 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
7b925432
RG
180 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
181 sent = sent + 1
182 if receivedQuery:
183 receivedQuery.id = query.id
184 self.assertEquals(query, receivedQuery)
185 self.assertEquals(receivedResponse, response)
186 allowed = allowed + 1
187 else:
dc2fd93a 188 self.assertEquals(receivedResponse, expectedResponse)
7b925432
RG
189 # the query has not reached the responder,
190 # let's clear the response queue
191 self.clearToResponderQueue()
192
193 # we might be already blocked, but we should have been able to send
194 # at least self._dynBlockQPS queries
195 self.assertGreaterEqual(allowed, self._dynBlockQPS)
196
197 if allowed == sent:
198 # wait for the maintenance function to run
199 time.sleep(2)
200
dc2fd93a 201 # we should now be 'rcode' for up to self._dynBlockDuration + self._dynBlockPeriod
7b925432 202 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
dc2fd93a 203 self.assertEquals(receivedResponse, expectedResponse)
7b925432
RG
204
205 # wait until we are not blocked anymore
206 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
207
208 # this one should succeed
209 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
210 receivedQuery.id = query.id
211 self.assertEquals(query, receivedQuery)
212 self.assertEquals(response, receivedResponse)
213
dc2fd93a 214 def doTestResponseByteRate(self, name):
7b925432
RG
215 query = dns.message.make_query(name, 'A', 'IN')
216 response = dns.message.make_response(query)
dc2fd93a
RG
217 response.answer.append(dns.rrset.from_text_list(name,
218 60,
219 dns.rdataclass.IN,
220 dns.rdatatype.A,
221 ['192.0.2.1', '192.0.2.2', '192.0.2.3', '192.0.2.4']))
222 response.answer.append(dns.rrset.from_text(name,
223 60,
224 dns.rdataclass.IN,
225 dns.rdatatype.AAAA,
226 '2001:DB8::1'))
7b925432
RG
227
228 allowed = 0
229 sent = 0
dc2fd93a
RG
230
231 print(time.time())
232
233 for _ in range(int(self._dynBlockBytesPerSecond * 5 / len(response.to_wire()))):
7b925432 234 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
dc2fd93a 235 sent = sent + len(response.to_wire())
3bef39c3
RG
236 if receivedQuery:
237 receivedQuery.id = query.id
238 self.assertEquals(query, receivedQuery)
dc2fd93a
RG
239 self.assertEquals(response, receivedResponse)
240 allowed = allowed + len(response.to_wire())
3bef39c3 241 else:
3bef39c3
RG
242 # the query has not reached the responder,
243 # let's clear the response queue
98883b8f 244 self.clearToResponderQueue()
dc2fd93a
RG
245 # and stop right there, otherwise we might
246 # wait for so long that the dynblock is gone
247 # by the time we finished
248 break
3bef39c3
RG
249
250 # we might be already blocked, but we should have been able to send
dc2fd93a
RG
251 # at least self._dynBlockBytesPerSecond bytes
252 print(allowed)
253 print(sent)
254 print(time.time())
255 self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond)
256
257 print(self.sendConsoleCommand("showDynBlocks()"))
258 print(self.sendConsoleCommand("grepq(\"\")"))
259 print(time.time())
3bef39c3
RG
260
261 if allowed == sent:
262 # wait for the maintenance function to run
dc2fd93a 263 print("Waiting for the maintenance function to run")
3bef39c3 264 time.sleep(2)
d354e773 265
dc2fd93a
RG
266 print(self.sendConsoleCommand("showDynBlocks()"))
267 print(self.sendConsoleCommand("grepq(\"\")"))
268 print(time.time())
269
270 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
d354e773 271 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
dc2fd93a
RG
272 self.assertEquals(receivedResponse, None)
273
274 print(self.sendConsoleCommand("showDynBlocks()"))
275 print(self.sendConsoleCommand("grepq(\"\")"))
276 print(time.time())
d354e773 277
3bef39c3 278 # wait until we are not blocked anymore
d354e773
RG
279 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
280
dc2fd93a
RG
281 print(self.sendConsoleCommand("showDynBlocks()"))
282 print(self.sendConsoleCommand("grepq(\"\")"))
283 print(time.time())
284
d354e773
RG
285 # this one should succeed
286 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
287 receivedQuery.id = query.id
288 self.assertEquals(query, receivedQuery)
289 self.assertEquals(response, receivedResponse)
290
dc2fd93a 291 # again, over TCP this time
3bef39c3
RG
292 allowed = 0
293 sent = 0
dc2fd93a 294 for _ in range(int(self._dynBlockBytesPerSecond * 5 / len(response.to_wire()))):
d354e773 295 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
dc2fd93a 296 sent = sent + len(response.to_wire())
3bef39c3
RG
297 if receivedQuery:
298 receivedQuery.id = query.id
299 self.assertEquals(query, receivedQuery)
dc2fd93a
RG
300 self.assertEquals(response, receivedResponse)
301 allowed = allowed + len(response.to_wire())
3bef39c3 302 else:
3bef39c3
RG
303 # the query has not reached the responder,
304 # let's clear the response queue
98883b8f 305 self.clearToResponderQueue()
dc2fd93a
RG
306 # and stop right there, otherwise we might
307 # wait for so long that the dynblock is gone
308 # by the time we finished
309 break
3bef39c3
RG
310
311 # we might be already blocked, but we should have been able to send
dc2fd93a
RG
312 # at least self._dynBlockBytesPerSecond bytes
313 self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond)
3bef39c3
RG
314
315 if allowed == sent:
316 # wait for the maintenance function to run
317 time.sleep(2)
d354e773 318
dc2fd93a 319 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
d354e773 320 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
dc2fd93a 321 self.assertEquals(receivedResponse, None)
d354e773 322
3bef39c3 323 # wait until we are not blocked anymore
d354e773
RG
324 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
325
326 # this one should succeed
327 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
328 receivedQuery.id = query.id
329 self.assertEquals(query, receivedQuery)
330 self.assertEquals(response, receivedResponse)
331
dc2fd93a 332 def doTestRCodeRate(self, name, rcode):
d354e773
RG
333 query = dns.message.make_query(name, 'A', 'IN')
334 response = dns.message.make_response(query)
335 rrset = dns.rrset.from_text(name,
336 60,
337 dns.rdataclass.IN,
338 dns.rdatatype.A,
339 '192.0.2.1')
340 response.answer.append(rrset)
dc2fd93a
RG
341 expectedResponse = dns.message.make_response(query)
342 expectedResponse.set_rcode(rcode)
d354e773
RG
343
344 # start with normal responses
b4f23783 345 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
d354e773
RG
346 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
347 receivedQuery.id = query.id
348 self.assertEquals(query, receivedQuery)
349 self.assertEquals(response, receivedResponse)
350
3bef39c3
RG
351 # wait for the maintenance function to run
352 time.sleep(2)
d354e773
RG
353
354 # we should NOT be dropped!
355 (_, receivedResponse) = self.sendUDPQuery(query, response)
356 self.assertEquals(receivedResponse, response)
357
dc2fd93a 358 # now with rcode!
3bef39c3
RG
359 sent = 0
360 allowed = 0
b4f23783 361 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
dc2fd93a 362 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
3bef39c3
RG
363 sent = sent + 1
364 if receivedQuery:
365 receivedQuery.id = query.id
366 self.assertEquals(query, receivedQuery)
dc2fd93a 367 self.assertEquals(expectedResponse, receivedResponse)
3bef39c3
RG
368 allowed = allowed + 1
369 else:
370 # the query has not reached the responder,
371 # let's clear the response queue
98883b8f 372 self.clearToResponderQueue()
3bef39c3
RG
373
374 # we might be already blocked, but we should have been able to send
375 # at least self._dynBlockQPS queries
376 self.assertGreaterEqual(allowed, self._dynBlockQPS)
377
378 if allowed == sent:
379 # wait for the maintenance function to run
380 time.sleep(2)
d354e773
RG
381
382 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
383 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
384 self.assertEquals(receivedResponse, None)
385
3bef39c3 386 # wait until we are not blocked anymore
d354e773
RG
387 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
388
389 # this one should succeed
390 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
391 receivedQuery.id = query.id
392 self.assertEquals(query, receivedQuery)
393 self.assertEquals(response, receivedResponse)
394
395 # again, over TCP this time
396 # start with normal responses
b4f23783 397 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
d354e773
RG
398 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
399 receivedQuery.id = query.id
400 self.assertEquals(query, receivedQuery)
401 self.assertEquals(response, receivedResponse)
402
3bef39c3
RG
403 # wait for the maintenance function to run
404 time.sleep(2)
d354e773
RG
405
406 # we should NOT be dropped!
407 (_, receivedResponse) = self.sendUDPQuery(query, response)
408 self.assertEquals(receivedResponse, response)
409
dc2fd93a 410 # now with rcode!
3bef39c3
RG
411 sent = 0
412 allowed = 0
b4f23783 413 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
dc2fd93a 414 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
3bef39c3
RG
415 sent = sent + 1
416 if receivedQuery:
417 receivedQuery.id = query.id
418 self.assertEquals(query, receivedQuery)
dc2fd93a 419 self.assertEquals(expectedResponse, receivedResponse)
3bef39c3
RG
420 allowed = allowed + 1
421 else:
422 # the query has not reached the responder,
423 # let's clear the response queue
98883b8f 424 self.clearToResponderQueue()
3bef39c3
RG
425
426 # we might be already blocked, but we should have been able to send
427 # at least self._dynBlockQPS queries
428 self.assertGreaterEqual(allowed, self._dynBlockQPS)
429
430 if allowed == sent:
431 # wait for the maintenance function to run
432 time.sleep(2)
d354e773
RG
433
434 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
435 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
436 self.assertEquals(receivedResponse, None)
437
3bef39c3 438 # wait until we are not blocked anymore
d354e773
RG
439 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
440
441 # this one should succeed
442 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
443 receivedQuery.id = query.id
444 self.assertEquals(query, receivedQuery)
445 self.assertEquals(response, receivedResponse)
446
94c38f24
RG
447 def doTestRCodeRatio(self, name, rcode, noerrorcount, rcodecount):
448 query = dns.message.make_query(name, 'A', 'IN')
449 response = dns.message.make_response(query)
450 rrset = dns.rrset.from_text(name,
451 60,
452 dns.rdataclass.IN,
453 dns.rdatatype.A,
454 '192.0.2.1')
455 response.answer.append(rrset)
456 expectedResponse = dns.message.make_response(query)
457 expectedResponse.set_rcode(rcode)
458
459 # start with normal responses
460 for _ in range(noerrorcount-1):
461 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
462 receivedQuery.id = query.id
463 self.assertEquals(query, receivedQuery)
464 self.assertEquals(response, receivedResponse)
465
466 # wait for the maintenance function to run
467 time.sleep(2)
468
469 # we should NOT be dropped!
470 (_, receivedResponse) = self.sendUDPQuery(query, response)
471 self.assertEquals(receivedResponse, response)
472
473 # now with rcode!
474 sent = 0
475 allowed = 0
476 for _ in range(rcodecount):
477 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
478 sent = sent + 1
479 if receivedQuery:
480 receivedQuery.id = query.id
481 self.assertEquals(query, receivedQuery)
482 self.assertEquals(expectedResponse, receivedResponse)
483 allowed = allowed + 1
484 else:
485 # the query has not reached the responder,
486 # let's clear the response queue
487 self.clearToResponderQueue()
488
489 # we should have been able to send all our queries since the minimum number of queries is set to noerrorcount + rcodecount
490 self.assertGreaterEqual(allowed, rcodecount)
491
492 # wait for the maintenance function to run
493 time.sleep(2)
494
495 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
496 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
497 self.assertEquals(receivedResponse, None)
498
499 # wait until we are not blocked anymore
500 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
501
502 # this one should succeed
503 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
504 receivedQuery.id = query.id
505 self.assertEquals(query, receivedQuery)
506 self.assertEquals(response, receivedResponse)
507
508 # again, over TCP this time
509 # start with normal responses
510 for _ in range(noerrorcount-1):
511 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
512 receivedQuery.id = query.id
513 self.assertEquals(query, receivedQuery)
514 self.assertEquals(response, receivedResponse)
515
516 # wait for the maintenance function to run
517 time.sleep(2)
518
519 # we should NOT be dropped!
520 (_, receivedResponse) = self.sendUDPQuery(query, response)
521 self.assertEquals(receivedResponse, response)
522
523 # now with rcode!
524 sent = 0
525 allowed = 0
526 for _ in range(rcodecount):
527 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
528 sent = sent + 1
529 if receivedQuery:
530 receivedQuery.id = query.id
531 self.assertEquals(query, receivedQuery)
532 self.assertEquals(expectedResponse, receivedResponse)
533 allowed = allowed + 1
534 else:
535 # the query has not reached the responder,
536 # let's clear the response queue
537 self.clearToResponderQueue()
538
539 # we should have been able to send all our queries since the minimum number of queries is set to noerrorcount + rcodecount
540 self.assertGreaterEqual(allowed, rcodecount)
541
542 # wait for the maintenance function to run
543 time.sleep(2)
544
545 # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod
546 (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False)
547 self.assertEquals(receivedResponse, None)
548
549 # wait until we are not blocked anymore
550 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
551
552 # this one should succeed
553 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
554 receivedQuery.id = query.id
555 self.assertEquals(query, receivedQuery)
556 self.assertEquals(response, receivedResponse)
557
dc2fd93a 558class TestDynBlockQPS(DynBlocksTest):
d354e773 559
dc2fd93a 560 _dynBlockQPS = 10
d354e773
RG
561 _dynBlockPeriod = 2
562 _dynBlockDuration = 5
d3473b8c 563 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
d354e773
RG
564 _config_template = """
565 function maintenance()
dc2fd93a 566 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d)
d354e773
RG
567 end
568 newServer{address="127.0.0.1:%s"}
d3473b8c 569 webserver("127.0.0.1:%s", "%s", "%s")
d354e773
RG
570 """
571
dc2fd93a 572 def testDynBlocksQRate(self):
d354e773 573 """
dc2fd93a 574 Dyn Blocks: QRate
d354e773 575 """
dc2fd93a 576 name = 'qrate.dynblocks.tests.powerdns.com.'
e44df0f1 577 self.doTestQRate(name)
d354e773 578
dc2fd93a 579class TestDynBlockGroupQPS(DynBlocksTest):
87b0577d 580
dc2fd93a
RG
581 _dynBlockQPS = 10
582 _dynBlockPeriod = 2
583 _dynBlockDuration = 5
d3473b8c 584 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
dc2fd93a
RG
585 _config_template = """
586 local dbr = dynBlockRulesGroup()
587 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
87b0577d 588
dc2fd93a
RG
589 function maintenance()
590 dbr:apply()
591 end
592 newServer{address="127.0.0.1:%s"}
d3473b8c 593 webserver("127.0.0.1:%s", "%s", "%s")
dc2fd93a
RG
594 """
595
596 def testDynBlocksQRate(self):
597 """
598 Dyn Blocks (Group): QRate
599 """
600 name = 'qrate.group.dynblocks.tests.powerdns.com.'
e44df0f1 601 self.doTestQRate(name)
dc2fd93a
RG
602
603
604class TestDynBlockQPSRefused(DynBlocksTest):
605
606 _dynBlockQPS = 10
607 _dynBlockPeriod = 2
608 _dynBlockDuration = 5
609 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
610 _config_template = """
611 function maintenance()
612 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d)
613 end
614 setDynBlocksAction(DNSAction.Refused)
615 newServer{address="127.0.0.1:%s"}
616 """
617
618 def testDynBlocksQRate(self):
619 """
620 Dyn Blocks: QRate refused
621 """
622 name = 'qraterefused.dynblocks.tests.powerdns.com.'
623 self.doTestQRateRCode(name, dns.rcode.REFUSED)
624
625class TestDynBlockGroupQPSRefused(DynBlocksTest):
626
627 _dynBlockQPS = 10
628 _dynBlockPeriod = 2
629 _dynBlockDuration = 5
630 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
631 _config_template = """
632 local dbr = dynBlockRulesGroup()
633 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
634
635 function maintenance()
636 dbr:apply()
637 end
638 setDynBlocksAction(DNSAction.Refused)
639 newServer{address="127.0.0.1:%s"}
640 """
641
642 def testDynBlocksQRate(self):
643 """
644 Dyn Blocks (Group): QRate refused
645 """
646 name = 'qraterefused.group.dynblocks.tests.powerdns.com.'
647 self.doTestQRateRCode(name, dns.rcode.REFUSED)
648
649class TestDynBlockQPSActionRefused(DynBlocksTest):
650
651 _dynBlockQPS = 10
652 _dynBlockPeriod = 2
653 _dynBlockDuration = 5
654 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
655 _config_template = """
656 function maintenance()
657 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Refused)
658 end
659 setDynBlocksAction(DNSAction.Drop)
660 newServer{address="127.0.0.1:%s"}
661 """
662
663 def testDynBlocksQRate(self):
664 """
665 Dyn Blocks: QRate refused (action)
666 """
667 name = 'qrateactionrefused.dynblocks.tests.powerdns.com.'
668 self.doTestQRateRCode(name, dns.rcode.REFUSED)
669
79ee8ff9
RG
670class TestDynBlockQPSActionNXD(DynBlocksTest):
671
672 _dynBlockQPS = 10
673 _dynBlockPeriod = 2
674 _dynBlockDuration = 5
675 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
676 _config_template = """
677 function maintenance()
678 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Nxdomain)
679 end
680 setDynBlocksAction(DNSAction.Drop)
681 newServer{address="127.0.0.1:%s"}
682 """
683
684 def testDynBlocksQRate(self):
685 """
686 Dyn Blocks: QRate NXD (action)
687 """
688 name = 'qrateactionnxd.dynblocks.tests.powerdns.com.'
689 self.doTestQRateRCode(name, dns.rcode.NXDOMAIN)
690
d3473b8c 691class TestDynBlockGroupQPSActionRefused(DynBlocksTest):
dc2fd93a
RG
692
693 _dynBlockQPS = 10
694 _dynBlockPeriod = 2
695 _dynBlockDuration = 5
696 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
697 _config_template = """
698 local dbr = dynBlockRulesGroup()
699 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.Refused)
700
701 function maintenance()
702 dbr:apply()
703 end
704 setDynBlocksAction(DNSAction.Drop)
705 newServer{address="127.0.0.1:%s"}
706 """
707
708 def testDynBlocksQRate(self):
709 """
710 Dyn Blocks (group): QRate refused (action)
711 """
712 name = 'qrateactionrefused.group.dynblocks.tests.powerdns.com.'
713 self.doTestQRateRCode(name, dns.rcode.REFUSED)
714
715class TestDynBlockQPSActionTruncated(DNSDistTest):
716
717 _dynBlockQPS = 10
718 _dynBlockPeriod = 2
719 _dynBlockDuration = 5
720 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
721 _config_template = """
722 function maintenance()
723 addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Truncate)
724 end
725 setDynBlocksAction(DNSAction.Drop)
726 newServer{address="127.0.0.1:%s"}
727 """
728
729 def testDynBlocksQRate(self):
730 """
731 Dyn Blocks: QRate truncated (action)
732 """
733 name = 'qrateactiontruncated.dynblocks.tests.powerdns.com.'
734 query = dns.message.make_query(name, 'A', 'IN')
955b9377
RG
735 # dnsdist sets RA = RD for TC responses
736 query.flags &= ~dns.flags.RD
dc2fd93a
RG
737 response = dns.message.make_response(query)
738 rrset = dns.rrset.from_text(name,
739 60,
740 dns.rdataclass.IN,
741 dns.rdatatype.A,
742 '192.0.2.1')
743 response.answer.append(rrset)
744 truncatedResponse = dns.message.make_response(query)
745 truncatedResponse.flags |= dns.flags.TC
746
747 allowed = 0
748 sent = 0
749 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
d354e773 750 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
dc2fd93a 751 sent = sent + 1
3bef39c3
RG
752 if receivedQuery:
753 receivedQuery.id = query.id
754 self.assertEquals(query, receivedQuery)
dc2fd93a
RG
755 self.assertEquals(receivedResponse, response)
756 allowed = allowed + 1
3bef39c3 757 else:
dc2fd93a 758 self.assertEquals(receivedResponse, truncatedResponse)
3bef39c3
RG
759 # the query has not reached the responder,
760 # let's clear the response queue
98883b8f 761 self.clearToResponderQueue()
3bef39c3 762
dc2fd93a
RG
763 # we might be already truncated, but we should have been able to send
764 # at least self._dynBlockQPS queries
765 self.assertGreaterEqual(allowed, self._dynBlockQPS)
87b0577d 766
3bef39c3
RG
767 if allowed == sent:
768 # wait for the maintenance function to run
769 time.sleep(2)
d354e773 770
dc2fd93a 771 # we should now be 'truncated' for up to self._dynBlockDuration + self._dynBlockPeriod
d354e773 772 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
dc2fd93a 773 self.assertEquals(receivedResponse, truncatedResponse)
d354e773 774
dc2fd93a
RG
775 # check over TCP, which should not be truncated
776 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
777
778 self.assertEquals(query, receivedQuery)
779 self.assertEquals(receivedResponse, response)
87b0577d 780
3bef39c3 781 # wait until we are not blocked anymore
d354e773
RG
782 time.sleep(self._dynBlockDuration + self._dynBlockPeriod)
783
784 # this one should succeed
785 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
786 receivedQuery.id = query.id
787 self.assertEquals(query, receivedQuery)
788 self.assertEquals(response, receivedResponse)
789
3bef39c3
RG
790 allowed = 0
791 sent = 0
dc2fd93a
RG
792 # again, over TCP this time, we should never get truncated!
793 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
d354e773 794 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
dc2fd93a
RG
795 sent = sent + 1
796 self.assertEquals(query, receivedQuery)
797 self.assertEquals(receivedResponse, response)
798 receivedQuery.id = query.id
799 allowed = allowed + 1
3bef39c3 800
dc2fd93a 801 self.assertEquals(allowed, sent)
3bef39c3 802
dc2fd93a 803class TestDynBlockServFails(DynBlocksTest):
d354e773 804
dc2fd93a
RG
805 _dynBlockQPS = 10
806 _dynBlockPeriod = 2
807 _dynBlockDuration = 5
808 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
809 _config_template = """
810 function maintenance()
811 addDynBlocks(exceedServFails(%d, %d), "Exceeded servfail rate", %d)
812 end
813 newServer{address="127.0.0.1:%s"}
814 """
d354e773 815
dc2fd93a
RG
816 def testDynBlocksServFailRate(self):
817 """
818 Dyn Blocks: Server Failure Rate
819 """
820 name = 'servfailrate.dynblocks.tests.powerdns.com.'
821 self.doTestRCodeRate(name, dns.rcode.SERVFAIL)
d354e773 822
ad3f984f
RG
823class TestDynBlockWhitelist(DynBlocksTest):
824
825 _dynBlockQPS = 10
826 _dynBlockPeriod = 2
827 _dynBlockDuration = 5
828 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
829 _config_template = """
830 whitelisted = false
831 function maintenance()
832 toBlock = exceedQRate(%d, %d)
833 for addr, count in pairs(toBlock) do
834 if addr:toString() == "127.0.0.1" then
835 whitelisted = true
836 toBlock[addr] = nil
837 end
838 end
839 addDynBlocks(toBlock, "Exceeded query rate", %d)
840 end
841
842 function spoofrule(dq)
843 if (whitelisted)
844 then
845 return DNSAction.Spoof, "192.0.2.42"
846 else
847 return DNSAction.None, ""
848 end
849 end
850 addAction("whitelisted-test.dynblocks.tests.powerdns.com.", LuaAction(spoofrule))
851
852 newServer{address="127.0.0.1:%s"}
853 """
854
855 def testWhitelisted(self):
856 """
857 Dyn Blocks: Whitelisted from the dynamic blocks
858 """
859 name = 'whitelisted.dynblocks.tests.powerdns.com.'
860 query = dns.message.make_query(name, 'A', 'IN')
861 response = dns.message.make_response(query)
862 rrset = dns.rrset.from_text(name,
863 60,
864 dns.rdataclass.IN,
865 dns.rdatatype.A,
866 '192.0.2.1')
867 response.answer.append(rrset)
868
869 allowed = 0
870 sent = 0
871 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
872 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
873 sent = sent + 1
874 if receivedQuery:
875 receivedQuery.id = query.id
876 self.assertEquals(query, receivedQuery)
877 self.assertEquals(response, receivedResponse)
878 allowed = allowed + 1
879 else:
880 # the query has not reached the responder,
881 # let's clear the response queue
882 self.clearToResponderQueue()
883
884 # we should not have been blocked
885 self.assertEqual(allowed, sent)
886
887 # wait for the maintenance function to run
888 time.sleep(2)
889
890 # we should still not be blocked
891 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
892 receivedQuery.id = query.id
893 self.assertEquals(query, receivedQuery)
894 self.assertEquals(receivedResponse, receivedResponse)
895
896 # check that we would have been blocked without the whitelisting
897 name = 'whitelisted-test.dynblocks.tests.powerdns.com.'
898 query = dns.message.make_query(name, 'A', 'IN')
899 # dnsdist set RA = RD for spoofed responses
900 query.flags &= ~dns.flags.RD
901 expectedResponse = dns.message.make_response(query)
902 rrset = dns.rrset.from_text(name,
903 60,
904 dns.rdataclass.IN,
905 dns.rdatatype.A,
906 '192.0.2.42')
907 expectedResponse.answer.append(rrset)
908 (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
909 self.assertEquals(receivedResponse, expectedResponse)
910
dc2fd93a
RG
911class TestDynBlockGroupServFails(DynBlocksTest):
912
913 _dynBlockQPS = 10
914 _dynBlockPeriod = 2
915 _dynBlockDuration = 5
916 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
917 _config_template = """
918 local dbr = dynBlockRulesGroup()
d3ec24f9 919 dbr:setRCodeRate(DNSRCode.SERVFAIL, %d, %d, "Exceeded query rate", %d)
dc2fd93a
RG
920
921 function maintenance()
922 dbr:apply()
923 end
924
925 newServer{address="127.0.0.1:%s"}
926 """
927
928 def testDynBlocksServFailRate(self):
929 """
930 Dyn Blocks (group): Server Failure Rate
931 """
932 name = 'servfailrate.group.dynblocks.tests.powerdns.com.'
933 self.doTestRCodeRate(name, dns.rcode.SERVFAIL)
934
94c38f24
RG
935class TestDynBlockGroupServFailsRatio(DynBlocksTest):
936
937 _dynBlockPeriod = 2
938 _dynBlockDuration = 5
939 _config_params = ['_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
940 _config_template = """
941 local dbr = dynBlockRulesGroup()
942 dbr:setRCodeRatio(DNSRCode.SERVFAIL, 0.2, %d, "Exceeded query rate", %d, 20)
943
944 function maintenance()
945 dbr:apply()
946 end
947
948 newServer{address="127.0.0.1:%s"}
949 """
950
951 def testDynBlocksServFailRatio(self):
952 """
953 Dyn Blocks (group): Server Failure Ratio
954 """
955 name = 'servfailratio.group.dynblocks.tests.powerdns.com.'
956 self.doTestRCodeRatio(name, dns.rcode.SERVFAIL, 10, 10)
957
dc2fd93a
RG
958class TestDynBlockResponseBytes(DynBlocksTest):
959
960 _dynBlockBytesPerSecond = 200
961 _dynBlockPeriod = 2
962 _dynBlockDuration = 5
963 _consoleKey = DNSDistTest.generateConsoleKey()
964 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
965 _config_params = ['_consoleKeyB64', '_consolePort', '_dynBlockBytesPerSecond', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
966 _config_template = """
967 setKey("%s")
968 controlSocket("127.0.0.1:%s")
969 function maintenance()
970 addDynBlocks(exceedRespByterate(%d, %d), "Exceeded response byterate", %d)
971 end
972 newServer{address="127.0.0.1:%s"}
973 """
974
975 def testDynBlocksResponseByteRate(self):
976 """
977 Dyn Blocks: Response Byte Rate
978 """
979 name = 'responsebyterate.dynblocks.tests.powerdns.com.'
980 self.doTestResponseByteRate(name)
981
982class TestDynBlockGroupResponseBytes(DynBlocksTest):
983
984 _dynBlockBytesPerSecond = 200
985 _dynBlockPeriod = 2
986 _dynBlockDuration = 5
987 _consoleKey = DNSDistTest.generateConsoleKey()
988 _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
989 _config_params = ['_consoleKeyB64', '_consolePort', '_dynBlockBytesPerSecond', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
990 _config_template = """
991 setKey("%s")
992 controlSocket("127.0.0.1:%s")
993 local dbr = dynBlockRulesGroup()
994 dbr:setResponseByteRate(%d, %d, "Exceeded query rate", %d)
995
996 function maintenance()
997 dbr:apply()
998 end
999
1000 newServer{address="127.0.0.1:%s"}
1001 """
1002
1003 def testDynBlocksResponseByteRate(self):
1004 """
1005 Dyn Blocks (group) : Response Byte Rate
1006 """
1007 name = 'responsebyterate.group.dynblocks.tests.powerdns.com.'
1008 self.doTestResponseByteRate(name)
b718792f 1009
477c86a0 1010class TestDynBlockGroupExcluded(DynBlocksTest):
b718792f
RG
1011
1012 _dynBlockQPS = 10
1013 _dynBlockPeriod = 2
1014 _dynBlockDuration = 5
477c86a0 1015 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort']
b718792f 1016 _config_template = """
b718792f
RG
1017 local dbr = dynBlockRulesGroup()
1018 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d)
1019 dbr:excludeRange("127.0.0.1/32")
1020
1021 function maintenance()
1022 dbr:apply()
1023 end
1024
1025 newServer{address="127.0.0.1:%s"}
1026 """
1027
1028 def testExcluded(self):
1029 """
1030 Dyn Blocks (group) : Excluded from the dynamic block rules
1031 """
1032 name = 'excluded.group.dynblocks.tests.powerdns.com.'
1033 query = dns.message.make_query(name, 'A', 'IN')
1034 response = dns.message.make_response(query)
1035 rrset = dns.rrset.from_text(name,
1036 60,
1037 dns.rdataclass.IN,
1038 dns.rdatatype.A,
1039 '192.0.2.1')
1040 response.answer.append(rrset)
1041
1042 allowed = 0
1043 sent = 0
1044 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
1045 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1046 sent = sent + 1
1047 if receivedQuery:
1048 receivedQuery.id = query.id
1049 self.assertEquals(query, receivedQuery)
1050 self.assertEquals(response, receivedResponse)
1051 allowed = allowed + 1
1052 else:
1053 # the query has not reached the responder,
1054 # let's clear the response queue
1055 self.clearToResponderQueue()
1056
477c86a0 1057 # we should not have been blocked
b718792f
RG
1058 self.assertEqual(allowed, sent)
1059
1060 # wait for the maintenance function to run
1061 time.sleep(2)
1062
1063 # we should still not be blocked
1064 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1065 receivedQuery.id = query.id
1066 self.assertEquals(query, receivedQuery)
1067 self.assertEquals(receivedResponse, receivedResponse)
477c86a0
RG
1068
1069class TestDynBlockGroupNoOp(DynBlocksTest):
1070
1071 _dynBlockQPS = 10
1072 _dynBlockPeriod = 2
1073 _dynBlockDuration = 5
1074 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
1075 _config_template = """
1076 local dbr = dynBlockRulesGroup()
1077 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.NoOp)
1078
1079 function maintenance()
1080 dbr:apply()
1081 end
1082
1083 newServer{address="127.0.0.1:%s"}
1084 webserver("127.0.0.1:%s", "%s", "%s")
1085 """
1086
1087 def testNoOp(self):
1088 """
1089 Dyn Blocks (group) : NoOp
1090 """
1091 name = 'noop.group.dynblocks.tests.powerdns.com.'
1092 query = dns.message.make_query(name, 'A', 'IN')
1093 response = dns.message.make_response(query)
1094 rrset = dns.rrset.from_text(name,
1095 60,
1096 dns.rdataclass.IN,
1097 dns.rdatatype.A,
1098 '192.0.2.1')
1099 response.answer.append(rrset)
1100
1101 allowed = 0
1102 sent = 0
1103 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1):
1104 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1105 sent = sent + 1
1106 if receivedQuery:
1107 receivedQuery.id = query.id
1108 self.assertEquals(query, receivedQuery)
1109 self.assertEquals(response, receivedResponse)
1110 allowed = allowed + 1
1111 else:
1112 # the query has not reached the responder,
1113 # let's clear the response queue
1114 self.clearToResponderQueue()
1115
1116 # a dynamic rule should have been inserted, but the queries should still go on
1117 self.assertEqual(allowed, sent)
1118
1119 # wait for the maintenance function to run
1120 time.sleep(2)
1121
1122 # the rule should still be present, but the queries pass through anyway
1123 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1124 receivedQuery.id = query.id
1125 self.assertEquals(query, receivedQuery)
1126 self.assertEquals(receivedResponse, receivedResponse)
1127
1128 # check that the rule has been inserted
1129 self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', self._dynBlockDuration - 4, self._dynBlockDuration, 0, sent)
1d3ba133
RG
1130
1131class TestDynBlockGroupWarning(DynBlocksTest):
1132
1133 _dynBlockWarningQPS = 5
1134 _dynBlockQPS = 20
1135 _dynBlockPeriod = 2
1136 _dynBlockDuration = 5
1137 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_dynBlockWarningQPS', '_testServerPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
1138 _config_template = """
1139 local dbr = dynBlockRulesGroup()
1140 dbr:setQueryRate(%d, %d, "Exceeded query rate", %d, DNSAction.Drop, %d)
1141
1142 function maintenance()
1143 dbr:apply()
1144 end
1145
1146 newServer{address="127.0.0.1:%s"}
1147 webserver("127.0.0.1:%s", "%s", "%s")
1148 """
1149
1150 def testWarning(self):
1151 """
1152 Dyn Blocks (group) : Warning
1153 """
1154 name = 'warning.group.dynblocks.tests.powerdns.com.'
1155 query = dns.message.make_query(name, 'A', 'IN')
1156 response = dns.message.make_response(query)
1157 rrset = dns.rrset.from_text(name,
1158 60,
1159 dns.rdataclass.IN,
1160 dns.rdatatype.A,
1161 '192.0.2.1')
1162 response.answer.append(rrset)
1163
1164 allowed = 0
1165 sent = 0
1166 for _ in range((self._dynBlockWarningQPS * self._dynBlockPeriod) + 1):
1167 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1168 sent = sent + 1
1169 if receivedQuery:
1170 receivedQuery.id = query.id
1171 self.assertEquals(query, receivedQuery)
1172 self.assertEquals(response, receivedResponse)
1173 allowed = allowed + 1
1174 else:
1175 # the query has not reached the responder,
1176 # let's clear the response queue
1177 self.clearToResponderQueue()
1178
1179 # a dynamic rule should have been inserted, but the queries should
1180 # still go on because we are still at warning level
1181 self.assertEqual(allowed, sent)
1182
1183 # wait for the maintenance function to run
1184 time.sleep(2)
1185
1186 # the rule should still be present, but the queries pass through anyway
1187 (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
1188 receivedQuery.id = query.id
1189 self.assertEquals(query, receivedQuery)
1190 self.assertEquals(receivedResponse, receivedResponse)
1191
1192 # check that the rule has been inserted
1193 self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', self._dynBlockDuration - 4, self._dynBlockDuration, 0, sent)
1194
1195 self.doTestQRate(name)