]>
Commit | Line | Data |
---|---|---|
d354e773 | 1 | #!/usr/bin/env python |
87b0577d | 2 | import base64 |
d354e773 RG |
3 | import time |
4 | import dns | |
5 | from dnsdisttests import DNSDistTest | |
6 | ||
7 | class TestDynBlockQPS(DNSDistTest): | |
8 | ||
9 | _dynBlockQPS = 10 | |
10 | _dynBlockPeriod = 2 | |
11 | _dynBlockDuration = 5 | |
12 | _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort'] | |
13 | _config_template = """ | |
14 | function maintenance() | |
15 | addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d) | |
16 | end | |
17 | newServer{address="127.0.0.1:%s"} | |
18 | """ | |
19 | ||
20 | def testDynBlocksQRate(self): | |
21 | """ | |
22 | Dyn Blocks: QRate | |
23 | """ | |
24 | name = 'qrate.dynblocks.tests.powerdns.com.' | |
25 | query = dns.message.make_query(name, 'A', 'IN') | |
26 | response = dns.message.make_response(query) | |
27 | rrset = dns.rrset.from_text(name, | |
28 | 60, | |
29 | dns.rdataclass.IN, | |
30 | dns.rdatatype.A, | |
31 | '192.0.2.1') | |
32 | response.answer.append(rrset) | |
33 | ||
3bef39c3 RG |
34 | allowed = 0 |
35 | sent = 0 | |
36 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
d354e773 | 37 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) |
3bef39c3 RG |
38 | sent = sent + 1 |
39 | if receivedQuery: | |
40 | receivedQuery.id = query.id | |
41 | self.assertEquals(query, receivedQuery) | |
42 | self.assertEquals(response, receivedResponse) | |
43 | allowed = allowed + 1 | |
44 | else: | |
45 | # the query has not reached the responder, | |
46 | # let's clear the response queue | |
98883b8f | 47 | self.clearToResponderQueue() |
3bef39c3 RG |
48 | |
49 | # we might be already blocked, but we should have been able to send | |
50 | # at least self._dynBlockQPS queries | |
51 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
52 | ||
53 | if allowed == sent: | |
54 | # wait for the maintenance function to run | |
55 | time.sleep(2) | |
d354e773 RG |
56 | |
57 | # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod | |
58 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
59 | self.assertEquals(receivedResponse, None) | |
60 | ||
3bef39c3 | 61 | # wait until we are not blocked anymore |
d354e773 RG |
62 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
63 | ||
64 | # this one should succeed | |
65 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
66 | receivedQuery.id = query.id | |
67 | self.assertEquals(query, receivedQuery) | |
68 | self.assertEquals(response, receivedResponse) | |
69 | ||
70 | # again, over TCP this time | |
3bef39c3 RG |
71 | allowed = 0 |
72 | sent = 0 | |
73 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
d354e773 | 74 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) |
3bef39c3 RG |
75 | sent = sent + 1 |
76 | if receivedQuery: | |
77 | receivedQuery.id = query.id | |
78 | self.assertEquals(query, receivedQuery) | |
79 | self.assertEquals(response, receivedResponse) | |
80 | allowed = allowed + 1 | |
81 | else: | |
82 | # the query has not reached the responder, | |
83 | # let's clear the response queue | |
98883b8f | 84 | self.clearToResponderQueue() |
3bef39c3 RG |
85 | |
86 | # we might be already blocked, but we should have been able to send | |
87 | # at least self._dynBlockQPS queries | |
88 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
89 | ||
90 | if allowed == sent: | |
91 | # wait for the maintenance function to run | |
92 | time.sleep(2) | |
d354e773 RG |
93 | |
94 | # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod | |
95 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
96 | self.assertEquals(receivedResponse, None) | |
97 | ||
3bef39c3 | 98 | # wait until we are not blocked anymore |
d354e773 RG |
99 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
100 | ||
101 | # this one should succeed | |
102 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
103 | receivedQuery.id = query.id | |
104 | self.assertEquals(query, receivedQuery) | |
105 | self.assertEquals(response, receivedResponse) | |
106 | ||
107 | class TestDynBlockQPSRefused(DNSDistTest): | |
108 | ||
109 | _dynBlockQPS = 10 | |
110 | _dynBlockPeriod = 2 | |
111 | _dynBlockDuration = 5 | |
112 | _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort'] | |
113 | _config_template = """ | |
114 | function maintenance() | |
115 | addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d) | |
116 | end | |
117 | setDynBlocksAction(DNSAction.Refused) | |
118 | newServer{address="127.0.0.1:%s"} | |
119 | """ | |
120 | ||
121 | def testDynBlocksQRate(self): | |
122 | """ | |
123 | Dyn Blocks: QRate refused | |
124 | """ | |
125 | name = 'qraterefused.dynblocks.tests.powerdns.com.' | |
126 | query = dns.message.make_query(name, 'A', 'IN') | |
127 | response = dns.message.make_response(query) | |
128 | rrset = dns.rrset.from_text(name, | |
129 | 60, | |
130 | dns.rdataclass.IN, | |
131 | dns.rdatatype.A, | |
132 | '192.0.2.1') | |
133 | response.answer.append(rrset) | |
134 | refusedResponse = dns.message.make_response(query) | |
135 | refusedResponse.set_rcode(dns.rcode.REFUSED) | |
136 | ||
3bef39c3 RG |
137 | allowed = 0 |
138 | sent = 0 | |
139 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
d354e773 | 140 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) |
7b925432 RG |
141 | sent = sent + 1 |
142 | if receivedQuery: | |
143 | receivedQuery.id = query.id | |
144 | self.assertEquals(query, receivedQuery) | |
145 | self.assertEquals(receivedResponse, response) | |
146 | allowed = allowed + 1 | |
147 | else: | |
148 | self.assertEquals(receivedResponse, refusedResponse) | |
149 | # the query has not reached the responder, | |
150 | # let's clear the response queue | |
151 | self.clearToResponderQueue() | |
152 | ||
153 | # we might be already blocked, but we should have been able to send | |
154 | # at least self._dynBlockQPS queries | |
155 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
156 | ||
157 | if allowed == sent: | |
158 | # wait for the maintenance function to run | |
159 | time.sleep(2) | |
160 | ||
161 | # we should now be 'refused' for up to self._dynBlockDuration + self._dynBlockPeriod | |
162 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
163 | self.assertEquals(receivedResponse, refusedResponse) | |
164 | ||
165 | # wait until we are not blocked anymore | |
166 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) | |
167 | ||
168 | # this one should succeed | |
169 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
170 | receivedQuery.id = query.id | |
171 | self.assertEquals(query, receivedQuery) | |
172 | self.assertEquals(response, receivedResponse) | |
173 | ||
174 | allowed = 0 | |
175 | sent = 0 | |
176 | # again, over TCP this time | |
177 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
178 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
179 | sent = sent + 1 | |
180 | if receivedQuery: | |
181 | receivedQuery.id = query.id | |
182 | self.assertEquals(query, receivedQuery) | |
183 | self.assertEquals(receivedResponse, response) | |
184 | allowed = allowed + 1 | |
185 | else: | |
186 | self.assertEquals(receivedResponse, refusedResponse) | |
187 | # the query has not reached the responder, | |
188 | # let's clear the response queue | |
189 | self.clearToResponderQueue() | |
190 | ||
191 | # we might be already blocked, but we should have been able to send | |
192 | # at least self._dynBlockQPS queries | |
193 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
194 | ||
195 | if allowed == sent: | |
196 | # wait for the maintenance function to run | |
197 | time.sleep(2) | |
198 | ||
199 | # we should now be 'refused' for up to self._dynBlockDuration + self._dynBlockPeriod | |
200 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
201 | self.assertEquals(receivedResponse, refusedResponse) | |
202 | ||
203 | # wait until we are not blocked anymore | |
204 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) | |
205 | ||
206 | # this one should succeed | |
207 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
208 | receivedQuery.id = query.id | |
209 | self.assertEquals(query, receivedQuery) | |
210 | self.assertEquals(response, receivedResponse) | |
211 | ||
212 | class TestDynBlockQPSActionRefused(DNSDistTest): | |
213 | ||
214 | _dynBlockQPS = 10 | |
215 | _dynBlockPeriod = 2 | |
216 | _dynBlockDuration = 5 | |
217 | _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort'] | |
218 | _config_template = """ | |
219 | function maintenance() | |
220 | addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Refused) | |
221 | end | |
222 | setDynBlocksAction(DNSAction.Drop) | |
223 | newServer{address="127.0.0.1:%s"} | |
224 | """ | |
225 | ||
226 | def testDynBlocksQRate(self): | |
227 | """ | |
228 | Dyn Blocks: QRate refused (action) | |
229 | """ | |
230 | name = 'qrateactionrefused.dynblocks.tests.powerdns.com.' | |
231 | query = dns.message.make_query(name, 'A', 'IN') | |
232 | response = dns.message.make_response(query) | |
233 | rrset = dns.rrset.from_text(name, | |
234 | 60, | |
235 | dns.rdataclass.IN, | |
236 | dns.rdatatype.A, | |
237 | '192.0.2.1') | |
238 | response.answer.append(rrset) | |
239 | refusedResponse = dns.message.make_response(query) | |
240 | refusedResponse.set_rcode(dns.rcode.REFUSED) | |
241 | ||
242 | allowed = 0 | |
243 | sent = 0 | |
244 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
245 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
3bef39c3 RG |
246 | sent = sent + 1 |
247 | if receivedQuery: | |
248 | receivedQuery.id = query.id | |
249 | self.assertEquals(query, receivedQuery) | |
250 | self.assertEquals(receivedResponse, response) | |
251 | allowed = allowed + 1 | |
252 | else: | |
253 | self.assertEquals(receivedResponse, refusedResponse) | |
254 | # the query has not reached the responder, | |
255 | # let's clear the response queue | |
98883b8f | 256 | self.clearToResponderQueue() |
3bef39c3 RG |
257 | |
258 | # we might be already blocked, but we should have been able to send | |
259 | # at least self._dynBlockQPS queries | |
260 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
261 | ||
262 | if allowed == sent: | |
263 | # wait for the maintenance function to run | |
264 | time.sleep(2) | |
d354e773 RG |
265 | |
266 | # we should now be 'refused' for up to self._dynBlockDuration + self._dynBlockPeriod | |
267 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
268 | self.assertEquals(receivedResponse, refusedResponse) | |
269 | ||
3bef39c3 | 270 | # wait until we are not blocked anymore |
d354e773 RG |
271 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
272 | ||
273 | # this one should succeed | |
274 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
275 | receivedQuery.id = query.id | |
276 | self.assertEquals(query, receivedQuery) | |
277 | self.assertEquals(response, receivedResponse) | |
278 | ||
3bef39c3 RG |
279 | allowed = 0 |
280 | sent = 0 | |
d354e773 | 281 | # again, over TCP this time |
3bef39c3 | 282 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): |
d354e773 | 283 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) |
3bef39c3 RG |
284 | sent = sent + 1 |
285 | if receivedQuery: | |
286 | receivedQuery.id = query.id | |
287 | self.assertEquals(query, receivedQuery) | |
288 | self.assertEquals(receivedResponse, response) | |
289 | allowed = allowed + 1 | |
290 | else: | |
291 | self.assertEquals(receivedResponse, refusedResponse) | |
292 | # the query has not reached the responder, | |
293 | # let's clear the response queue | |
98883b8f | 294 | self.clearToResponderQueue() |
3bef39c3 RG |
295 | |
296 | # we might be already blocked, but we should have been able to send | |
297 | # at least self._dynBlockQPS queries | |
298 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
299 | ||
300 | if allowed == sent: | |
301 | # wait for the maintenance function to run | |
302 | time.sleep(2) | |
d354e773 RG |
303 | |
304 | # we should now be 'refused' for up to self._dynBlockDuration + self._dynBlockPeriod | |
305 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
306 | self.assertEquals(receivedResponse, refusedResponse) | |
307 | ||
3bef39c3 | 308 | # wait until we are not blocked anymore |
d354e773 RG |
309 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
310 | ||
311 | # this one should succeed | |
312 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
313 | receivedQuery.id = query.id | |
314 | self.assertEquals(query, receivedQuery) | |
315 | self.assertEquals(response, receivedResponse) | |
316 | ||
c4f5aeff RG |
317 | class TestDynBlockQPSActionTruncated(DNSDistTest): |
318 | ||
319 | _dynBlockQPS = 10 | |
320 | _dynBlockPeriod = 2 | |
321 | _dynBlockDuration = 5 | |
322 | _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort'] | |
323 | _config_template = """ | |
324 | function maintenance() | |
325 | addDynBlocks(exceedQRate(%d, %d), "Exceeded query rate", %d, DNSAction.Truncate) | |
326 | end | |
327 | setDynBlocksAction(DNSAction.Drop) | |
328 | newServer{address="127.0.0.1:%s"} | |
329 | """ | |
330 | ||
331 | def testDynBlocksQRate(self): | |
332 | """ | |
333 | Dyn Blocks: QRate truncated (action) | |
334 | """ | |
335 | name = 'qrateactiontruncated.dynblocks.tests.powerdns.com.' | |
336 | query = dns.message.make_query(name, 'A', 'IN') | |
337 | response = dns.message.make_response(query) | |
338 | rrset = dns.rrset.from_text(name, | |
339 | 60, | |
340 | dns.rdataclass.IN, | |
341 | dns.rdatatype.A, | |
342 | '192.0.2.1') | |
343 | response.answer.append(rrset) | |
344 | truncatedResponse = dns.message.make_response(query) | |
345 | truncatedResponse.flags |= dns.flags.TC | |
346 | ||
347 | allowed = 0 | |
348 | sent = 0 | |
349 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
350 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
351 | sent = sent + 1 | |
352 | if receivedQuery: | |
353 | receivedQuery.id = query.id | |
354 | self.assertEquals(query, receivedQuery) | |
355 | self.assertEquals(receivedResponse, response) | |
356 | allowed = allowed + 1 | |
357 | else: | |
358 | self.assertEquals(receivedResponse, truncatedResponse) | |
359 | # the query has not reached the responder, | |
360 | # let's clear the response queue | |
361 | self.clearToResponderQueue() | |
362 | ||
e2e59d2d | 363 | # we might be already truncated, but we should have been able to send |
c4f5aeff RG |
364 | # at least self._dynBlockQPS queries |
365 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
366 | ||
367 | if allowed == sent: | |
368 | # wait for the maintenance function to run | |
369 | time.sleep(2) | |
370 | ||
371 | # we should now be 'truncated' for up to self._dynBlockDuration + self._dynBlockPeriod | |
372 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
373 | self.assertEquals(receivedResponse, truncatedResponse) | |
374 | ||
e2e59d2d | 375 | # check over TCP, which should not be truncated |
376 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
377 | ||
378 | self.assertEquals(query, receivedQuery) | |
379 | self.assertEquals(receivedResponse, response) | |
380 | ||
c4f5aeff RG |
381 | # wait until we are not blocked anymore |
382 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) | |
383 | ||
384 | # this one should succeed | |
385 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
386 | receivedQuery.id = query.id | |
387 | self.assertEquals(query, receivedQuery) | |
388 | self.assertEquals(response, receivedResponse) | |
389 | ||
390 | allowed = 0 | |
391 | sent = 0 | |
392 | # again, over TCP this time, we should never get truncated! | |
393 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
394 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
395 | sent = sent + 1 | |
396 | self.assertEquals(query, receivedQuery) | |
397 | self.assertEquals(receivedResponse, response) | |
398 | receivedQuery.id = query.id | |
399 | allowed = allowed + 1 | |
400 | ||
401 | self.assertEquals(allowed, sent) | |
402 | ||
d354e773 RG |
403 | class TestDynBlockServFails(DNSDistTest): |
404 | ||
405 | _dynBlockQPS = 10 | |
406 | _dynBlockPeriod = 2 | |
407 | _dynBlockDuration = 5 | |
408 | _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort'] | |
409 | _config_template = """ | |
410 | function maintenance() | |
411 | addDynBlocks(exceedServFails(%d, %d), "Exceeded servfail rate", %d) | |
412 | end | |
413 | newServer{address="127.0.0.1:%s"} | |
414 | """ | |
415 | ||
416 | def testDynBlocksServFailRate(self): | |
417 | """ | |
418 | Dyn Blocks: Server Failure Rate | |
419 | """ | |
420 | name = 'servfailrate.dynblocks.tests.powerdns.com.' | |
421 | query = dns.message.make_query(name, 'A', 'IN') | |
422 | response = dns.message.make_response(query) | |
423 | rrset = dns.rrset.from_text(name, | |
424 | 60, | |
425 | dns.rdataclass.IN, | |
426 | dns.rdatatype.A, | |
427 | '192.0.2.1') | |
428 | response.answer.append(rrset) | |
429 | servfailResponse = dns.message.make_response(query) | |
430 | servfailResponse.set_rcode(dns.rcode.SERVFAIL) | |
431 | ||
432 | # start with normal responses | |
3bef39c3 | 433 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): |
d354e773 RG |
434 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) |
435 | receivedQuery.id = query.id | |
436 | self.assertEquals(query, receivedQuery) | |
437 | self.assertEquals(response, receivedResponse) | |
438 | ||
3bef39c3 RG |
439 | # wait for the maintenance function to run |
440 | time.sleep(2) | |
d354e773 RG |
441 | |
442 | # we should NOT be dropped! | |
443 | (_, receivedResponse) = self.sendUDPQuery(query, response) | |
444 | self.assertEquals(receivedResponse, response) | |
445 | ||
446 | # now with ServFail! | |
3bef39c3 RG |
447 | sent = 0 |
448 | allowed = 0 | |
449 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
d354e773 | 450 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, servfailResponse) |
3bef39c3 RG |
451 | sent = sent + 1 |
452 | if receivedQuery: | |
453 | receivedQuery.id = query.id | |
454 | self.assertEquals(query, receivedQuery) | |
455 | self.assertEquals(servfailResponse, receivedResponse) | |
456 | allowed = allowed + 1 | |
457 | else: | |
458 | # the query has not reached the responder, | |
459 | # let's clear the response queue | |
98883b8f | 460 | self.clearToResponderQueue() |
3bef39c3 RG |
461 | |
462 | # we might be already blocked, but we should have been able to send | |
463 | # at least self._dynBlockQPS queries | |
464 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
465 | ||
466 | if allowed == sent: | |
467 | # wait for the maintenance function to run | |
468 | time.sleep(2) | |
d354e773 RG |
469 | |
470 | # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod | |
471 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
472 | self.assertEquals(receivedResponse, None) | |
473 | ||
3bef39c3 | 474 | # wait until we are not blocked anymore |
d354e773 RG |
475 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
476 | ||
477 | # this one should succeed | |
478 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
479 | receivedQuery.id = query.id | |
480 | self.assertEquals(query, receivedQuery) | |
481 | self.assertEquals(response, receivedResponse) | |
482 | ||
483 | # again, over TCP this time | |
484 | # start with normal responses | |
3bef39c3 | 485 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): |
d354e773 RG |
486 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) |
487 | receivedQuery.id = query.id | |
488 | self.assertEquals(query, receivedQuery) | |
489 | self.assertEquals(response, receivedResponse) | |
490 | ||
3bef39c3 RG |
491 | # wait for the maintenance function to run |
492 | time.sleep(2) | |
d354e773 RG |
493 | |
494 | # we should NOT be dropped! | |
495 | (_, receivedResponse) = self.sendUDPQuery(query, response) | |
496 | self.assertEquals(receivedResponse, response) | |
497 | ||
498 | # now with ServFail! | |
3bef39c3 RG |
499 | sent = 0 |
500 | allowed = 0 | |
501 | for _ in xrange((self._dynBlockQPS * self._dynBlockPeriod) + 1): | |
d354e773 | 502 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, servfailResponse) |
3bef39c3 RG |
503 | sent = sent + 1 |
504 | if receivedQuery: | |
505 | receivedQuery.id = query.id | |
506 | self.assertEquals(query, receivedQuery) | |
507 | self.assertEquals(servfailResponse, receivedResponse) | |
508 | allowed = allowed + 1 | |
509 | else: | |
510 | # the query has not reached the responder, | |
511 | # let's clear the response queue | |
98883b8f | 512 | self.clearToResponderQueue() |
3bef39c3 RG |
513 | |
514 | # we might be already blocked, but we should have been able to send | |
515 | # at least self._dynBlockQPS queries | |
516 | self.assertGreaterEqual(allowed, self._dynBlockQPS) | |
517 | ||
518 | if allowed == sent: | |
519 | # wait for the maintenance function to run | |
520 | time.sleep(2) | |
d354e773 RG |
521 | |
522 | # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod | |
523 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
524 | self.assertEquals(receivedResponse, None) | |
525 | ||
3bef39c3 | 526 | # wait until we are not blocked anymore |
d354e773 RG |
527 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
528 | ||
529 | # this one should succeed | |
530 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
531 | receivedQuery.id = query.id | |
532 | self.assertEquals(query, receivedQuery) | |
533 | self.assertEquals(response, receivedResponse) | |
534 | ||
535 | class TestDynBlockResponseBytes(DNSDistTest): | |
536 | ||
537 | _dynBlockBytesPerSecond = 200 | |
538 | _dynBlockPeriod = 2 | |
539 | _dynBlockDuration = 5 | |
87b0577d RG |
540 | _consoleKey = DNSDistTest.generateConsoleKey() |
541 | _consoleKeyB64 = base64.b64encode(_consoleKey) | |
542 | _config_params = ['_consoleKeyB64', '_consolePort', '_dynBlockBytesPerSecond', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort'] | |
d354e773 | 543 | _config_template = """ |
87b0577d RG |
544 | setKey("%s") |
545 | controlSocket("127.0.0.1:%s") | |
d354e773 RG |
546 | function maintenance() |
547 | addDynBlocks(exceedRespByterate(%d, %d), "Exceeded response byterate", %d) | |
548 | end | |
549 | newServer{address="127.0.0.1:%s"} | |
550 | """ | |
551 | ||
552 | def testDynBlocksResponseByteRate(self): | |
553 | """ | |
554 | Dyn Blocks: Response Byte Rate | |
555 | """ | |
556 | name = 'responsebyterate.dynblocks.tests.powerdns.com.' | |
557 | query = dns.message.make_query(name, 'A', 'IN') | |
558 | response = dns.message.make_response(query) | |
559 | response.answer.append(dns.rrset.from_text_list(name, | |
560 | 60, | |
561 | dns.rdataclass.IN, | |
562 | dns.rdatatype.A, | |
563 | ['192.0.2.1', '192.0.2.2', '192.0.2.3', '192.0.2.4'])) | |
564 | response.answer.append(dns.rrset.from_text(name, | |
565 | 60, | |
566 | dns.rdataclass.IN, | |
567 | dns.rdatatype.AAAA, | |
568 | '2001:DB8::1')) | |
569 | ||
3bef39c3 RG |
570 | allowed = 0 |
571 | sent = 0 | |
87b0577d RG |
572 | |
573 | print(time.time()) | |
574 | ||
d354e773 RG |
575 | for _ in xrange(self._dynBlockBytesPerSecond * 5 / len(response.to_wire())): |
576 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
3bef39c3 RG |
577 | sent = sent + len(response.to_wire()) |
578 | if receivedQuery: | |
579 | receivedQuery.id = query.id | |
580 | self.assertEquals(query, receivedQuery) | |
581 | self.assertEquals(response, receivedResponse) | |
582 | allowed = allowed + len(response.to_wire()) | |
583 | else: | |
584 | # the query has not reached the responder, | |
585 | # let's clear the response queue | |
98883b8f | 586 | self.clearToResponderQueue() |
5d91160a | 587 | # and stop right there, otherwise we might |
16fc4a38 | 588 | # wait for so long that the dynblock is gone |
5d91160a RG |
589 | # by the time we finished |
590 | break | |
3bef39c3 RG |
591 | |
592 | # we might be already blocked, but we should have been able to send | |
593 | # at least self._dynBlockBytesPerSecond bytes | |
87b0577d RG |
594 | print(allowed) |
595 | print(sent) | |
596 | print(time.time()) | |
3bef39c3 RG |
597 | self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond) |
598 | ||
87b0577d RG |
599 | print(self.sendConsoleCommand("showDynBlocks()")) |
600 | print(self.sendConsoleCommand("grepq(\"\")")) | |
601 | print(time.time()) | |
602 | ||
3bef39c3 RG |
603 | if allowed == sent: |
604 | # wait for the maintenance function to run | |
87b0577d | 605 | print("Waiting for the maintenance function to run") |
3bef39c3 | 606 | time.sleep(2) |
d354e773 | 607 | |
87b0577d RG |
608 | print(self.sendConsoleCommand("showDynBlocks()")) |
609 | print(self.sendConsoleCommand("grepq(\"\")")) | |
610 | print(time.time()) | |
611 | ||
d354e773 RG |
612 | # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod |
613 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
614 | self.assertEquals(receivedResponse, None) | |
615 | ||
87b0577d RG |
616 | print(self.sendConsoleCommand("showDynBlocks()")) |
617 | print(self.sendConsoleCommand("grepq(\"\")")) | |
618 | print(time.time()) | |
619 | ||
3bef39c3 | 620 | # wait until we are not blocked anymore |
d354e773 RG |
621 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
622 | ||
87b0577d RG |
623 | print(self.sendConsoleCommand("showDynBlocks()")) |
624 | print(self.sendConsoleCommand("grepq(\"\")")) | |
625 | print(time.time()) | |
626 | ||
d354e773 RG |
627 | # this one should succeed |
628 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
629 | receivedQuery.id = query.id | |
630 | self.assertEquals(query, receivedQuery) | |
631 | self.assertEquals(response, receivedResponse) | |
632 | ||
633 | # again, over TCP this time | |
3bef39c3 RG |
634 | allowed = 0 |
635 | sent = 0 | |
d354e773 RG |
636 | for _ in xrange(self._dynBlockBytesPerSecond * 5 / len(response.to_wire())): |
637 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
3bef39c3 RG |
638 | sent = sent + len(response.to_wire()) |
639 | if receivedQuery: | |
640 | receivedQuery.id = query.id | |
641 | self.assertEquals(query, receivedQuery) | |
642 | self.assertEquals(response, receivedResponse) | |
643 | allowed = allowed + len(response.to_wire()) | |
644 | else: | |
645 | # the query has not reached the responder, | |
646 | # let's clear the response queue | |
98883b8f | 647 | self.clearToResponderQueue() |
5d91160a | 648 | # and stop right there, otherwise we might |
16fc4a38 | 649 | # wait for so long that the dynblock is gone |
5d91160a RG |
650 | # by the time we finished |
651 | break | |
3bef39c3 RG |
652 | |
653 | # we might be already blocked, but we should have been able to send | |
654 | # at least self._dynBlockBytesPerSecond bytes | |
655 | self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond) | |
656 | ||
657 | if allowed == sent: | |
658 | # wait for the maintenance function to run | |
659 | time.sleep(2) | |
d354e773 RG |
660 | |
661 | # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod | |
662 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
663 | self.assertEquals(receivedResponse, None) | |
664 | ||
3bef39c3 | 665 | # wait until we are not blocked anymore |
d354e773 RG |
666 | time.sleep(self._dynBlockDuration + self._dynBlockPeriod) |
667 | ||
668 | # this one should succeed | |
669 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
670 | receivedQuery.id = query.id | |
671 | self.assertEquals(query, receivedQuery) | |
672 | self.assertEquals(response, receivedResponse) |