]>
Commit | Line | Data |
---|---|---|
903853f4 | 1 | #!/usr/bin/env python |
1ea747c0 | 2 | import base64 |
903853f4 RG |
3 | import time |
4 | import dns | |
78e3ac9e | 5 | import clientsubnetoption |
903853f4 RG |
6 | from dnsdisttests import DNSDistTest |
7 | ||
8 | class TestCaching(DNSDistTest): | |
9 | ||
10 | _config_template = """ | |
fe1c60f2 | 11 | pc = newPacketCache(100, 86400, 1) |
903853f4 RG |
12 | getPool(""):setCache(pc) |
13 | addAction(makeRule("nocache.cache.tests.powerdns.com."), SkipCacheAction()) | |
816dff3d RG |
14 | function skipViaLua(dq) |
15 | dq.skipCache = true | |
16 | return DNSAction.None, "" | |
17 | end | |
a2ff35e3 | 18 | addAction("nocachevialua.cache.tests.powerdns.com.", LuaAction(skipViaLua)) |
903853f4 RG |
19 | newServer{address="127.0.0.1:%s"} |
20 | """ | |
fe1c60f2 | 21 | |
903853f4 RG |
22 | def testCached(self): |
23 | """ | |
24 | Cache: Served from cache | |
25 | ||
26 | dnsdist is configured to cache entries, we are sending several | |
27 | identical requests and checking that the backend only receive | |
28 | the first one. | |
29 | """ | |
30 | numberOfQueries = 10 | |
31 | name = 'cached.cache.tests.powerdns.com.' | |
32 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
33 | response = dns.message.make_response(query) | |
34 | rrset = dns.rrset.from_text(name, | |
35 | 3600, | |
36 | dns.rdataclass.IN, | |
37 | dns.rdatatype.AAAA, | |
38 | '::1') | |
39 | response.answer.append(rrset) | |
40 | ||
41 | # first query to fill the cache | |
42 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
43 | self.assertTrue(receivedQuery) | |
44 | self.assertTrue(receivedResponse) | |
45 | receivedQuery.id = query.id | |
46 | self.assertEquals(query, receivedQuery) | |
47 | self.assertEquals(receivedResponse, response) | |
0bbd746a RG |
48 | |
49 | for _ in range(numberOfQueries): | |
50 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
51 | self.assertEquals(receivedResponse, response) | |
52 | ||
53 | total = 0 | |
54 | for key in self._responsesCounter: | |
55 | total += self._responsesCounter[key] | |
56 | TestCaching._responsesCounter[key] = 0 | |
57 | ||
58 | self.assertEquals(total, 1) | |
59 | ||
60 | # TCP should not be cached | |
61 | # first query to fill the cache | |
62 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
63 | self.assertTrue(receivedQuery) | |
64 | self.assertTrue(receivedResponse) | |
65 | receivedQuery.id = query.id | |
66 | self.assertEquals(query, receivedQuery) | |
67 | self.assertEquals(receivedResponse, response) | |
68 | ||
69 | for _ in range(numberOfQueries): | |
70 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
71 | self.assertEquals(receivedResponse, response) | |
72 | ||
73 | total = 0 | |
74 | for key in self._responsesCounter: | |
75 | total += self._responsesCounter[key] | |
76 | TestCaching._responsesCounter[key] = 0 | |
77 | ||
78 | self.assertEquals(total, 1) | |
79 | ||
80 | def testDOCached(self): | |
81 | """ | |
82 | Cache: Served from cache, query has DO bit set | |
83 | ||
84 | dnsdist is configured to cache entries, we are sending several | |
85 | identical requests and checking that the backend only receive | |
86 | the first one. | |
87 | """ | |
88 | numberOfQueries = 10 | |
89 | name = 'cached-do.cache.tests.powerdns.com.' | |
90 | query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, payload=4096, want_dnssec=True) | |
91 | response = dns.message.make_response(query) | |
92 | rrset = dns.rrset.from_text(name, | |
93 | 3600, | |
94 | dns.rdataclass.IN, | |
95 | dns.rdatatype.AAAA, | |
96 | '::1') | |
97 | response.answer.append(rrset) | |
98 | ||
99 | # first query to fill the cache | |
100 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
101 | self.assertTrue(receivedQuery) | |
102 | self.assertTrue(receivedResponse) | |
103 | receivedQuery.id = query.id | |
104 | self.assertEquals(query, receivedQuery) | |
105 | self.assertEquals(receivedResponse, response) | |
903853f4 RG |
106 | |
107 | for _ in range(numberOfQueries): | |
108 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
109 | self.assertEquals(receivedResponse, response) | |
110 | ||
111 | total = 0 | |
02bbf9eb RG |
112 | for key in self._responsesCounter: |
113 | total += self._responsesCounter[key] | |
903853f4 RG |
114 | TestCaching._responsesCounter[key] = 0 |
115 | ||
116 | self.assertEquals(total, 1) | |
117 | ||
118 | # TCP should not be cached | |
119 | # first query to fill the cache | |
120 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
121 | self.assertTrue(receivedQuery) | |
122 | self.assertTrue(receivedResponse) | |
123 | receivedQuery.id = query.id | |
124 | self.assertEquals(query, receivedQuery) | |
125 | self.assertEquals(receivedResponse, response) | |
126 | ||
127 | for _ in range(numberOfQueries): | |
128 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
129 | self.assertEquals(receivedResponse, response) | |
130 | ||
131 | total = 0 | |
02bbf9eb RG |
132 | for key in self._responsesCounter: |
133 | total += self._responsesCounter[key] | |
903853f4 RG |
134 | TestCaching._responsesCounter[key] = 0 |
135 | ||
136 | self.assertEquals(total, 1) | |
137 | ||
138 | def testSkipCache(self): | |
139 | """ | |
140 | Cache: SkipCacheAction | |
141 | ||
142 | dnsdist is configured to not cache entries for nocache.cache.tests.powerdns.com. | |
143 | we are sending several requests and checking that the backend get them all. | |
144 | """ | |
145 | name = 'nocache.cache.tests.powerdns.com.' | |
146 | numberOfQueries = 10 | |
147 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
148 | response = dns.message.make_response(query) | |
816dff3d RG |
149 | rrset = dns.rrset.from_text(name, |
150 | 3600, | |
151 | dns.rdataclass.IN, | |
152 | dns.rdatatype.AAAA, | |
153 | '::1') | |
154 | response.answer.append(rrset) | |
155 | ||
156 | for _ in range(numberOfQueries): | |
157 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
158 | self.assertTrue(receivedQuery) | |
159 | self.assertTrue(receivedResponse) | |
160 | receivedQuery.id = query.id | |
161 | self.assertEquals(query, receivedQuery) | |
162 | self.assertEquals(receivedResponse, response) | |
163 | ||
164 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
165 | self.assertTrue(receivedQuery) | |
166 | self.assertTrue(receivedResponse) | |
167 | receivedQuery.id = query.id | |
168 | self.assertEquals(query, receivedQuery) | |
169 | self.assertEquals(receivedResponse, response) | |
170 | ||
02bbf9eb RG |
171 | for key in self._responsesCounter: |
172 | value = self._responsesCounter[key] | |
816dff3d RG |
173 | self.assertEquals(value, numberOfQueries) |
174 | ||
175 | def testSkipCacheViaLua(self): | |
176 | """ | |
177 | Cache: SkipCache via Lua | |
178 | ||
179 | dnsdist is configured to not cache entries for nocachevialua.cache.tests.powerdns.com. | |
180 | we are sending several requests and checking that the backend get them all. | |
181 | """ | |
182 | name = 'nocachevialua.cache.tests.powerdns.com.' | |
183 | numberOfQueries = 10 | |
184 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
185 | response = dns.message.make_response(query) | |
903853f4 RG |
186 | rrset = dns.rrset.from_text(name, |
187 | 3600, | |
188 | dns.rdataclass.IN, | |
189 | dns.rdatatype.AAAA, | |
190 | '::1') | |
191 | response.answer.append(rrset) | |
192 | ||
193 | for _ in range(numberOfQueries): | |
194 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
195 | self.assertTrue(receivedQuery) | |
196 | self.assertTrue(receivedResponse) | |
197 | receivedQuery.id = query.id | |
198 | self.assertEquals(query, receivedQuery) | |
199 | self.assertEquals(receivedResponse, response) | |
200 | ||
201 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
202 | self.assertTrue(receivedQuery) | |
203 | self.assertTrue(receivedResponse) | |
204 | receivedQuery.id = query.id | |
205 | self.assertEquals(query, receivedQuery) | |
206 | self.assertEquals(receivedResponse, response) | |
207 | ||
02bbf9eb RG |
208 | for key in self._responsesCounter: |
209 | value = self._responsesCounter[key] | |
903853f4 RG |
210 | self.assertEquals(value, numberOfQueries) |
211 | ||
212 | def testCacheExpiration(self): | |
213 | """ | |
214 | Cache: Cache expiration | |
215 | ||
216 | dnsdist is configured to cache entries, we are sending one request | |
217 | (cache miss) with a very short TTL, checking that the next requests | |
218 | are cached. Then we wait for the TTL to expire, check that the | |
219 | next request is a miss but the following one a hit. | |
220 | """ | |
221 | ttl = 2 | |
222 | misses = 0 | |
223 | name = 'cacheexpiration.cache.tests.powerdns.com.' | |
224 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
225 | response = dns.message.make_response(query) | |
226 | rrset = dns.rrset.from_text(name, | |
227 | ttl, | |
228 | dns.rdataclass.IN, | |
229 | dns.rdatatype.AAAA, | |
230 | '::1') | |
231 | response.answer.append(rrset) | |
232 | ||
233 | # first query to fill the cache | |
234 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
235 | self.assertTrue(receivedQuery) | |
236 | self.assertTrue(receivedResponse) | |
237 | receivedQuery.id = query.id | |
238 | self.assertEquals(query, receivedQuery) | |
239 | self.assertEquals(receivedResponse, response) | |
240 | misses += 1 | |
241 | ||
242 | # next queries should hit the cache | |
243 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
244 | self.assertEquals(receivedResponse, response) | |
245 | ||
246 | # now we wait a bit for the cache entry to expire | |
247 | time.sleep(ttl + 1) | |
248 | ||
249 | # next query should be a miss, fill the cache again | |
250 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
251 | self.assertTrue(receivedQuery) | |
252 | self.assertTrue(receivedResponse) | |
253 | receivedQuery.id = query.id | |
254 | self.assertEquals(query, receivedQuery) | |
255 | self.assertEquals(receivedResponse, response) | |
256 | misses += 1 | |
257 | ||
258 | # following queries should hit the cache again | |
259 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
260 | self.assertEquals(receivedResponse, response) | |
261 | ||
262 | total = 0 | |
02bbf9eb RG |
263 | for key in self._responsesCounter: |
264 | total += self._responsesCounter[key] | |
903853f4 RG |
265 | |
266 | self.assertEquals(total, misses) | |
267 | ||
268 | def testCacheExpirationDifferentSets(self): | |
269 | """ | |
270 | Cache: Cache expiration with different sets | |
271 | ||
272 | dnsdist is configured to cache entries, we are sending one request | |
273 | (cache miss) whose response has a long and a very short TTL, | |
274 | checking that the next requests are cached. Then we wait for the | |
275 | short TTL to expire, check that the | |
276 | next request is a miss but the following one a hit. | |
277 | """ | |
278 | ttl = 2 | |
279 | misses = 0 | |
280 | name = 'cacheexpirationdifferentsets.cache.tests.powerdns.com.' | |
281 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
282 | response = dns.message.make_response(query) | |
283 | rrset = dns.rrset.from_text(name, | |
284 | ttl, | |
285 | dns.rdataclass.IN, | |
286 | dns.rdatatype.CNAME, | |
287 | 'cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.') | |
288 | response.answer.append(rrset) | |
289 | rrset = dns.rrset.from_text('cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.', | |
290 | ttl + 3600, | |
291 | dns.rdataclass.IN, | |
292 | dns.rdatatype.A, | |
293 | '192.2.0.1') | |
294 | response.additional.append(rrset) | |
295 | ||
296 | # first query to fill the cache | |
297 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
298 | self.assertTrue(receivedQuery) | |
299 | self.assertTrue(receivedResponse) | |
300 | receivedQuery.id = query.id | |
301 | self.assertEquals(query, receivedQuery) | |
302 | self.assertEquals(receivedResponse, response) | |
303 | misses += 1 | |
304 | ||
305 | # next queries should hit the cache | |
306 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
307 | self.assertEquals(receivedResponse, response) | |
308 | ||
309 | # now we wait a bit for the cache entry to expire | |
310 | time.sleep(ttl + 1) | |
311 | ||
312 | # next query should be a miss, fill the cache again | |
313 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
314 | self.assertTrue(receivedQuery) | |
315 | self.assertTrue(receivedResponse) | |
316 | receivedQuery.id = query.id | |
317 | self.assertEquals(query, receivedQuery) | |
318 | self.assertEquals(receivedResponse, response) | |
319 | misses += 1 | |
320 | ||
321 | # following queries should hit the cache again | |
322 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
323 | self.assertEquals(receivedResponse, response) | |
324 | ||
325 | total = 0 | |
02bbf9eb RG |
326 | for key in self._responsesCounter: |
327 | total += self._responsesCounter[key] | |
903853f4 RG |
328 | |
329 | self.assertEquals(total, misses) | |
330 | ||
331 | def testCacheDecreaseTTL(self): | |
332 | """ | |
333 | Cache: Cache decreases TTL | |
334 | ||
335 | dnsdist is configured to cache entries, we are sending one request | |
336 | (cache miss) and verify that the cache hits have a decreasing TTL. | |
337 | """ | |
338 | ttl = 600 | |
339 | misses = 0 | |
340 | name = 'cachedecreasettl.cache.tests.powerdns.com.' | |
341 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
342 | response = dns.message.make_response(query) | |
343 | rrset = dns.rrset.from_text(name, | |
344 | ttl, | |
345 | dns.rdataclass.IN, | |
346 | dns.rdatatype.AAAA, | |
347 | '::1') | |
348 | response.answer.append(rrset) | |
349 | ||
350 | # first query to fill the cache | |
351 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
352 | self.assertTrue(receivedQuery) | |
353 | self.assertTrue(receivedResponse) | |
354 | receivedQuery.id = query.id | |
355 | self.assertEquals(query, receivedQuery) | |
356 | self.assertEquals(receivedResponse, response) | |
357 | misses += 1 | |
358 | ||
359 | # next queries should hit the cache | |
360 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
361 | self.assertEquals(receivedResponse, response) | |
362 | for an in receivedResponse.answer: | |
363 | self.assertTrue(an.ttl <= ttl) | |
364 | ||
365 | # now we wait a bit for the TTL to decrease | |
366 | time.sleep(1) | |
367 | ||
368 | # next queries should hit the cache | |
369 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
370 | self.assertEquals(receivedResponse, response) | |
371 | for an in receivedResponse.answer: | |
372 | self.assertTrue(an.ttl < ttl) | |
373 | ||
374 | total = 0 | |
02bbf9eb RG |
375 | for key in self._responsesCounter: |
376 | total += self._responsesCounter[key] | |
903853f4 RG |
377 | |
378 | self.assertEquals(total, misses) | |
379 | ||
380 | def testCacheDifferentCase(self): | |
381 | """ | |
382 | Cache: Cache matches different case | |
383 | ||
384 | dnsdist is configured to cache entries, we are sending one request | |
385 | (cache miss) and verify that the same one with a different case | |
386 | matches. | |
387 | """ | |
388 | ttl = 600 | |
389 | name = 'cachedifferentcase.cache.tests.powerdns.com.' | |
390 | differentCaseName = 'CacheDifferentCASE.cache.tests.powerdns.com.' | |
391 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
392 | differentCaseQuery = dns.message.make_query(differentCaseName, 'AAAA', 'IN') | |
393 | response = dns.message.make_response(query) | |
394 | differentCaseResponse = dns.message.make_response(differentCaseQuery) | |
395 | rrset = dns.rrset.from_text(name, | |
396 | ttl, | |
397 | dns.rdataclass.IN, | |
398 | dns.rdatatype.AAAA, | |
399 | '::1') | |
400 | response.answer.append(rrset) | |
401 | differentCaseResponse.answer.append(rrset) | |
402 | ||
403 | # first query to fill the cache | |
404 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
405 | self.assertTrue(receivedQuery) | |
406 | self.assertTrue(receivedResponse) | |
407 | receivedQuery.id = query.id | |
408 | self.assertEquals(query, receivedQuery) | |
409 | self.assertEquals(receivedResponse, response) | |
410 | ||
411 | # different case query should still hit the cache | |
412 | (_, receivedResponse) = self.sendUDPQuery(differentCaseQuery, response=None, useQueue=False) | |
413 | self.assertEquals(receivedResponse, differentCaseResponse) | |
414 | ||
415 | ||
a2c4a339 CH |
416 | class TestTempFailureCacheTTLAction(DNSDistTest): |
417 | ||
418 | _config_template = """ | |
419 | pc = newPacketCache(100, 86400, 1) | |
420 | getPool(""):setCache(pc) | |
421 | addAction("servfail.cache.tests.powerdns.com.", TempFailureCacheTTLAction(1)) | |
422 | newServer{address="127.0.0.1:%s"} | |
423 | """ | |
424 | ||
425 | def testTempFailureCacheTTLAction(self): | |
426 | """ | |
427 | Cache: When a TempFailure TTL is set, it should be honored | |
428 | ||
429 | dnsdist is configured to cache packets, plus a specific qname is | |
430 | set up with a lower TempFailure Cache TTL. we are sending one request | |
431 | (cache miss) and verify that the cache is hit for the following query, | |
432 | but the TTL then expires before the larger "good" packetcache TTL. | |
433 | """ | |
434 | name = 'servfail.cache.tests.powerdns.com.' | |
435 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
436 | response = dns.message.make_response(query) | |
437 | response.set_rcode(dns.rcode.SERVFAIL) | |
438 | ||
439 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
440 | self.assertTrue(receivedQuery) | |
441 | self.assertTrue(receivedResponse) | |
442 | receivedQuery.id = query.id | |
443 | self.assertEquals(query, receivedQuery) | |
444 | self.assertEquals(receivedResponse, response) | |
445 | ||
446 | # next query should hit the cache | |
45fc7a50 | 447 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) |
a2c4a339 CH |
448 | self.assertFalse(receivedQuery) |
449 | self.assertTrue(receivedResponse) | |
450 | self.assertEquals(receivedResponse, response) | |
451 | ||
452 | # now we wait a bit for the Failure-Cache TTL to expire | |
453 | time.sleep(2) | |
454 | ||
455 | # next query should NOT hit the cache | |
456 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
457 | self.assertTrue(receivedQuery) | |
458 | self.assertTrue(receivedResponse) | |
459 | self.assertEquals(receivedResponse, response) | |
460 | ||
461 | ||
903853f4 RG |
462 | class TestCachingWithExistingEDNS(DNSDistTest): |
463 | ||
464 | _config_template = """ | |
465 | pc = newPacketCache(5, 86400, 1) | |
466 | getPool(""):setCache(pc) | |
467 | newServer{address="127.0.0.1:%s"} | |
468 | """ | |
469 | def testCacheWithEDNS(self): | |
470 | """ | |
471 | Cache: Cache should not match different EDNS value | |
472 | ||
473 | dnsdist is configured to cache entries, we are sending one request | |
474 | (cache miss) and verify that the same one with a different EDNS UDP | |
475 | Payload size is not served from the cache. | |
476 | """ | |
477 | misses = 0 | |
478 | name = 'cachedifferentedns.cache.tests.powerdns.com.' | |
479 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512) | |
480 | response = dns.message.make_response(query) | |
481 | rrset = dns.rrset.from_text(name, | |
482 | 3600, | |
483 | dns.rdataclass.IN, | |
484 | dns.rdatatype.A, | |
485 | '127.0.0.1') | |
486 | response.answer.append(rrset) | |
487 | ||
488 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
489 | self.assertTrue(receivedQuery) | |
490 | self.assertTrue(receivedResponse) | |
491 | receivedQuery.id = query.id | |
492 | self.assertEquals(query, receivedQuery) | |
493 | self.assertEquals(response, receivedResponse) | |
494 | misses += 1 | |
495 | ||
496 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
497 | response = dns.message.make_response(query) | |
498 | rrset = dns.rrset.from_text(name, | |
499 | 3600, | |
500 | dns.rdataclass.IN, | |
501 | dns.rdatatype.A, | |
502 | '127.0.0.1') | |
503 | response.answer.append(rrset) | |
504 | ||
505 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
506 | self.assertTrue(receivedQuery) | |
507 | self.assertTrue(receivedResponse) | |
508 | receivedQuery.id = query.id | |
509 | self.assertEquals(query, receivedQuery) | |
510 | self.assertEquals(response, receivedResponse) | |
511 | misses += 1 | |
512 | ||
513 | total = 0 | |
02bbf9eb RG |
514 | for key in self._responsesCounter: |
515 | total += self._responsesCounter[key] | |
903853f4 RG |
516 | |
517 | self.assertEquals(total, misses) | |
fe1c60f2 RG |
518 | |
519 | class TestCachingCacheFull(DNSDistTest): | |
520 | ||
521 | _config_template = """ | |
522 | pc = newPacketCache(1, 86400, 1) | |
523 | getPool(""):setCache(pc) | |
524 | newServer{address="127.0.0.1:%s"} | |
525 | """ | |
526 | def testCacheFull(self): | |
527 | """ | |
528 | Cache: No new entries are cached when the cache is full | |
529 | ||
530 | """ | |
531 | misses = 0 | |
532 | name = 'cachenotfullyet.cache.tests.powerdns.com.' | |
533 | query = dns.message.make_query(name, 'A', 'IN') | |
534 | response = dns.message.make_response(query) | |
535 | rrset = dns.rrset.from_text(name, | |
536 | 3600, | |
537 | dns.rdataclass.IN, | |
538 | dns.rdatatype.A, | |
539 | '127.0.0.1') | |
540 | response.answer.append(rrset) | |
541 | ||
542 | # Miss | |
543 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
544 | self.assertTrue(receivedQuery) | |
545 | self.assertTrue(receivedResponse) | |
546 | receivedQuery.id = query.id | |
547 | self.assertEquals(query, receivedQuery) | |
548 | self.assertEquals(response, receivedResponse) | |
549 | misses += 1 | |
550 | ||
551 | # next queries should hit the cache | |
552 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
553 | self.assertEquals(receivedResponse, response) | |
554 | ||
555 | # ok, now the cache is full, send another query | |
556 | name = 'cachefull.cache.tests.powerdns.com.' | |
557 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
558 | response = dns.message.make_response(query) | |
559 | rrset = dns.rrset.from_text(name, | |
560 | 3600, | |
561 | dns.rdataclass.IN, | |
562 | dns.rdatatype.AAAA, | |
563 | '::1') | |
564 | response.answer.append(rrset) | |
565 | ||
566 | # Miss | |
567 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
568 | self.assertTrue(receivedQuery) | |
569 | self.assertTrue(receivedResponse) | |
570 | receivedQuery.id = query.id | |
571 | self.assertEquals(query, receivedQuery) | |
572 | self.assertEquals(response, receivedResponse) | |
573 | misses += 1 | |
574 | ||
575 | # next queries should NOT hit the cache | |
576 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
577 | self.assertTrue(receivedQuery) | |
578 | self.assertTrue(receivedResponse) | |
579 | receivedQuery.id = query.id | |
580 | self.assertEquals(query, receivedQuery) | |
581 | self.assertEquals(response, receivedResponse) | |
582 | misses += 1 | |
583 | ||
584 | total = 0 | |
02bbf9eb RG |
585 | for key in self._responsesCounter: |
586 | total += self._responsesCounter[key] | |
fe1c60f2 RG |
587 | |
588 | self.assertEquals(total, misses) | |
1ea747c0 RG |
589 | |
590 | class TestCachingNoStale(DNSDistTest): | |
591 | ||
592 | _consoleKey = DNSDistTest.generateConsoleKey() | |
b4f23783 | 593 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') |
1ea747c0 RG |
594 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort'] |
595 | _config_template = """ | |
596 | pc = newPacketCache(100, 86400, 1) | |
597 | getPool(""):setCache(pc) | |
598 | setKey("%s") | |
599 | controlSocket("127.0.0.1:%s") | |
600 | newServer{address="127.0.0.1:%s"} | |
601 | """ | |
602 | def testCacheNoStale(self): | |
603 | """ | |
604 | Cache: Cache entry, set backend down, we should not get a stale entry | |
605 | ||
606 | """ | |
607 | ttl = 1 | |
608 | name = 'nostale.cache.tests.powerdns.com.' | |
609 | query = dns.message.make_query(name, 'A', 'IN') | |
610 | response = dns.message.make_response(query) | |
611 | rrset = dns.rrset.from_text(name, | |
612 | 1, | |
613 | dns.rdataclass.IN, | |
614 | dns.rdatatype.A, | |
615 | '127.0.0.1') | |
616 | response.answer.append(rrset) | |
617 | ||
618 | # Miss | |
619 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
620 | self.assertTrue(receivedQuery) | |
621 | self.assertTrue(receivedResponse) | |
622 | receivedQuery.id = query.id | |
623 | self.assertEquals(query, receivedQuery) | |
624 | self.assertEquals(response, receivedResponse) | |
625 | ||
626 | # next queries should hit the cache | |
627 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
628 | self.assertEquals(receivedResponse, response) | |
629 | ||
630 | # ok, we mark the backend as down | |
631 | self.sendConsoleCommand("getServer(0):setDown()") | |
632 | # and we wait for the entry to expire | |
633 | time.sleep(ttl + 1) | |
634 | ||
635 | # we should NOT get a cached, stale, entry | |
636 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
637 | self.assertEquals(receivedResponse, None) | |
638 | ||
639 | ||
640 | class TestCachingStale(DNSDistTest): | |
641 | ||
642 | _consoleKey = DNSDistTest.generateConsoleKey() | |
b4f23783 | 643 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') |
1ea747c0 RG |
644 | _staleCacheTTL = 60 |
645 | _config_params = ['_staleCacheTTL', '_consoleKeyB64', '_consolePort', '_testServerPort'] | |
646 | _config_template = """ | |
647 | pc = newPacketCache(100, 86400, 1, %s) | |
648 | getPool(""):setCache(pc) | |
649 | setStaleCacheEntriesTTL(600) | |
650 | setKey("%s") | |
651 | controlSocket("127.0.0.1:%s") | |
652 | newServer{address="127.0.0.1:%s"} | |
653 | """ | |
654 | def testCacheStale(self): | |
655 | """ | |
656 | Cache: Cache entry, set backend down, get stale entry | |
657 | ||
658 | """ | |
659 | misses = 0 | |
660 | ttl = 1 | |
661 | name = 'stale.cache.tests.powerdns.com.' | |
662 | query = dns.message.make_query(name, 'A', 'IN') | |
663 | response = dns.message.make_response(query) | |
664 | rrset = dns.rrset.from_text(name, | |
665 | ttl, | |
666 | dns.rdataclass.IN, | |
667 | dns.rdatatype.A, | |
668 | '127.0.0.1') | |
669 | response.answer.append(rrset) | |
670 | ||
671 | # Miss | |
672 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
673 | self.assertTrue(receivedQuery) | |
674 | self.assertTrue(receivedResponse) | |
675 | receivedQuery.id = query.id | |
676 | self.assertEquals(query, receivedQuery) | |
677 | self.assertEquals(response, receivedResponse) | |
678 | misses += 1 | |
679 | ||
680 | # next queries should hit the cache | |
681 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
682 | self.assertEquals(receivedResponse, response) | |
683 | ||
684 | # ok, we mark the backend as down | |
685 | self.sendConsoleCommand("getServer(0):setDown()") | |
686 | # and we wait for the entry to expire | |
687 | time.sleep(ttl + 1) | |
688 | ||
689 | # we should get a cached, stale, entry | |
690 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
691 | self.assertEquals(receivedResponse, response) | |
692 | for an in receivedResponse.answer: | |
693 | self.assertEquals(an.ttl, self._staleCacheTTL) | |
694 | ||
695 | total = 0 | |
02bbf9eb RG |
696 | for key in self._responsesCounter: |
697 | total += self._responsesCounter[key] | |
1ea747c0 RG |
698 | |
699 | self.assertEquals(total, misses) | |
700 | ||
701 | class TestCacheManagement(DNSDistTest): | |
702 | ||
703 | _consoleKey = DNSDistTest.generateConsoleKey() | |
b4f23783 | 704 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') |
1ea747c0 RG |
705 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort'] |
706 | _config_template = """ | |
707 | pc = newPacketCache(100, 86400, 1) | |
708 | getPool(""):setCache(pc) | |
709 | setKey("%s") | |
710 | controlSocket("127.0.0.1:%s") | |
711 | newServer{address="127.0.0.1:%s"} | |
712 | """ | |
713 | def testCacheExpunge(self): | |
714 | """ | |
715 | Cache: Expunge | |
716 | ||
717 | """ | |
718 | misses = 0 | |
719 | ttl = 600 | |
720 | name = 'expunge.cache.tests.powerdns.com.' | |
721 | query = dns.message.make_query(name, 'A', 'IN') | |
722 | response = dns.message.make_response(query) | |
723 | rrset = dns.rrset.from_text(name, | |
724 | ttl, | |
725 | dns.rdataclass.IN, | |
726 | dns.rdatatype.A, | |
727 | '127.0.0.1') | |
728 | response.answer.append(rrset) | |
729 | ||
730 | # Miss | |
731 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
732 | self.assertTrue(receivedQuery) | |
733 | self.assertTrue(receivedResponse) | |
734 | receivedQuery.id = query.id | |
735 | self.assertEquals(query, receivedQuery) | |
736 | self.assertEquals(response, receivedResponse) | |
737 | misses += 1 | |
738 | ||
739 | # next queries should hit the cache | |
740 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
741 | self.assertEquals(receivedResponse, response) | |
742 | ||
743 | # remove cached entries | |
744 | self.sendConsoleCommand("getPool(\"\"):getCache():expunge(0)") | |
745 | ||
746 | # Miss | |
747 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
748 | self.assertTrue(receivedQuery) | |
749 | self.assertTrue(receivedResponse) | |
750 | receivedQuery.id = query.id | |
751 | self.assertEquals(query, receivedQuery) | |
752 | self.assertEquals(response, receivedResponse) | |
753 | misses += 1 | |
754 | ||
755 | # next queries should hit the cache again | |
756 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
757 | self.assertEquals(receivedResponse, response) | |
758 | ||
759 | total = 0 | |
02bbf9eb RG |
760 | for key in self._responsesCounter: |
761 | total += self._responsesCounter[key] | |
1ea747c0 RG |
762 | |
763 | self.assertEquals(total, misses) | |
764 | ||
765 | def testCacheExpungeByName(self): | |
766 | """ | |
767 | Cache: Expunge by name | |
768 | ||
769 | """ | |
770 | misses = 0 | |
771 | ttl = 600 | |
772 | name = 'expungebyname.cache.tests.powerdns.com.' | |
773 | query = dns.message.make_query(name, 'A', 'IN') | |
774 | response = dns.message.make_response(query) | |
775 | rrset = dns.rrset.from_text(name, | |
776 | ttl, | |
777 | dns.rdataclass.IN, | |
778 | dns.rdatatype.A, | |
779 | '127.0.0.1') | |
780 | response.answer.append(rrset) | |
781 | ||
782 | name2 = 'expungebynameother.cache.tests.powerdns.com.' | |
783 | query2 = dns.message.make_query(name2, 'A', 'IN') | |
784 | response2 = dns.message.make_response(query2) | |
785 | rrset2 = dns.rrset.from_text(name2, | |
786 | ttl, | |
787 | dns.rdataclass.IN, | |
788 | dns.rdatatype.A, | |
789 | '127.0.0.1') | |
790 | response2.answer.append(rrset2) | |
791 | ||
792 | # Miss | |
793 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
794 | self.assertTrue(receivedQuery) | |
795 | self.assertTrue(receivedResponse) | |
796 | receivedQuery.id = query.id | |
797 | self.assertEquals(query, receivedQuery) | |
798 | self.assertEquals(response, receivedResponse) | |
799 | misses += 1 | |
800 | ||
801 | # next queries should hit the cache | |
802 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
803 | self.assertEquals(receivedResponse, response) | |
804 | ||
805 | # cache another entry | |
806 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
807 | self.assertTrue(receivedQuery) | |
808 | self.assertTrue(receivedResponse) | |
809 | receivedQuery.id = query2.id | |
810 | self.assertEquals(query2, receivedQuery) | |
811 | self.assertEquals(response2, receivedResponse) | |
812 | misses += 1 | |
813 | ||
814 | # queries for name and name 2 should hit the cache | |
815 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
816 | self.assertEquals(receivedResponse, response) | |
817 | ||
818 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
819 | self.assertEquals(receivedResponse, response2) | |
820 | ||
821 | # remove cached entries from name | |
822 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"))") | |
823 | ||
824 | # Miss for name | |
825 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
826 | self.assertTrue(receivedQuery) | |
827 | self.assertTrue(receivedResponse) | |
828 | receivedQuery.id = query.id | |
829 | self.assertEquals(query, receivedQuery) | |
830 | self.assertEquals(response, receivedResponse) | |
831 | misses += 1 | |
832 | ||
833 | # next queries for name should hit the cache again | |
834 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
835 | self.assertEquals(receivedResponse, response) | |
836 | ||
837 | # queries for name2 should still hit the cache | |
838 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
839 | self.assertEquals(receivedResponse, response2) | |
840 | ||
841 | total = 0 | |
02bbf9eb RG |
842 | for key in self._responsesCounter: |
843 | total += self._responsesCounter[key] | |
1ea747c0 RG |
844 | |
845 | self.assertEquals(total, misses) | |
846 | ||
847 | def testCacheExpungeByNameAndType(self): | |
848 | """ | |
849 | Cache: Expunge by name and type | |
850 | ||
851 | """ | |
852 | misses = 0 | |
853 | ttl = 600 | |
854 | name = 'expungebynameandtype.cache.tests.powerdns.com.' | |
855 | query = dns.message.make_query(name, 'A', 'IN') | |
856 | response = dns.message.make_response(query) | |
857 | rrset = dns.rrset.from_text(name, | |
858 | ttl, | |
859 | dns.rdataclass.IN, | |
860 | dns.rdatatype.A, | |
861 | '127.0.0.1') | |
862 | response.answer.append(rrset) | |
863 | ||
864 | query2 = dns.message.make_query(name, 'AAAA', 'IN') | |
865 | response2 = dns.message.make_response(query2) | |
866 | rrset2 = dns.rrset.from_text(name, | |
867 | ttl, | |
868 | dns.rdataclass.IN, | |
869 | dns.rdatatype.AAAA, | |
870 | '::1') | |
871 | response2.answer.append(rrset2) | |
872 | ||
873 | # Miss | |
874 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
875 | self.assertTrue(receivedQuery) | |
876 | self.assertTrue(receivedResponse) | |
877 | receivedQuery.id = query.id | |
878 | self.assertEquals(query, receivedQuery) | |
879 | self.assertEquals(response, receivedResponse) | |
880 | misses += 1 | |
881 | ||
882 | # next queries should hit the cache | |
883 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
884 | self.assertEquals(receivedResponse, response) | |
885 | ||
886 | # cache another entry | |
887 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
888 | self.assertTrue(receivedQuery) | |
889 | self.assertTrue(receivedResponse) | |
890 | receivedQuery.id = query2.id | |
891 | self.assertEquals(query2, receivedQuery) | |
892 | self.assertEquals(response2, receivedResponse) | |
893 | misses += 1 | |
894 | ||
895 | # queries for name A and AAAA should hit the cache | |
896 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
897 | self.assertEquals(receivedResponse, response) | |
898 | ||
899 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
900 | self.assertEquals(receivedResponse, response2) | |
901 | ||
902 | # remove cached entries from name A | |
903 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"" + name + "\"), dnsdist.A)") | |
904 | ||
905 | # Miss for name A | |
906 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
907 | self.assertTrue(receivedQuery) | |
908 | self.assertTrue(receivedResponse) | |
909 | receivedQuery.id = query.id | |
910 | self.assertEquals(query, receivedQuery) | |
911 | self.assertEquals(response, receivedResponse) | |
912 | misses += 1 | |
913 | ||
914 | # next queries for name A should hit the cache again | |
915 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
916 | self.assertEquals(receivedResponse, response) | |
917 | ||
918 | # queries for name AAAA should still hit the cache | |
919 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
490dc586 RG |
920 | self.assertEquals(receivedResponse, response2) |
921 | ||
922 | total = 0 | |
923 | for key in self._responsesCounter: | |
924 | total += self._responsesCounter[key] | |
925 | self.assertEquals(total, misses) | |
926 | ||
927 | def testCacheExpungeByNameAndSuffix(self): | |
928 | """ | |
929 | Cache: Expunge by name | |
930 | ||
931 | """ | |
932 | misses = 0 | |
933 | ttl = 600 | |
934 | name = 'expungebyname.suffix.cache.tests.powerdns.com.' | |
935 | query = dns.message.make_query(name, 'A', 'IN') | |
936 | response = dns.message.make_response(query) | |
937 | rrset = dns.rrset.from_text(name, | |
938 | ttl, | |
939 | dns.rdataclass.IN, | |
940 | dns.rdatatype.A, | |
941 | '127.0.0.1') | |
942 | response.answer.append(rrset) | |
943 | ||
944 | name2 = 'expungebyname.suffixother.cache.tests.powerdns.com.' | |
945 | query2 = dns.message.make_query(name2, 'A', 'IN') | |
946 | response2 = dns.message.make_response(query2) | |
947 | rrset2 = dns.rrset.from_text(name2, | |
948 | ttl, | |
949 | dns.rdataclass.IN, | |
950 | dns.rdatatype.A, | |
951 | '127.0.0.1') | |
952 | response2.answer.append(rrset2) | |
953 | ||
954 | # Miss | |
955 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
956 | self.assertTrue(receivedQuery) | |
957 | self.assertTrue(receivedResponse) | |
958 | receivedQuery.id = query.id | |
959 | self.assertEquals(query, receivedQuery) | |
960 | self.assertEquals(response, receivedResponse) | |
961 | misses += 1 | |
962 | ||
963 | # next queries should hit the cache | |
964 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
965 | self.assertEquals(receivedResponse, response) | |
966 | ||
967 | # cache another entry | |
968 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
969 | self.assertTrue(receivedQuery) | |
970 | self.assertTrue(receivedResponse) | |
971 | receivedQuery.id = query2.id | |
972 | self.assertEquals(query2, receivedQuery) | |
973 | self.assertEquals(response2, receivedResponse) | |
974 | misses += 1 | |
975 | ||
976 | # queries for name and name 2 should hit the cache | |
977 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
978 | self.assertEquals(receivedResponse, response) | |
979 | ||
980 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
981 | self.assertEquals(receivedResponse, response2) | |
982 | ||
983 | # remove cached entries from name | |
984 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffix.cache.tests.powerdns.com.\"), dnsdist.ANY, true)") | |
985 | ||
986 | # Miss for name | |
987 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
988 | self.assertTrue(receivedQuery) | |
989 | self.assertTrue(receivedResponse) | |
990 | receivedQuery.id = query.id | |
991 | self.assertEquals(query, receivedQuery) | |
992 | self.assertEquals(response, receivedResponse) | |
993 | misses += 1 | |
994 | ||
995 | # next queries for name should hit the cache again | |
996 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
997 | self.assertEquals(receivedResponse, response) | |
998 | ||
999 | # queries for name2 should still hit the cache | |
1000 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
1001 | self.assertEquals(receivedResponse, response2) | |
1002 | ||
1003 | total = 0 | |
1004 | for key in self._responsesCounter: | |
1005 | total += self._responsesCounter[key] | |
1006 | ||
1007 | self.assertEquals(total, misses) | |
1008 | ||
1009 | def testCacheExpungeByNameAndTypeAndSuffix(self): | |
1010 | """ | |
1011 | Cache: Expunge by name and type | |
1012 | ||
1013 | """ | |
1014 | misses = 0 | |
1015 | ttl = 600 | |
1016 | name = 'expungebynameandtype.suffixtype.cache.tests.powerdns.com.' | |
1017 | query = dns.message.make_query(name, 'A', 'IN') | |
1018 | response = dns.message.make_response(query) | |
1019 | rrset = dns.rrset.from_text(name, | |
1020 | ttl, | |
1021 | dns.rdataclass.IN, | |
1022 | dns.rdatatype.A, | |
1023 | '127.0.0.1') | |
1024 | response.answer.append(rrset) | |
1025 | ||
1026 | query2 = dns.message.make_query(name, 'AAAA', 'IN') | |
1027 | response2 = dns.message.make_response(query2) | |
1028 | rrset2 = dns.rrset.from_text(name, | |
1029 | ttl, | |
1030 | dns.rdataclass.IN, | |
1031 | dns.rdatatype.AAAA, | |
1032 | '::1') | |
1033 | response2.answer.append(rrset2) | |
1034 | ||
1035 | # Miss | |
1036 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1037 | self.assertTrue(receivedQuery) | |
1038 | self.assertTrue(receivedResponse) | |
1039 | receivedQuery.id = query.id | |
1040 | self.assertEquals(query, receivedQuery) | |
1041 | self.assertEquals(response, receivedResponse) | |
1042 | misses += 1 | |
1043 | ||
1044 | # next queries should hit the cache | |
1045 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1046 | self.assertEquals(receivedResponse, response) | |
1047 | ||
1048 | # cache another entry | |
1049 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
1050 | self.assertTrue(receivedQuery) | |
1051 | self.assertTrue(receivedResponse) | |
1052 | receivedQuery.id = query2.id | |
1053 | self.assertEquals(query2, receivedQuery) | |
1054 | self.assertEquals(response2, receivedResponse) | |
1055 | misses += 1 | |
1056 | ||
1057 | # queries for name A and AAAA should hit the cache | |
1058 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1059 | self.assertEquals(receivedResponse, response) | |
1060 | ||
1061 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
1062 | self.assertEquals(receivedResponse, response2) | |
1063 | ||
1064 | # remove cached entries from name A | |
1065 | self.sendConsoleCommand("getPool(\"\"):getCache():expungeByName(newDNSName(\"suffixtype.cache.tests.powerdns.com.\"), dnsdist.A, true)") | |
1066 | ||
1067 | # Miss for name A | |
1068 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1069 | self.assertTrue(receivedQuery) | |
1070 | self.assertTrue(receivedResponse) | |
1071 | receivedQuery.id = query.id | |
1072 | self.assertEquals(query, receivedQuery) | |
1073 | self.assertEquals(response, receivedResponse) | |
1074 | misses += 1 | |
1075 | ||
1076 | # next queries for name A should hit the cache again | |
1077 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1078 | self.assertEquals(receivedResponse, response) | |
1079 | ||
1080 | # queries for name AAAA should still hit the cache | |
1081 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
1ea747c0 RG |
1082 | self.assertEquals(receivedResponse, response2) |
1083 | ||
1084 | total = 0 | |
02bbf9eb RG |
1085 | for key in self._responsesCounter: |
1086 | total += self._responsesCounter[key] | |
1ea747c0 | 1087 | self.assertEquals(total, misses) |
cc8cefe1 RG |
1088 | |
1089 | class TestCachingTTL(DNSDistTest): | |
1090 | ||
1091 | _maxCacheTTL = 86400 | |
1092 | _minCacheTTL = 600 | |
1093 | _config_params = ['_maxCacheTTL', '_minCacheTTL', '_testServerPort'] | |
1094 | _config_template = """ | |
1095 | pc = newPacketCache(1000, %s, %s) | |
1096 | getPool(""):setCache(pc) | |
1097 | newServer{address="127.0.0.1:%s"} | |
1098 | """ | |
1099 | def testCacheShortTTL(self): | |
1100 | """ | |
1101 | Cache: Entries with a TTL shorter than minTTL | |
1102 | ||
1103 | """ | |
1104 | misses = 0 | |
1105 | ttl = 60 | |
1106 | name = 'ttltooshort.cache.tests.powerdns.com.' | |
1107 | query = dns.message.make_query(name, 'A', 'IN') | |
1108 | response = dns.message.make_response(query) | |
1109 | rrset = dns.rrset.from_text(name, | |
1110 | ttl, | |
1111 | dns.rdataclass.IN, | |
1112 | dns.rdatatype.A, | |
1113 | '127.0.0.1') | |
1114 | response.answer.append(rrset) | |
1115 | ||
1116 | # Miss | |
1117 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1118 | self.assertTrue(receivedQuery) | |
1119 | self.assertTrue(receivedResponse) | |
1120 | receivedQuery.id = query.id | |
1121 | self.assertEquals(query, receivedQuery) | |
1122 | self.assertEquals(response, receivedResponse) | |
1123 | for an in receivedResponse.answer: | |
1124 | self.assertEquals(an.ttl, ttl) | |
1125 | misses += 1 | |
1126 | ||
1127 | # We should not have been cached | |
1128 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1129 | self.assertTrue(receivedQuery) | |
1130 | self.assertTrue(receivedResponse) | |
1131 | receivedQuery.id = query.id | |
1132 | self.assertEquals(query, receivedQuery) | |
1133 | self.assertEquals(response, receivedResponse) | |
1134 | for an in receivedResponse.answer: | |
1135 | self.assertEquals(an.ttl, ttl) | |
1136 | misses += 1 | |
1137 | ||
1138 | total = 0 | |
1139 | for key in self._responsesCounter: | |
1140 | total += self._responsesCounter[key] | |
1141 | ||
1142 | self.assertEquals(total, misses) | |
1143 | ||
a3824e43 RG |
1144 | def testCacheNXWithNoRR(self): |
1145 | """ | |
1146 | Cache: NX with no RR | |
1147 | ||
1148 | """ | |
1149 | misses = 0 | |
1150 | name = 'nxwithnorr.cache.tests.powerdns.com.' | |
1151 | query = dns.message.make_query(name, 'A', 'IN') | |
1152 | response = dns.message.make_response(query) | |
1153 | response.set_rcode(dns.rcode.NXDOMAIN) | |
1154 | ||
1155 | # Miss | |
1156 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1157 | self.assertTrue(receivedQuery) | |
1158 | self.assertTrue(receivedResponse) | |
1159 | receivedQuery.id = query.id | |
1160 | self.assertEquals(query, receivedQuery) | |
1161 | self.assertEquals(response, receivedResponse) | |
1162 | misses += 1 | |
1163 | ||
1164 | # We should not have been cached | |
1165 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1166 | self.assertTrue(receivedQuery) | |
1167 | self.assertTrue(receivedResponse) | |
1168 | receivedQuery.id = query.id | |
1169 | self.assertEquals(query, receivedQuery) | |
1170 | self.assertEquals(response, receivedResponse) | |
1171 | misses += 1 | |
1172 | ||
1173 | total = 0 | |
1174 | for key in self._responsesCounter: | |
1175 | total += self._responsesCounter[key] | |
1176 | ||
1177 | self.assertEquals(total, misses) | |
1178 | ||
cc8cefe1 RG |
1179 | class TestCachingLongTTL(DNSDistTest): |
1180 | ||
1181 | _maxCacheTTL = 2 | |
1182 | _config_params = ['_maxCacheTTL', '_testServerPort'] | |
1183 | _config_template = """ | |
1184 | pc = newPacketCache(1000, %s) | |
1185 | getPool(""):setCache(pc) | |
1186 | newServer{address="127.0.0.1:%s"} | |
1187 | """ | |
1188 | def testCacheLongTTL(self): | |
1189 | """ | |
1190 | Cache: Entries with a longer TTL than the maximum | |
1191 | ||
1192 | """ | |
1193 | misses = 0 | |
1194 | ttl = 172800 | |
1195 | name = 'longttl.cache.tests.powerdns.com.' | |
1196 | query = dns.message.make_query(name, 'A', 'IN') | |
1197 | response = dns.message.make_response(query) | |
1198 | rrset = dns.rrset.from_text(name, | |
1199 | ttl, | |
1200 | dns.rdataclass.IN, | |
1201 | dns.rdatatype.A, | |
1202 | '127.0.0.1') | |
1203 | response.answer.append(rrset) | |
1204 | ||
1205 | # Miss | |
1206 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1207 | self.assertTrue(receivedQuery) | |
1208 | self.assertTrue(receivedResponse) | |
1209 | receivedQuery.id = query.id | |
1210 | self.assertEquals(query, receivedQuery) | |
1211 | self.assertEquals(response, receivedResponse) | |
1212 | for an in receivedResponse.answer: | |
1213 | self.assertEquals(an.ttl, ttl) | |
1214 | misses += 1 | |
1215 | ||
1216 | # next queries should hit the cache | |
1217 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1218 | self.assertEquals(receivedResponse, response) | |
1219 | for an in receivedResponse.answer: | |
1220 | self.assertTrue(an.ttl <= ttl) | |
1221 | ||
1222 | time.sleep(self._maxCacheTTL + 1) | |
1223 | ||
1224 | # we should not have cached for longer than max cache | |
1225 | # so it should be a miss | |
1226 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1227 | self.assertTrue(receivedQuery) | |
1228 | self.assertTrue(receivedResponse) | |
1229 | receivedQuery.id = query.id | |
1230 | self.assertEquals(query, receivedQuery) | |
1231 | self.assertEquals(response, receivedResponse) | |
1232 | for an in receivedResponse.answer: | |
1233 | self.assertEquals(an.ttl, ttl) | |
1234 | misses += 1 | |
1235 | ||
1236 | total = 0 | |
1237 | for key in self._responsesCounter: | |
1238 | total += self._responsesCounter[key] | |
1239 | ||
1240 | self.assertEquals(total, misses) | |
2714396e RG |
1241 | |
1242 | class TestCachingFailureTTL(DNSDistTest): | |
1243 | ||
1244 | _failureCacheTTL = 2 | |
1245 | _config_params = ['_failureCacheTTL', '_testServerPort'] | |
1246 | _config_template = """ | |
1247 | pc = newPacketCache(1000, 86400, 0, %d, 60) | |
1248 | getPool(""):setCache(pc) | |
1249 | newServer{address="127.0.0.1:%s"} | |
1250 | """ | |
1251 | def testCacheServFailTTL(self): | |
1252 | """ | |
1253 | Cache: ServFail TTL | |
1254 | ||
1255 | """ | |
1256 | misses = 0 | |
1257 | name = 'servfail.failure.cache.tests.powerdns.com.' | |
1258 | query = dns.message.make_query(name, 'A', 'IN') | |
1259 | response = dns.message.make_response(query) | |
1260 | response.set_rcode(dns.rcode.SERVFAIL) | |
1261 | ||
1262 | # Miss | |
1263 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1264 | self.assertTrue(receivedQuery) | |
1265 | self.assertTrue(receivedResponse) | |
1266 | receivedQuery.id = query.id | |
1267 | self.assertEquals(query, receivedQuery) | |
1268 | self.assertEquals(response, receivedResponse) | |
1269 | misses += 1 | |
1270 | ||
1271 | # next queries should hit the cache | |
1272 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1273 | self.assertEquals(receivedResponse, response) | |
1274 | ||
1275 | time.sleep(self._failureCacheTTL + 1) | |
1276 | ||
1277 | # we should not have cached for longer than failure cache | |
1278 | # so it should be a miss | |
1279 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1280 | self.assertTrue(receivedQuery) | |
1281 | self.assertTrue(receivedResponse) | |
1282 | receivedQuery.id = query.id | |
1283 | self.assertEquals(query, receivedQuery) | |
1284 | self.assertEquals(response, receivedResponse) | |
1285 | misses += 1 | |
1286 | ||
1287 | total = 0 | |
1288 | for key in self._responsesCounter: | |
1289 | total += self._responsesCounter[key] | |
1290 | ||
1291 | self.assertEquals(total, misses) | |
1292 | ||
1293 | def testCacheRefusedTTL(self): | |
1294 | """ | |
1295 | Cache: Refused TTL | |
1296 | ||
1297 | """ | |
1298 | misses = 0 | |
1299 | name = 'refused.failure.cache.tests.powerdns.com.' | |
1300 | query = dns.message.make_query(name, 'A', 'IN') | |
1301 | response = dns.message.make_response(query) | |
1302 | response.set_rcode(dns.rcode.REFUSED) | |
1303 | ||
1304 | # Miss | |
1305 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1306 | self.assertTrue(receivedQuery) | |
1307 | self.assertTrue(receivedResponse) | |
1308 | receivedQuery.id = query.id | |
1309 | self.assertEquals(query, receivedQuery) | |
1310 | self.assertEquals(response, receivedResponse) | |
1311 | misses += 1 | |
1312 | ||
1313 | # next queries should hit the cache | |
1314 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1315 | self.assertEquals(receivedResponse, response) | |
1316 | ||
1317 | time.sleep(self._failureCacheTTL + 1) | |
1318 | ||
1319 | # we should not have cached for longer than failure cache | |
1320 | # so it should be a miss | |
1321 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1322 | self.assertTrue(receivedQuery) | |
1323 | self.assertTrue(receivedResponse) | |
1324 | receivedQuery.id = query.id | |
1325 | self.assertEquals(query, receivedQuery) | |
1326 | self.assertEquals(response, receivedResponse) | |
1327 | misses += 1 | |
1328 | ||
1329 | total = 0 | |
1330 | for key in self._responsesCounter: | |
1331 | total += self._responsesCounter[key] | |
1332 | ||
1333 | self.assertEquals(total, misses) | |
1334 | ||
1335 | def testCacheHeaderOnlyRefusedTTL(self): | |
1336 | """ | |
1337 | Cache: Header-Only Refused TTL | |
1338 | ||
1339 | """ | |
1340 | misses = 0 | |
1341 | name = 'header-only-refused.failure.cache.tests.powerdns.com.' | |
1342 | query = dns.message.make_query(name, 'A', 'IN') | |
1343 | response = dns.message.make_response(query) | |
1344 | response.set_rcode(dns.rcode.REFUSED) | |
1345 | response.question = [] | |
1346 | ||
1347 | # Miss | |
1348 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1349 | self.assertTrue(receivedQuery) | |
1350 | self.assertTrue(receivedResponse) | |
1351 | receivedQuery.id = query.id | |
1352 | self.assertEquals(query, receivedQuery) | |
1353 | self.assertEquals(response, receivedResponse) | |
1354 | misses += 1 | |
1355 | ||
1356 | # next queries should hit the cache | |
1357 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1358 | self.assertEquals(receivedResponse, response) | |
1359 | ||
1360 | time.sleep(self._failureCacheTTL + 1) | |
1361 | ||
1362 | # we should not have cached for longer than failure cache | |
1363 | # so it should be a miss | |
1364 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1365 | self.assertTrue(receivedQuery) | |
1366 | self.assertTrue(receivedResponse) | |
1367 | receivedQuery.id = query.id | |
1368 | self.assertEquals(query, receivedQuery) | |
1369 | self.assertEquals(response, receivedResponse) | |
1370 | misses += 1 | |
1371 | ||
1372 | total = 0 | |
1373 | for key in self._responsesCounter: | |
1374 | total += self._responsesCounter[key] | |
1375 | ||
1376 | self.assertEquals(total, misses) | |
2b67180c | 1377 | |
47698274 RG |
1378 | class TestCachingNegativeTTL(DNSDistTest): |
1379 | ||
1380 | _negCacheTTL = 1 | |
1381 | _config_params = ['_negCacheTTL', '_testServerPort'] | |
1382 | _config_template = """ | |
1383 | pc = newPacketCache(1000, 86400, 0, 60, 60, false, 1, true, %d) | |
1384 | getPool(""):setCache(pc) | |
1385 | newServer{address="127.0.0.1:%s"} | |
1386 | """ | |
1387 | ||
1388 | def testCacheNegativeTTLNXDomain(self): | |
1389 | """ | |
1390 | Cache: Negative TTL on NXDOMAIN | |
1391 | ||
1392 | """ | |
1393 | misses = 0 | |
1394 | name = 'nxdomain.negativettl.cache.tests.powerdns.com.' | |
1395 | query = dns.message.make_query(name, 'A', 'IN') | |
1396 | response = dns.message.make_response(query) | |
1397 | response.set_rcode(dns.rcode.NXDOMAIN) | |
1398 | soa = dns.rrset.from_text(name, | |
1399 | 60, | |
1400 | dns.rdataclass.IN, | |
1401 | dns.rdatatype.SOA, | |
1402 | 'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60') | |
1403 | response.authority.append(soa) | |
1404 | ||
1405 | # Miss | |
1406 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1407 | self.assertTrue(receivedQuery) | |
1408 | self.assertTrue(receivedResponse) | |
1409 | receivedQuery.id = query.id | |
1410 | self.assertEquals(query, receivedQuery) | |
1411 | self.assertEquals(response, receivedResponse) | |
1412 | misses += 1 | |
1413 | ||
1414 | # next queries should hit the cache | |
1415 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1416 | self.assertEquals(receivedResponse, response) | |
1417 | ||
1418 | time.sleep(self._negCacheTTL + 1) | |
1419 | ||
1420 | # we should not have cached for longer than the negativel TTL | |
1421 | # so it should be a miss | |
1422 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1423 | self.assertTrue(receivedQuery) | |
1424 | self.assertTrue(receivedResponse) | |
1425 | receivedQuery.id = query.id | |
1426 | self.assertEquals(query, receivedQuery) | |
1427 | self.assertEquals(response, receivedResponse) | |
1428 | misses += 1 | |
1429 | ||
1430 | total = 0 | |
1431 | for key in self._responsesCounter: | |
1432 | total += self._responsesCounter[key] | |
1433 | ||
1434 | self.assertEquals(total, misses) | |
1435 | ||
1436 | def testCacheNegativeTTLNoData(self): | |
1437 | """ | |
1438 | Cache: Negative TTL on NoData | |
1439 | ||
1440 | """ | |
1441 | misses = 0 | |
1442 | name = 'nodata.negativettl.cache.tests.powerdns.com.' | |
1443 | query = dns.message.make_query(name, 'A', 'IN') | |
1444 | response = dns.message.make_response(query) | |
1445 | response.set_rcode(dns.rcode.NOERROR) | |
1446 | soa = dns.rrset.from_text(name, | |
1447 | 60, | |
1448 | dns.rdataclass.IN, | |
1449 | dns.rdatatype.SOA, | |
1450 | 'ns.' + name + ' hostmaster.' + name + ' 1 3600 3600 3600 60') | |
1451 | response.authority.append(soa) | |
1452 | ||
1453 | # Miss | |
1454 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1455 | self.assertTrue(receivedQuery) | |
1456 | self.assertTrue(receivedResponse) | |
1457 | receivedQuery.id = query.id | |
1458 | self.assertEquals(query, receivedQuery) | |
1459 | self.assertEquals(response, receivedResponse) | |
1460 | misses += 1 | |
1461 | ||
1462 | # next queries should hit the cache | |
1463 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1464 | self.assertEquals(receivedResponse, response) | |
1465 | ||
1466 | time.sleep(self._negCacheTTL + 1) | |
1467 | ||
1468 | # we should not have cached for longer than the negativel TTL | |
1469 | # so it should be a miss | |
1470 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1471 | self.assertTrue(receivedQuery) | |
1472 | self.assertTrue(receivedResponse) | |
1473 | receivedQuery.id = query.id | |
1474 | self.assertEquals(query, receivedQuery) | |
1475 | self.assertEquals(response, receivedResponse) | |
1476 | misses += 1 | |
1477 | ||
1478 | total = 0 | |
1479 | for key in self._responsesCounter: | |
1480 | total += self._responsesCounter[key] | |
1481 | ||
1482 | self.assertEquals(total, misses) | |
1483 | ||
2b67180c RG |
1484 | class TestCachingDontAge(DNSDistTest): |
1485 | ||
1486 | _config_template = """ | |
1487 | pc = newPacketCache(100, 86400, 0, 60, 60, true) | |
1488 | getPool(""):setCache(pc) | |
1489 | newServer{address="127.0.0.1:%s"} | |
1490 | """ | |
1491 | def testCacheDoesntDecreaseTTL(self): | |
1492 | """ | |
1493 | Cache: Cache doesn't decrease TTL with 'don't age' set | |
1494 | ||
1495 | dnsdist is configured to cache entries but without aging the TTL, | |
1496 | we are sending one request (cache miss) and verify that the cache | |
1497 | hits don't have a decreasing TTL. | |
1498 | """ | |
1499 | ttl = 600 | |
1500 | misses = 0 | |
1501 | name = 'cachedoesntdecreasettl.cache-dont-age.tests.powerdns.com.' | |
1502 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
1503 | response = dns.message.make_response(query) | |
1504 | rrset = dns.rrset.from_text(name, | |
1505 | ttl, | |
1506 | dns.rdataclass.IN, | |
1507 | dns.rdatatype.AAAA, | |
1508 | '::1') | |
1509 | response.answer.append(rrset) | |
1510 | ||
1511 | # first query to fill the cache | |
1512 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1513 | self.assertTrue(receivedQuery) | |
1514 | self.assertTrue(receivedResponse) | |
1515 | receivedQuery.id = query.id | |
1516 | self.assertEquals(query, receivedQuery) | |
1517 | self.assertEquals(receivedResponse, response) | |
1518 | misses += 1 | |
1519 | ||
1520 | # next queries should hit the cache | |
1521 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1522 | self.assertEquals(receivedResponse, response) | |
1523 | for an in receivedResponse.answer: | |
1524 | self.assertTrue(an.ttl == ttl) | |
1525 | ||
1526 | # now we wait a bit for the TTL to decrease | |
1527 | time.sleep(1) | |
1528 | ||
1529 | # next queries should hit the cache | |
1530 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1531 | self.assertEquals(receivedResponse, response) | |
1532 | for an in receivedResponse.answer: | |
1533 | self.assertTrue(an.ttl == ttl) | |
1534 | ||
1535 | total = 0 | |
1536 | for key in self._responsesCounter: | |
1537 | total += self._responsesCounter[key] | |
1538 | ||
1539 | self.assertEquals(total, misses) | |
7e687744 RG |
1540 | |
1541 | class TestCachingECSWithoutPoolECS(DNSDistTest): | |
1542 | ||
1543 | _consoleKey = DNSDistTest.generateConsoleKey() | |
1544 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') | |
1545 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort'] | |
1546 | _config_template = """ | |
1547 | pc = newPacketCache(100, 86400, 1) | |
1548 | getPool(""):setCache(pc) | |
1549 | setKey("%s") | |
1550 | controlSocket("127.0.0.1:%d") | |
1551 | newServer{address="127.0.0.1:%d", useClientSubnet=true} | |
1552 | """ | |
1553 | ||
1554 | def testCached(self): | |
1555 | """ | |
1556 | Cache: Cached entry with ECS is a miss when no backend are available | |
1557 | """ | |
1558 | ttl = 600 | |
1559 | name = 'cached.cache-ecs-without-pool-ecs.tests.powerdns.com.' | |
1560 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
1561 | response = dns.message.make_response(query) | |
1562 | rrset = dns.rrset.from_text(name, | |
1563 | ttl, | |
1564 | dns.rdataclass.IN, | |
1565 | dns.rdatatype.AAAA, | |
1566 | '::1') | |
1567 | response.answer.append(rrset) | |
1568 | ||
1569 | # first query to fill the cache | |
1570 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1571 | self.assertTrue(receivedQuery) | |
1572 | self.assertTrue(receivedResponse) | |
1573 | receivedQuery.id = query.id | |
1574 | self.assertEquals(query, receivedQuery) | |
1575 | self.assertEquals(receivedResponse, response) | |
1576 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
1577 | self.assertTrue(receivedQuery) | |
1578 | self.assertTrue(receivedResponse) | |
1579 | receivedQuery.id = query.id | |
1580 | self.assertEquals(query, receivedQuery) | |
1581 | self.assertEquals(receivedResponse, response) | |
1582 | ||
1583 | # next queries should hit the cache | |
1584 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1585 | self.assertEquals(receivedResponse, response) | |
1586 | ||
1587 | # over TCP too | |
1588 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
1589 | self.assertEquals(receivedResponse, response) | |
1590 | ||
1591 | # we mark the backend as down | |
1592 | self.sendConsoleCommand("getServer(0):setDown()") | |
1593 | ||
1594 | # we should NOT get a cached entry since it has ECS and we haven't asked the pool | |
1595 | # to add ECS when no backend is up | |
1596 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1597 | self.assertEquals(receivedResponse, None) | |
1598 | ||
1599 | # same over TCP | |
1600 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
1601 | self.assertEquals(receivedResponse, None) | |
1602 | ||
1603 | class TestCachingECSWithPoolECS(DNSDistTest): | |
1604 | ||
1605 | _consoleKey = DNSDistTest.generateConsoleKey() | |
1606 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') | |
1607 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort'] | |
1608 | _config_template = """ | |
1609 | pc = newPacketCache(100, 86400, 1) | |
1610 | getPool(""):setCache(pc) | |
1611 | getPool(""):setECS(true) | |
1612 | setKey("%s") | |
1613 | controlSocket("127.0.0.1:%d") | |
1614 | newServer{address="127.0.0.1:%d", useClientSubnet=true} | |
1615 | """ | |
1616 | ||
1617 | def testCached(self): | |
1618 | """ | |
1619 | Cache: Cached entry with ECS is a hit when no backend are available | |
1620 | """ | |
1621 | ttl = 600 | |
1622 | name = 'cached.cache-ecs-with-pool-ecs.tests.powerdns.com.' | |
1623 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
1624 | response = dns.message.make_response(query) | |
1625 | rrset = dns.rrset.from_text(name, | |
1626 | ttl, | |
1627 | dns.rdataclass.IN, | |
1628 | dns.rdatatype.AAAA, | |
1629 | '::1') | |
1630 | response.answer.append(rrset) | |
1631 | ||
1632 | # first query to fill the cache | |
1633 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1634 | self.assertTrue(receivedQuery) | |
1635 | self.assertTrue(receivedResponse) | |
1636 | receivedQuery.id = query.id | |
1637 | self.assertEquals(query, receivedQuery) | |
1638 | self.assertEquals(receivedResponse, response) | |
1639 | (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) | |
1640 | self.assertTrue(receivedQuery) | |
1641 | self.assertTrue(receivedResponse) | |
1642 | receivedQuery.id = query.id | |
1643 | self.assertEquals(query, receivedQuery) | |
1644 | self.assertEquals(receivedResponse, response) | |
1645 | ||
1646 | # next queries should hit the cache | |
1647 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1648 | self.assertEquals(receivedResponse, response) | |
1649 | ||
1650 | # over TCP too | |
1651 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
1652 | self.assertEquals(receivedResponse, response) | |
1653 | ||
1654 | # we mark the backend as down | |
1655 | self.sendConsoleCommand("getServer(0):setDown()") | |
1656 | ||
1657 | # we should STILL get a cached entry since it has ECS and we have asked the pool | |
1658 | # to add ECS when no backend is up | |
1659 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
1660 | self.assertEquals(receivedResponse, response) | |
1661 | ||
1662 | # same over TCP | |
1663 | (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) | |
1664 | self.assertEquals(receivedResponse, response) | |
78e3ac9e RG |
1665 | |
1666 | class TestCachingCollisionNoECSParsing(DNSDistTest): | |
1667 | ||
1668 | _config_template = """ | |
1669 | pc = newPacketCache(100, 86400, 1) | |
1670 | getPool(""):setCache(pc) | |
1671 | newServer{address="127.0.0.1:%s"} | |
1672 | """ | |
1673 | ||
1674 | def testCacheCollisionNoECSParsing(self): | |
1675 | """ | |
1676 | Cache: Collision with no ECS parsing | |
1677 | """ | |
1678 | name = 'collision-no-ecs-parsing.cache.tests.powerdns.com.' | |
1679 | ecso = clientsubnetoption.ClientSubnetOption('10.0.188.3', 32) | |
1680 | query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512) | |
1681 | query.flags = dns.flags.RD | |
1682 | response = dns.message.make_response(query) | |
1683 | rrset = dns.rrset.from_text(name, | |
1684 | 3600, | |
1685 | dns.rdataclass.IN, | |
1686 | dns.rdatatype.AAAA, | |
1687 | '::1') | |
1688 | response.answer.append(rrset) | |
1689 | ||
1690 | # first query should to fill the cache | |
1691 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1692 | self.assertTrue(receivedQuery) | |
1693 | self.assertTrue(receivedResponse) | |
1694 | receivedQuery.id = query.id | |
1695 | self.assertEquals(query, receivedQuery) | |
1696 | self.assertEquals(receivedResponse, response) | |
1697 | ||
1698 | # second query will hash to the same key, triggering a collision which | |
1699 | # will not be detected because the qname, qtype, qclass and flags will | |
1700 | # match and EDNS Client Subnet parsing has not been enabled | |
1701 | ecso2 = clientsubnetoption.ClientSubnetOption('10.0.192.138', 32) | |
1702 | query2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512) | |
1703 | query2.flags = dns.flags.RD | |
1704 | (_, receivedResponse) = self.sendUDPQuery(query2, response=None, useQueue=False) | |
1705 | receivedResponse.id = response.id | |
1706 | self.assertEquals(receivedResponse, response) | |
1707 | ||
1708 | class TestCachingCollisionWithECSParsing(DNSDistTest): | |
1709 | ||
1710 | _config_template = """ | |
1711 | pc = newPacketCache(100, 86400, 1, 60, 60, false, 1, true, 3600, true) | |
1712 | getPool(""):setCache(pc) | |
1713 | newServer{address="127.0.0.1:%s"} | |
1714 | """ | |
1715 | ||
1716 | def testCacheCollisionWithECSParsing(self): | |
1717 | """ | |
1718 | Cache: Collision with ECS parsing | |
1719 | """ | |
1720 | name = 'collision-with-ecs-parsing.cache.tests.powerdns.com.' | |
1721 | ecso = clientsubnetoption.ClientSubnetOption('10.0.115.61', 32) | |
1722 | query = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso], payload=512) | |
1723 | query.flags = dns.flags.RD | |
1724 | response = dns.message.make_response(query) | |
1725 | rrset = dns.rrset.from_text(name, | |
1726 | 3600, | |
1727 | dns.rdataclass.IN, | |
1728 | dns.rdatatype.AAAA, | |
1729 | '::1') | |
1730 | response.answer.append(rrset) | |
1731 | ||
1732 | # first query should to fill the cache | |
1733 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) | |
1734 | self.assertTrue(receivedQuery) | |
1735 | self.assertTrue(receivedResponse) | |
1736 | receivedQuery.id = query.id | |
1737 | self.assertEquals(query, receivedQuery) | |
1738 | self.assertEquals(receivedResponse, response) | |
1739 | ||
1740 | # second query will hash to the same key, triggering a collision which | |
1741 | # _will_ be detected this time because the qname, qtype, qclass and flags will | |
1742 | # match but EDNS Client Subnet parsing is now enabled and will detect the issue | |
1743 | ecso2 = clientsubnetoption.ClientSubnetOption('10.0.143.21', 32) | |
1744 | query2 = dns.message.make_query(name, 'AAAA', 'IN', use_edns=True, options=[ecso2], payload=512) | |
1745 | query2.flags = dns.flags.RD | |
1746 | response2 = dns.message.make_response(query2) | |
1747 | rrset = dns.rrset.from_text(name, | |
1748 | 3600, | |
1749 | dns.rdataclass.IN, | |
1750 | dns.rdatatype.AAAA, | |
1751 | '2001:DB8::1') | |
1752 | response2.answer.append(rrset) | |
1753 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query2, response2) | |
1754 | self.assertEquals(receivedResponse, response2) |