]>
git.ipfire.org Git - thirdparty/pdns.git/blob - regression-tests.dnsdist/test_Caching.py
5 import clientsubnetoption
7 from dnsdisttests
import DNSDistTest
9 class TestCaching ( DNSDistTest
):
11 _config_template
= """
12 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
13 getPool(""):setCache(pc)
14 addAction(makeRule("nocache.cache.tests.powerdns.com."), SetSkipCacheAction())
15 addResponseAction(makeRule("nocache-response.cache.tests.powerdns.com."), SetSkipCacheResponseAction())
16 function skipViaLua(dq)
18 return DNSAction.None, ""
20 addAction("nocachevialua.cache.tests.powerdns.com.", LuaAction(skipViaLua))
21 newServer{address="127.0.0.1: %d "}
26 Cache: Served from cache
28 dnsdist is configured to cache entries, we are sending several
29 identical requests and checking that the backend only receive
33 name
= 'cached.cache.tests.powerdns.com.'
34 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
35 response
= dns
. message
. make_response ( query
)
36 rrset
= dns
. rrset
. from_text ( name
,
41 response
. answer
. append ( rrset
)
43 # first query to fill the cache
44 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
45 self
. assertTrue ( receivedQuery
)
46 self
. assertTrue ( receivedResponse
)
47 receivedQuery
. id = query
. id
48 self
. assertEqual ( query
, receivedQuery
)
49 self
. assertEqual ( receivedResponse
, response
)
51 for _
in range ( numberOfQueries
):
52 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
53 self
. assertEqual ( receivedResponse
, response
)
56 for key
in self
._ responsesCounter
:
57 total
+= self
._ responsesCounter
[ key
]
58 TestCaching
._ responsesCounter
[ key
] = 0
60 self
. assertEqual ( total
, 1 )
62 # TCP should not be cached
63 # first query to fill the cache
64 ( receivedQuery
, receivedResponse
) = self
. sendTCPQuery ( query
, response
)
65 self
. assertTrue ( receivedQuery
)
66 self
. assertTrue ( receivedResponse
)
67 receivedQuery
. id = query
. id
68 self
. assertEqual ( query
, receivedQuery
)
69 self
. assertEqual ( receivedResponse
, response
)
71 for _
in range ( numberOfQueries
):
72 ( _
, receivedResponse
) = self
. sendTCPQuery ( query
, response
= None , useQueue
= False )
73 self
. assertEqual ( receivedResponse
, response
)
76 for key
in self
._ responsesCounter
:
77 total
+= self
._ responsesCounter
[ key
]
78 TestCaching
._ responsesCounter
[ key
] = 0
80 self
. assertEqual ( total
, 1 )
82 def testDOCached ( self
):
84 Cache: Served from cache, query has DO bit set
86 dnsdist is configured to cache entries, we are sending several
87 identical requests and checking that the backend only receive
91 name
= 'cached-do.cache.tests.powerdns.com.'
92 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , want_dnssec
= True )
93 response
= dns
. message
. make_response ( query
)
94 rrset
= dns
. rrset
. from_text ( name
,
99 response
. answer
. append ( rrset
)
101 # first query to fill the cache
102 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
103 self
. assertTrue ( receivedQuery
)
104 self
. assertTrue ( receivedResponse
)
105 receivedQuery
. id = query
. id
106 self
. assertEqual ( query
, receivedQuery
)
107 self
. assertEqual ( receivedResponse
, response
)
109 for _
in range ( numberOfQueries
):
110 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
111 self
. assertEqual ( receivedResponse
, response
)
114 for key
in self
._ responsesCounter
:
115 total
+= self
._ responsesCounter
[ key
]
116 TestCaching
._ responsesCounter
[ key
] = 0
118 self
. assertEqual ( total
, 1 )
120 # TCP should not be cached
121 # first query to fill the cache
122 ( receivedQuery
, receivedResponse
) = self
. sendTCPQuery ( query
, response
)
123 self
. assertTrue ( receivedQuery
)
124 self
. assertTrue ( receivedResponse
)
125 receivedQuery
. id = query
. id
126 self
. assertEqual ( query
, receivedQuery
)
127 self
. assertEqual ( receivedResponse
, response
)
129 for _
in range ( numberOfQueries
):
130 ( _
, receivedResponse
) = self
. sendTCPQuery ( query
, response
= None , useQueue
= False )
131 self
. assertEqual ( receivedResponse
, response
)
134 for key
in self
._ responsesCounter
:
135 total
+= self
._ responsesCounter
[ key
]
136 TestCaching
._ responsesCounter
[ key
] = 0
138 self
. assertEqual ( total
, 1 )
140 def testSkipCache ( self
):
142 Cache: SetSkipCacheAction
144 dnsdist is configured to not cache entries for nocache.cache.tests.powerdns.com.
145 we are sending several requests and checking that the backend get them all.
147 name
= 'nocache.cache.tests.powerdns.com.'
149 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
150 response
= dns
. message
. make_response ( query
)
151 rrset
= dns
. rrset
. from_text ( name
,
156 response
. answer
. append ( rrset
)
158 for _
in range ( numberOfQueries
):
159 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
160 sender
= getattr ( self
, method
)
161 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
162 self
. assertTrue ( receivedQuery
)
163 self
. assertTrue ( receivedResponse
)
164 receivedQuery
. id = query
. id
165 self
. assertEqual ( query
, receivedQuery
)
166 self
. assertEqual ( receivedResponse
, response
)
168 for key
in self
._ responsesCounter
:
169 value
= self
._ responsesCounter
[ key
]
170 self
. assertEqual ( value
, numberOfQueries
)
172 def testSkipCacheViaLua ( self
):
174 Cache: SkipCache via Lua
176 dnsdist is configured to not cache entries for nocachevialua.cache.tests.powerdns.com.
177 we are sending several requests and checking that the backend get them all.
179 name
= 'nocachevialua.cache.tests.powerdns.com.'
181 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
182 response
= dns
. message
. make_response ( query
)
183 rrset
= dns
. rrset
. from_text ( name
,
188 response
. answer
. append ( rrset
)
190 for _
in range ( numberOfQueries
):
191 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
192 sender
= getattr ( self
, method
)
193 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
194 self
. assertTrue ( receivedQuery
)
195 self
. assertTrue ( receivedResponse
)
196 receivedQuery
. id = query
. id
197 self
. assertEqual ( query
, receivedQuery
)
198 self
. assertEqual ( receivedResponse
, response
)
200 for key
in self
._ responsesCounter
:
201 value
= self
._ responsesCounter
[ key
]
202 self
. assertEqual ( value
, numberOfQueries
)
204 def testSkipCacheResponse ( self
):
206 Cache: SetSkipCacheResponseAction
208 dnsdist is configured to not cache entries for answer matching nocache-response.cache.tests.powerdns.com.
209 we are sending several requests and checking that the backend get them all.
211 name
= 'nocache-response.cache.tests.powerdns.com.'
213 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
214 response
= dns
. message
. make_response ( query
)
215 rrset
= dns
. rrset
. from_text ( name
,
220 response
. answer
. append ( rrset
)
222 for _
in range ( numberOfQueries
):
223 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
224 sender
= getattr ( self
, method
)
225 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
226 self
. assertTrue ( receivedQuery
)
227 self
. assertTrue ( receivedResponse
)
228 receivedQuery
. id = query
. id
229 self
. assertEqual ( query
, receivedQuery
)
230 self
. assertEqual ( receivedResponse
, response
)
232 for key
in self
._ responsesCounter
:
233 value
= self
._ responsesCounter
[ key
]
234 self
. assertEqual ( value
, numberOfQueries
)
236 def testAXFRResponse ( self
):
238 Cache: AXFR should not be cached
240 dnsdist should not cache responses to AXFR queries.
242 name
= 'axfr.cache.tests.powerdns.com.'
243 query
= dns
. message
. make_query ( name
, 'AXFR' , 'IN' )
244 response
= dns
. message
. make_response ( query
)
245 soa
= dns
. rrset
. from_text ( name
,
249 'ns.' + name
+ ' hostmaster.' + name
+ ' 1 3600 3600 3600 60' )
250 response
. answer
. append ( soa
)
251 response
. answer
. append ( dns
. rrset
. from_text ( name
,
256 response
. answer
. append ( soa
)
259 for _
in range ( numberOfQueries
):
260 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
261 sender
= getattr ( self
, method
)
262 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
263 self
. assertTrue ( receivedQuery
)
264 self
. assertTrue ( receivedResponse
)
265 receivedQuery
. id = query
. id
266 self
. assertEqual ( query
, receivedQuery
)
267 self
. assertEqual ( receivedResponse
, response
)
269 for key
in self
._ responsesCounter
:
270 value
= self
._ responsesCounter
[ key
]
271 self
. assertEqual ( value
, numberOfQueries
)
273 def testIXFRResponse ( self
):
275 Cache: IXFR should not be cached
277 dnsdist should not cache responses to IXFR queries.
279 name
= 'ixfr.cache.tests.powerdns.com.'
280 query
= dns
. message
. make_query ( name
, 'IXFR' , 'IN' )
281 response
= dns
. message
. make_response ( query
)
282 soa
= dns
. rrset
. from_text ( name
,
286 'ns.' + name
+ ' hostmaster.' + name
+ ' 1 3600 3600 3600 60' )
287 response
. answer
. append ( soa
)
288 response
. answer
. append ( dns
. rrset
. from_text ( name
,
293 response
. answer
. append ( soa
)
296 for _
in range ( numberOfQueries
):
297 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
298 sender
= getattr ( self
, method
)
299 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
300 self
. assertTrue ( receivedQuery
)
301 self
. assertTrue ( receivedResponse
)
302 receivedQuery
. id = query
. id
303 self
. assertEqual ( query
, receivedQuery
)
304 self
. assertEqual ( receivedResponse
, response
)
306 for key
in self
._ responsesCounter
:
307 value
= self
._ responsesCounter
[ key
]
308 self
. assertEqual ( value
, numberOfQueries
)
310 def testCacheExpiration ( self
):
312 Cache: Cache expiration
314 dnsdist is configured to cache entries, we are sending one request
315 (cache miss) with a very short TTL, checking that the next requests
316 are cached. Then we wait for the TTL to expire, check that the
317 next request is a miss but the following one a hit.
321 name
= 'cacheexpiration.cache.tests.powerdns.com.'
322 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
323 response
= dns
. message
. make_response ( query
)
324 rrset
= dns
. rrset
. from_text ( name
,
329 response
. answer
. append ( rrset
)
331 # first query to fill the cache
332 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
333 self
. assertTrue ( receivedQuery
)
334 self
. assertTrue ( receivedResponse
)
335 receivedQuery
. id = query
. id
336 self
. assertEqual ( query
, receivedQuery
)
337 self
. assertEqual ( receivedResponse
, response
)
340 # next queries should hit the cache
341 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
342 self
. assertEqual ( receivedResponse
, response
)
344 # now we wait a bit for the cache entry to expire
347 # next query should be a miss, fill the cache again
348 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
349 self
. assertTrue ( receivedQuery
)
350 self
. assertTrue ( receivedResponse
)
351 receivedQuery
. id = query
. id
352 self
. assertEqual ( query
, receivedQuery
)
353 self
. assertEqual ( receivedResponse
, response
)
356 # following queries should hit the cache again
357 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
358 self
. assertEqual ( receivedResponse
, response
)
361 for key
in self
._ responsesCounter
:
362 total
+= self
._ responsesCounter
[ key
]
364 self
. assertEqual ( total
, misses
)
366 def testCacheExpirationDifferentSets ( self
):
368 Cache: Cache expiration with different sets
370 dnsdist is configured to cache entries, we are sending one request
371 (cache miss) whose response has a long and a very short TTL,
372 checking that the next requests are cached. Then we wait for the
373 short TTL to expire, check that the
374 next request is a miss but the following one a hit.
378 name
= 'cacheexpirationdifferentsets.cache.tests.powerdns.com.'
379 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
380 response
= dns
. message
. make_response ( query
)
381 rrset
= dns
. rrset
. from_text ( name
,
385 'cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.' )
386 response
. answer
. append ( rrset
)
387 rrset
= dns
. rrset
. from_text ( 'cname.cacheexpirationdifferentsets.cache.tests.powerdns.com.' ,
392 response
. additional
. append ( rrset
)
394 # first query to fill the cache
395 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
396 self
. assertTrue ( receivedQuery
)
397 self
. assertTrue ( receivedResponse
)
398 receivedQuery
. id = query
. id
399 self
. assertEqual ( query
, receivedQuery
)
400 self
. assertEqual ( receivedResponse
, response
)
403 # next queries should hit the cache
404 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
405 self
. assertEqual ( receivedResponse
, response
)
407 # now we wait a bit for the cache entry to expire
410 # next query should be a miss, fill the cache again
411 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
412 self
. assertTrue ( receivedQuery
)
413 self
. assertTrue ( receivedResponse
)
414 receivedQuery
. id = query
. id
415 self
. assertEqual ( query
, receivedQuery
)
416 self
. assertEqual ( receivedResponse
, response
)
419 # following queries should hit the cache again
420 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
421 self
. assertEqual ( receivedResponse
, response
)
424 for key
in self
._ responsesCounter
:
425 total
+= self
._ responsesCounter
[ key
]
427 self
. assertEqual ( total
, misses
)
429 def testCacheDecreaseTTL ( self
):
431 Cache: Cache decreases TTL
433 dnsdist is configured to cache entries, we are sending one request
434 (cache miss) and verify that the cache hits have a decreasing TTL.
438 name
= 'cachedecreasettl.cache.tests.powerdns.com.'
439 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
440 response
= dns
. message
. make_response ( query
)
441 rrset
= dns
. rrset
. from_text ( name
,
446 response
. answer
. append ( rrset
)
448 # first query to fill the cache
449 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
450 self
. assertTrue ( receivedQuery
)
451 self
. assertTrue ( receivedResponse
)
452 receivedQuery
. id = query
. id
453 self
. assertEqual ( query
, receivedQuery
)
454 self
. assertEqual ( receivedResponse
, response
)
457 # next queries should hit the cache
458 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
459 self
. assertEqual ( receivedResponse
, response
)
460 for an
in receivedResponse
. answer
:
461 self
. assertTrue ( an
. ttl
<= ttl
)
463 # now we wait a bit for the TTL to decrease
466 # next queries should hit the cache
467 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
468 self
. assertEqual ( receivedResponse
, response
)
469 for an
in receivedResponse
. answer
:
470 self
. assertTrue ( an
. ttl
< ttl
)
473 for key
in self
._ responsesCounter
:
474 total
+= self
._ responsesCounter
[ key
]
476 self
. assertEqual ( total
, misses
)
478 def testCacheDifferentCase ( self
):
480 Cache: Cache matches different case
482 dnsdist is configured to cache entries, we are sending one request
483 (cache miss) and verify that the same one with a different case
487 name
= 'cachedifferentcase.cache.tests.powerdns.com.'
488 differentCaseName
= 'CacheDifferentCASE.cache.tests.powerdns.com.'
489 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
490 differentCaseQuery
= dns
. message
. make_query ( differentCaseName
, 'AAAA' , 'IN' )
491 response
= dns
. message
. make_response ( query
)
492 differentCaseResponse
= dns
. message
. make_response ( differentCaseQuery
)
493 rrset
= dns
. rrset
. from_text ( name
,
498 response
. answer
. append ( rrset
)
499 differentCaseResponse
. answer
. append ( rrset
)
501 # first query to fill the cache
502 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
503 self
. assertTrue ( receivedQuery
)
504 self
. assertTrue ( receivedResponse
)
505 receivedQuery
. id = query
. id
506 self
. assertEqual ( query
, receivedQuery
)
507 self
. assertEqual ( receivedResponse
, response
)
509 # different case query should still hit the cache
510 ( _
, receivedResponse
) = self
. sendUDPQuery ( differentCaseQuery
, response
= None , useQueue
= False )
511 self
. assertEqual ( receivedResponse
, differentCaseResponse
)
513 def testLargeAnswer ( self
):
515 Cache: Check that we can cache (and retrieve) large answers
517 We should be able to get answers as large as 4096 bytes
520 name
= 'large-answer.cache.tests.powerdns.com.'
521 query
= dns
. message
. make_query ( name
, 'TXT' , 'IN' )
522 response
= dns
. message
. make_response ( query
)
523 # we prepare a large answer
527 content
= content
+ ', '
528 content
= content
+ ( str ( i
)* 50 )
530 content
= content
+ 'A' * 42
532 rrset
= dns
. rrset
. from_text ( name
,
537 response
. answer
. append ( rrset
)
538 self
. assertEqual ( len ( response
. to_wire ()), 4096 )
540 # first query to fill the cache
541 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
542 self
. assertTrue ( receivedQuery
)
543 self
. assertTrue ( receivedResponse
)
544 receivedQuery
. id = query
. id
545 self
. assertEqual ( query
, receivedQuery
)
546 self
. assertEqual ( receivedResponse
, response
)
548 for _
in range ( numberOfQueries
):
549 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
550 self
. assertEqual ( receivedResponse
, response
)
553 for key
in self
._ responsesCounter
:
554 total
+= self
._ responsesCounter
[ key
]
555 TestCaching
._ responsesCounter
[ key
] = 0
557 self
. assertEqual ( total
, 1 )
559 # TCP should not be cached
560 # first query to fill the cache
561 ( receivedQuery
, receivedResponse
) = self
. sendTCPQuery ( query
, response
)
562 self
. assertTrue ( receivedQuery
)
563 self
. assertTrue ( receivedResponse
)
564 receivedQuery
. id = query
. id
565 self
. assertEqual ( query
, receivedQuery
)
566 self
. assertEqual ( receivedResponse
, response
)
568 for _
in range ( numberOfQueries
):
569 ( _
, receivedResponse
) = self
. sendTCPQuery ( query
, response
= None , useQueue
= False )
570 self
. assertEqual ( receivedResponse
, response
)
573 for key
in self
._ responsesCounter
:
574 total
+= self
._ responsesCounter
[ key
]
575 TestCaching
._ responsesCounter
[ key
] = 0
577 self
. assertEqual ( total
, 1 )
579 def testCacheDifferentCookies ( self
):
581 Cache: The content of cookies should be ignored by the cache
584 name
= 'cache-different-cookies.cache.tests.powerdns.com.'
585 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
586 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
])
587 response
= dns
. message
. make_response ( query
)
588 rrset
= dns
. rrset
. from_text ( name
,
593 response
. answer
. append ( rrset
)
595 # first query to fill the cache
596 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
597 self
. assertTrue ( receivedQuery
)
598 self
. assertTrue ( receivedResponse
)
599 receivedQuery
. id = query
. id
600 self
. assertEqual ( query
, receivedQuery
)
601 self
. assertEqual ( receivedResponse
, response
)
603 eco
= cookiesoption
. CookiesOption ( b
'badc0fee' , b
'badc0fee' )
604 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
])
605 # second query should be served from the cache
606 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
607 receivedResponse
. id = response
. id
608 self
. assertEqual ( receivedResponse
, response
)
610 def testCacheCookies ( self
):
612 Cache: A query with a cookie should not match one without any cookie
615 name
= 'cache-cookie.cache.tests.powerdns.com.'
616 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
617 query
= dns
. message
. make_query ( name
, 'A' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
])
618 response
= dns
. message
. make_response ( query
)
619 rrset
= dns
. rrset
. from_text ( name
,
624 response
. answer
. append ( rrset
)
626 # first query to fill the cache
627 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
628 self
. assertTrue ( receivedQuery
)
629 self
. assertTrue ( receivedResponse
)
630 receivedQuery
. id = query
. id
631 self
. assertEqual ( query
, receivedQuery
)
632 self
. assertEqual ( receivedResponse
, response
)
634 query
= dns
. message
. make_query ( name
, 'A' , 'IN' , use_edns
= True , payload
= 4096 , options
=[])
635 response
= dns
. message
. make_response ( query
)
636 rrset
= dns
. rrset
. from_text ( name
,
641 response
. answer
. append ( rrset
)
642 # second query should NOT be served from the cache
643 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
644 self
. assertTrue ( receivedQuery
)
645 self
. assertTrue ( receivedResponse
)
646 receivedQuery
. id = query
. id
647 self
. assertEqual ( query
, receivedQuery
)
648 self
. assertEqual ( receivedResponse
, response
)
650 def testCacheSameCookieDifferentECS ( self
):
652 Cache: The content of cookies should be ignored by the cache but not the ECS one
655 name
= 'cache-different-cookies-different-ecs.cache.tests.powerdns.com.'
656 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
657 ecso
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.1' , 32 )
658 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
, ecso
])
659 response
= dns
. message
. make_response ( query
)
660 rrset
= dns
. rrset
. from_text ( name
,
665 response
. answer
. append ( rrset
)
667 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
668 self
. assertTrue ( receivedQuery
)
669 self
. assertTrue ( receivedResponse
)
670 receivedQuery
. id = query
. id
671 self
. assertEqual ( query
, receivedQuery
)
672 self
. assertEqual ( receivedResponse
, response
)
674 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
675 ecso
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.2' , 32 )
676 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
, ecso
])
677 response
= dns
. message
. make_response ( query
)
678 rrset
= dns
. rrset
. from_text ( name
,
683 response
. answer
. append ( rrset
)
685 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
686 self
. assertTrue ( receivedQuery
)
687 self
. assertTrue ( receivedResponse
)
688 receivedQuery
. id = query
. id
689 self
. assertEqual ( query
, receivedQuery
)
690 self
. assertEqual ( receivedResponse
, response
)
692 class TestCachingHashingOptions ( DNSDistTest
):
694 _config_template
= """
695 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, cookieHashing=true, skipOptions= {8} })
696 getPool(""):setCache(pc)
697 newServer{address="127.0.0.1: %d "}
700 def testCacheDifferentECSSameCookie ( self
):
702 Cache: ECS should be ignored by the cache even if cookie is present
705 name
= 'cache-different-ecs.cache.tests.powerdns.com.'
706 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
707 ecso
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.2' , 32 )
708 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
, ecso
])
709 response
= dns
. message
. make_response ( query
)
710 rrset
= dns
. rrset
. from_text ( name
,
715 response
. answer
. append ( rrset
)
717 # first query to fill the cache
718 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
719 self
. assertTrue ( receivedQuery
)
720 self
. assertTrue ( receivedResponse
)
721 receivedQuery
. id = query
. id
722 self
. assertEqual ( query
, receivedQuery
)
723 self
. assertEqual ( receivedResponse
, response
)
725 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
726 ecso
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.1' , 32 )
727 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
, ecso
])
728 # second query should be served from the cache
729 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
730 receivedResponse
. id = response
. id
731 self
. assertEqual ( receivedResponse
, response
)
733 class TestCachingHashingCookies ( DNSDistTest
):
735 _config_template
= """
736 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, cookieHashing=true})
737 getPool(""):setCache(pc)
738 newServer{address="127.0.0.1: %d "}
741 def testCached ( self
):
743 Cache: Served from cache
745 dnsdist is configured to cache entries, we are sending several
746 identical requests and checking that the backend only receive
750 name
= 'cached.cache.tests.powerdns.com.'
751 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
752 response
= dns
. message
. make_response ( query
)
753 rrset
= dns
. rrset
. from_text ( name
,
758 response
. answer
. append ( rrset
)
760 # first query to fill the cache
761 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
762 self
. assertTrue ( receivedQuery
)
763 self
. assertTrue ( receivedResponse
)
764 receivedQuery
. id = query
. id
765 self
. assertEqual ( query
, receivedQuery
)
766 self
. assertEqual ( receivedResponse
, response
)
768 for _
in range ( numberOfQueries
):
769 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
770 self
. assertEqual ( receivedResponse
, response
)
773 for key
in self
._ responsesCounter
:
774 total
+= self
._ responsesCounter
[ key
]
775 TestCaching
._ responsesCounter
[ key
] = 0
777 self
. assertEqual ( total
, 1 )
779 # TCP should not be cached
780 # first query to fill the cache
781 ( receivedQuery
, receivedResponse
) = self
. sendTCPQuery ( query
, response
)
782 self
. assertTrue ( receivedQuery
)
783 self
. assertTrue ( receivedResponse
)
784 receivedQuery
. id = query
. id
785 self
. assertEqual ( query
, receivedQuery
)
786 self
. assertEqual ( receivedResponse
, response
)
788 for _
in range ( numberOfQueries
):
789 ( _
, receivedResponse
) = self
. sendTCPQuery ( query
, response
= None , useQueue
= False )
790 self
. assertEqual ( receivedResponse
, response
)
793 for key
in self
._ responsesCounter
:
794 total
+= self
._ responsesCounter
[ key
]
795 TestCaching
._ responsesCounter
[ key
] = 0
797 self
. assertEqual ( total
, 1 )
800 def testCacheDifferentCookies ( self
):
802 Cache: The content of cookies should NOT be ignored by the cache (cookieHashing is set)
805 name
= 'cache-different-cookies.cache-cookie-hashing.tests.powerdns.com.'
806 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
807 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
])
808 response
= dns
. message
. make_response ( query
)
809 rrset
= dns
. rrset
. from_text ( name
,
814 response
. answer
. append ( rrset
)
816 # first query to fill the cache
817 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
818 self
. assertTrue ( receivedQuery
)
819 self
. assertTrue ( receivedResponse
)
820 receivedQuery
. id = query
. id
821 self
. assertEqual ( query
, receivedQuery
)
822 self
. assertEqual ( receivedResponse
, response
)
824 eco
= cookiesoption
. CookiesOption ( b
'badc0fee' , b
'badc0fee' )
825 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
])
826 differentResponse
= dns
. message
. make_response ( query
)
827 rrset
= dns
. rrset
. from_text ( name
,
832 differentResponse
. answer
. append ( rrset
)
833 # second query should NOT be served from the cache
834 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, differentResponse
)
835 self
. assertTrue ( receivedQuery
)
836 self
. assertTrue ( receivedResponse
)
837 receivedQuery
. id = query
. id
838 self
. assertEqual ( query
, receivedQuery
)
839 self
. assertEqual ( receivedResponse
, differentResponse
)
840 self
. assertNotEqual ( receivedResponse
, response
)
842 def testCacheCookies ( self
):
844 Cache: A query with a cookie should not match one without any cookie (cookieHashing=true)
847 name
= 'cache-cookie.cache-cookie-hashing.tests.powerdns.com.'
848 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
849 query
= dns
. message
. make_query ( name
, 'A' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
])
850 response
= dns
. message
. make_response ( query
)
851 rrset
= dns
. rrset
. from_text ( name
,
856 response
. answer
. append ( rrset
)
858 # first query to fill the cache
859 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
860 self
. assertTrue ( receivedQuery
)
861 self
. assertTrue ( receivedResponse
)
862 receivedQuery
. id = query
. id
863 self
. assertEqual ( query
, receivedQuery
)
864 self
. assertEqual ( receivedResponse
, response
)
866 query
= dns
. message
. make_query ( name
, 'A' , 'IN' , use_edns
= True , payload
= 4096 , options
=[])
867 response
= dns
. message
. make_response ( query
)
868 rrset
= dns
. rrset
. from_text ( name
,
873 response
. answer
. append ( rrset
)
874 # second query should NOT be served from the cache
875 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
876 self
. assertTrue ( receivedQuery
)
877 self
. assertTrue ( receivedResponse
)
878 receivedQuery
. id = query
. id
879 self
. assertEqual ( query
, receivedQuery
)
880 self
. assertEqual ( receivedResponse
, response
)
882 def testCacheSameCookieDifferentECS ( self
):
884 Cache: The content of cookies should NOT be ignored by the cache (cookieHashing=true), even with ECS there
887 name
= 'cache-different-cookies-different-ecs.cache-cookie-hashing.tests.powerdns.com.'
888 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
889 ecso
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.1' , 32 )
890 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
, ecso
])
891 response
= dns
. message
. make_response ( query
)
892 rrset
= dns
. rrset
. from_text ( name
,
897 response
. answer
. append ( rrset
)
899 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
900 self
. assertTrue ( receivedQuery
)
901 self
. assertTrue ( receivedResponse
)
902 receivedQuery
. id = query
. id
903 self
. assertEqual ( query
, receivedQuery
)
904 self
. assertEqual ( receivedResponse
, response
)
906 eco
= cookiesoption
. CookiesOption ( b
'deadbeef' , b
'deadbeef' )
907 ecso
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.2' , 32 )
908 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , payload
= 4096 , options
=[ eco
, ecso
])
909 response
= dns
. message
. make_response ( query
)
910 rrset
= dns
. rrset
. from_text ( name
,
915 response
. answer
. append ( rrset
)
917 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
918 self
. assertTrue ( receivedQuery
)
919 self
. assertTrue ( receivedResponse
)
920 receivedQuery
. id = query
. id
921 self
. assertEqual ( query
, receivedQuery
)
922 self
. assertEqual ( receivedResponse
, response
)
924 class TestTempFailureCacheTTLAction ( DNSDistTest
):
926 _extraStartupSleep
= 1
927 _config_template
= """
928 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
929 getPool(""):setCache(pc)
930 addAction("servfail.cache.tests.powerdns.com.", SetTempFailureCacheTTLAction(1))
931 newServer{address="127.0.0.1: %d "}
934 def testTempFailureCacheTTLAction ( self
):
936 Cache: When a TempFailure TTL is set, it should be honored
938 dnsdist is configured to cache packets, plus a specific qname is
939 set up with a lower TempFailure Cache TTL. we are sending one request
940 (cache miss) and verify that the cache is hit for the following query,
941 but the TTL then expires before the larger "good" packetcache TTL.
943 name
= 'servfail.cache.tests.powerdns.com.'
944 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
945 response
= dns
. message
. make_response ( query
)
946 response
. set_rcode ( dns
. rcode
. SERVFAIL
)
948 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
949 self
. assertTrue ( receivedQuery
)
950 self
. assertTrue ( receivedResponse
)
951 receivedQuery
. id = query
. id
952 self
. assertEqual ( query
, receivedQuery
)
953 self
. assertEqual ( receivedResponse
, response
)
955 # next query should hit the cache
956 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
957 self
. assertFalse ( receivedQuery
)
958 self
. assertTrue ( receivedResponse
)
959 self
. assertEqual ( receivedResponse
, response
)
961 # now we wait a bit for the Failure-Cache TTL to expire
964 # next query should NOT hit the cache
965 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
966 self
. assertTrue ( receivedQuery
)
967 self
. assertTrue ( receivedResponse
)
968 self
. assertEqual ( receivedResponse
, response
)
970 class TestCachingWithExistingEDNS ( DNSDistTest
):
972 _config_template
= """
973 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
974 getPool(""):setCache(pc)
975 newServer{address="127.0.0.1: %d "}
977 def testCacheWithEDNS ( self
):
979 Cache: Cache should not match different EDNS value
981 dnsdist is configured to cache entries, we are sending one request
982 (cache miss) and verify that the same one with a different EDNS UDP
983 Payload size is not served from the cache.
986 name
= 'cachedifferentedns.cache.tests.powerdns.com.'
987 query
= dns
. message
. make_query ( name
, 'A' , 'IN' , use_edns
= True , payload
= 512 )
988 response
= dns
. message
. make_response ( query
)
989 rrset
= dns
. rrset
. from_text ( name
,
994 response
. answer
. append ( rrset
)
996 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
997 self
. assertTrue ( receivedQuery
)
998 self
. assertTrue ( receivedResponse
)
999 receivedQuery
. id = query
. id
1000 self
. assertEqual ( query
, receivedQuery
)
1001 self
. assertEqual ( response
, receivedResponse
)
1004 query
= dns
. message
. make_query ( name
, 'A' , 'IN' , use_edns
= True , payload
= 4096 )
1005 response
= dns
. message
. make_response ( query
)
1006 rrset
= dns
. rrset
. from_text ( name
,
1011 response
. answer
. append ( rrset
)
1013 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1014 self
. assertTrue ( receivedQuery
)
1015 self
. assertTrue ( receivedResponse
)
1016 receivedQuery
. id = query
. id
1017 self
. assertEqual ( query
, receivedQuery
)
1018 self
. assertEqual ( response
, receivedResponse
)
1022 for key
in self
._ responsesCounter
:
1023 total
+= self
._ responsesCounter
[ key
]
1025 self
. assertEqual ( total
, misses
)
1027 class TestCachingCacheFull ( DNSDistTest
):
1029 _config_template
= """
1030 pc = newPacketCache(1, {maxTTL=86400, minTTL=1, numberOfShards=1})
1031 getPool(""):setCache(pc)
1032 newServer{address="127.0.0.1: %d "}
1034 def testCacheFull ( self
):
1036 Cache: No new entries are cached when the cache is full
1040 name
= 'cachenotfullyet.cache.tests.powerdns.com.'
1041 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1042 response
= dns
. message
. make_response ( query
)
1043 rrset
= dns
. rrset
. from_text ( name
,
1048 response
. answer
. append ( rrset
)
1051 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1052 self
. assertTrue ( receivedQuery
)
1053 self
. assertTrue ( receivedResponse
)
1054 receivedQuery
. id = query
. id
1055 self
. assertEqual ( query
, receivedQuery
)
1056 self
. assertEqual ( response
, receivedResponse
)
1059 # next queries should hit the cache
1060 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1061 self
. assertEqual ( receivedResponse
, response
)
1063 # ok, now the cache is full, send another query
1064 name
= 'cachefull.cache.tests.powerdns.com.'
1065 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
1066 response
= dns
. message
. make_response ( query
)
1067 rrset
= dns
. rrset
. from_text ( name
,
1072 response
. answer
. append ( rrset
)
1075 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1076 self
. assertTrue ( receivedQuery
)
1077 self
. assertTrue ( receivedResponse
)
1078 receivedQuery
. id = query
. id
1079 self
. assertEqual ( query
, receivedQuery
)
1080 self
. assertEqual ( response
, receivedResponse
)
1083 # next queries should NOT hit the cache
1084 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1085 self
. assertTrue ( receivedQuery
)
1086 self
. assertTrue ( receivedResponse
)
1087 receivedQuery
. id = query
. id
1088 self
. assertEqual ( query
, receivedQuery
)
1089 self
. assertEqual ( response
, receivedResponse
)
1093 for key
in self
._ responsesCounter
:
1094 total
+= self
._ responsesCounter
[ key
]
1096 self
. assertEqual ( total
, misses
)
1098 class TestCachingNoStale ( DNSDistTest
):
1100 _consoleKey
= DNSDistTest
. generateConsoleKey ()
1101 _consoleKeyB64
= base64
. b64encode ( _consoleKey
). decode ( 'ascii' )
1102 _config_params
= [ '_consoleKeyB64' , '_consolePort' , '_testServerPort' ]
1103 _config_template
= """
1104 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
1105 getPool(""):setCache(pc)
1107 controlSocket("127.0.0.1: %d ")
1108 newServer{address="127.0.0.1: %d "}
1110 def testCacheNoStale ( self
):
1112 Cache: Cache entry, set backend down, we should not get a stale entry
1116 name
= 'nostale.cache.tests.powerdns.com.'
1117 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1118 response
= dns
. message
. make_response ( query
)
1119 rrset
= dns
. rrset
. from_text ( name
,
1124 response
. answer
. append ( rrset
)
1127 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1128 self
. assertTrue ( receivedQuery
)
1129 self
. assertTrue ( receivedResponse
)
1130 receivedQuery
. id = query
. id
1131 self
. assertEqual ( query
, receivedQuery
)
1132 self
. assertEqual ( response
, receivedResponse
)
1134 # next queries should hit the cache
1135 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1136 self
. assertEqual ( receivedResponse
, response
)
1138 # ok, we mark the backend as down
1139 self
. sendConsoleCommand ( "getServer(0):setDown()" )
1140 # and we wait for the entry to expire
1143 # we should NOT get a cached, stale, entry
1144 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1145 self
. assertEqual ( receivedResponse
, None )
1148 class TestCachingStale ( DNSDistTest
):
1150 _consoleKey
= DNSDistTest
. generateConsoleKey ()
1151 _consoleKeyB64
= base64
. b64encode ( _consoleKey
). decode ( 'ascii' )
1153 _config_params
= [ '_staleCacheTTL' , '_consoleKeyB64' , '_consolePort' , '_testServerPort' ]
1154 _config_template
= """
1155 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=0, staleTTL= %d })
1156 getPool(""):setCache(pc)
1157 setStaleCacheEntriesTTL(600)
1159 controlSocket("127.0.0.1: %d ")
1160 newServer{address="127.0.0.1: %d "}
1162 def testCacheStale ( self
):
1164 Cache: Cache entry, set backend down, get stale entry
1169 name
= 'stale.cache.tests.powerdns.com.'
1170 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1171 response
= dns
. message
. make_response ( query
)
1172 rrset
= dns
. rrset
. from_text ( name
,
1177 response
. answer
. append ( rrset
)
1180 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1181 self
. assertTrue ( receivedQuery
)
1182 self
. assertTrue ( receivedResponse
)
1183 receivedQuery
. id = query
. id
1184 self
. assertEqual ( query
, receivedQuery
)
1185 self
. assertEqual ( response
, receivedResponse
)
1188 # next queries should hit the cache
1189 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1190 self
. assertEqual ( receivedResponse
, response
)
1192 # ok, we mark the backend as down
1193 self
. sendConsoleCommand ( "getServer(0):setDown()" )
1194 # and we wait for the entry to expire
1197 # we should get a cached, stale, entry
1198 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1199 self
. assertEqual ( receivedResponse
, response
)
1200 for an
in receivedResponse
. answer
:
1201 self
. assertEqual ( an
. ttl
, self
._ staleCacheTTL
)
1204 for key
in self
._ responsesCounter
:
1205 total
+= self
._ responsesCounter
[ key
]
1207 self
. assertEqual ( total
, misses
)
1209 class TestCachingStaleExpunged ( DNSDistTest
):
1211 _consoleKey
= DNSDistTest
. generateConsoleKey ()
1212 _consoleKeyB64
= base64
. b64encode ( _consoleKey
). decode ( 'ascii' )
1214 _config_params
= [ '_staleCacheTTL' , '_consoleKeyB64' , '_consolePort' , '_testServerPort' ]
1215 _config_template
= """
1216 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=0, staleTTL= %d })
1217 getPool(""):setCache(pc)
1218 setStaleCacheEntriesTTL(600)
1219 -- try to remove all expired entries
1220 setCacheCleaningPercentage(100)
1221 -- clean the cache every second
1222 setCacheCleaningDelay(1)
1224 controlSocket("127.0.0.1: %d ")
1225 newServer{address="127.0.0.1: %d "}
1227 def testCacheStale ( self
):
1229 Cache: Cache entry, set backend down, wait for the cache cleaning to run and remove the entry, get no entry
1234 name
= 'stale-but-expunged.cache.tests.powerdns.com.'
1235 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1236 response
= dns
. message
. make_response ( query
)
1237 rrset
= dns
. rrset
. from_text ( name
,
1242 response
. answer
. append ( rrset
)
1245 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1246 self
. assertTrue ( receivedQuery
)
1247 self
. assertTrue ( receivedResponse
)
1248 receivedQuery
. id = query
. id
1249 self
. assertEqual ( query
, receivedQuery
)
1250 self
. assertEqual ( response
, receivedResponse
)
1252 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" misses \" ]" ). strip ( " \n " )), misses
+ drops
)
1254 # next queries should hit the cache
1255 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1256 self
. assertEqual ( receivedResponse
, response
)
1257 # the cache should have one entry
1258 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" entries \" ]" ). strip ( " \n " )), 1 )
1259 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" hits \" ]" ). strip ( " \n " )), 1 )
1261 # ok, we mark the backend as down
1262 self
. sendConsoleCommand ( "getServer(0):setDown()" )
1263 # and we wait for the entry to expire
1265 # wait a bit more to be sure that the cache cleaning algo has been run
1267 # the cache should be empty now
1268 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" entries \" ]" ). strip ( " \n " )), 0 )
1270 # we should get a DROP (backend is down, nothing in the cache anymore)
1271 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1272 self
. assertEqual ( receivedResponse
, None )
1275 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" misses \" ]" ). strip ( " \n " )), misses
+ drops
)
1276 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" hits \" ]" ). strip ( " \n " )), 1 )
1279 for key
in self
._ responsesCounter
:
1280 total
+= self
._ responsesCounter
[ key
]
1282 self
. assertEqual ( total
, misses
)
1284 class TestCachingStaleExpungePrevented ( DNSDistTest
):
1286 _consoleKey
= DNSDistTest
. generateConsoleKey ()
1287 _consoleKeyB64
= base64
. b64encode ( _consoleKey
). decode ( 'ascii' )
1288 _config_params
= [ '_consoleKeyB64' , '_consolePort' , '_testServerPort' ]
1289 _config_template
= """
1290 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=0, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=3600, ecsParsing=false, keepStaleData=true})
1291 getPool(""):setCache(pc)
1292 setStaleCacheEntriesTTL(600)
1293 -- try to remove all expired entries
1294 setCacheCleaningPercentage(100)
1295 -- clean the cache every second
1296 setCacheCleaningDelay(1)
1298 controlSocket("127.0.0.1: %d ")
1299 newServer{address="127.0.0.1: %d "}
1301 def testCacheStale ( self
):
1303 Cache: Cache entry, set backend down, wait for the cache cleaning to run and remove the entry, still get a cache HIT because the stale entry was not removed
1307 name
= 'stale-not-expunged.cache.tests.powerdns.com.'
1308 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1309 response
= dns
. message
. make_response ( query
)
1310 rrset
= dns
. rrset
. from_text ( name
,
1315 response
. answer
. append ( rrset
)
1318 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1319 self
. assertTrue ( receivedQuery
)
1320 self
. assertTrue ( receivedResponse
)
1321 receivedQuery
. id = query
. id
1322 self
. assertEqual ( query
, receivedQuery
)
1323 self
. assertEqual ( response
, receivedResponse
)
1325 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" misses \" ]" ). strip ( " \n " )), 1 )
1327 # next queries should hit the cache
1328 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1329 self
. assertEqual ( receivedResponse
, response
)
1330 # the cache should have one entry
1331 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" entries \" ]" ). strip ( " \n " )), 1 )
1332 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" hits \" ]" ). strip ( " \n " )), 1 )
1334 # ok, we mark the backend as down
1335 self
. sendConsoleCommand ( "getServer(0):setDown()" )
1336 # and we wait for the entry to expire
1338 # wait a bit more to be sure that the cache cleaning algo has been run
1340 # the cache should NOT be empty because the removal of the expired entry should have been prevented
1341 # since all backends for this pool are down
1342 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" entries \" ]" ). strip ( " \n " )), 1 )
1344 # we should get a HIT
1345 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1346 self
. assertEqual ( receivedResponse
, response
)
1348 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" misses \" ]" ). strip ( " \n " )), 1 )
1349 self
. assertEqual ( int ( self
. sendConsoleCommand ( "getPool( \"\" ):getCache():getStats()[ \" hits \" ]" ). strip ( " \n " )), 2 )
1352 for key
in self
._ responsesCounter
:
1353 total
+= self
._ responsesCounter
[ key
]
1355 self
. assertEqual ( total
, misses
)
1357 class TestCacheManagement ( DNSDistTest
):
1359 _consoleKey
= DNSDistTest
. generateConsoleKey ()
1360 _consoleKeyB64
= base64
. b64encode ( _consoleKey
). decode ( 'ascii' )
1361 _config_params
= [ '_consoleKeyB64' , '_consolePort' , '_testServerPort' ]
1362 _config_template
= """
1363 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
1364 getPool(""):setCache(pc)
1366 controlSocket("127.0.0.1: %d ")
1367 newServer{address="127.0.0.1: %d "}
1369 def testCacheExpunge ( self
):
1376 name
= 'expunge.cache.tests.powerdns.com.'
1377 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1378 response
= dns
. message
. make_response ( query
)
1379 rrset
= dns
. rrset
. from_text ( name
,
1384 response
. answer
. append ( rrset
)
1387 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1388 self
. assertTrue ( receivedQuery
)
1389 self
. assertTrue ( receivedResponse
)
1390 receivedQuery
. id = query
. id
1391 self
. assertEqual ( query
, receivedQuery
)
1392 self
. assertEqual ( response
, receivedResponse
)
1395 # next queries should hit the cache
1396 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1397 self
. assertEqual ( receivedResponse
, response
)
1399 # remove cached entries
1400 self
. sendConsoleCommand ( "getPool( \"\" ):getCache():expunge(0)" )
1403 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1404 self
. assertTrue ( receivedQuery
)
1405 self
. assertTrue ( receivedResponse
)
1406 receivedQuery
. id = query
. id
1407 self
. assertEqual ( query
, receivedQuery
)
1408 self
. assertEqual ( response
, receivedResponse
)
1411 # next queries should hit the cache again
1412 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1413 self
. assertEqual ( receivedResponse
, response
)
1416 for key
in self
._ responsesCounter
:
1417 total
+= self
._ responsesCounter
[ key
]
1419 self
. assertEqual ( total
, misses
)
1421 def testCacheExpungeByName ( self
):
1423 Cache: Expunge by name
1428 name
= 'expungebyname.cache.tests.powerdns.com.'
1429 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1430 response
= dns
. message
. make_response ( query
)
1431 rrset
= dns
. rrset
. from_text ( name
,
1436 response
. answer
. append ( rrset
)
1438 name2
= 'expungebynameother.cache.tests.powerdns.com.'
1439 query2
= dns
. message
. make_query ( name2
, 'A' , 'IN' )
1440 response2
= dns
. message
. make_response ( query2
)
1441 rrset2
= dns
. rrset
. from_text ( name2
,
1446 response2
. answer
. append ( rrset2
)
1449 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1450 self
. assertTrue ( receivedQuery
)
1451 self
. assertTrue ( receivedResponse
)
1452 receivedQuery
. id = query
. id
1453 self
. assertEqual ( query
, receivedQuery
)
1454 self
. assertEqual ( response
, receivedResponse
)
1457 # next queries should hit the cache
1458 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1459 self
. assertEqual ( receivedResponse
, response
)
1461 # cache another entry
1462 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query2
, response2
)
1463 self
. assertTrue ( receivedQuery
)
1464 self
. assertTrue ( receivedResponse
)
1465 receivedQuery
. id = query2
. id
1466 self
. assertEqual ( query2
, receivedQuery
)
1467 self
. assertEqual ( response2
, receivedResponse
)
1470 # queries for name and name 2 should hit the cache
1471 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1472 self
. assertEqual ( receivedResponse
, response
)
1474 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1475 self
. assertEqual ( receivedResponse
, response2
)
1477 # remove cached entries from name
1478 self
. sendConsoleCommand ( "getPool( \"\" ):getCache():expungeByName(newDNSName( \" " + name
+ " \" ))" )
1481 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1482 self
. assertTrue ( receivedQuery
)
1483 self
. assertTrue ( receivedResponse
)
1484 receivedQuery
. id = query
. id
1485 self
. assertEqual ( query
, receivedQuery
)
1486 self
. assertEqual ( response
, receivedResponse
)
1489 # next queries for name should hit the cache again
1490 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1491 self
. assertEqual ( receivedResponse
, response
)
1493 # queries for name2 should still hit the cache
1494 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1495 self
. assertEqual ( receivedResponse
, response2
)
1498 for key
in self
._ responsesCounter
:
1499 total
+= self
._ responsesCounter
[ key
]
1501 self
. assertEqual ( total
, misses
)
1503 def testCacheExpungeByNameAndType ( self
):
1505 Cache: Expunge by name and type
1510 name
= 'expungebynameandtype.cache.tests.powerdns.com.'
1511 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1512 response
= dns
. message
. make_response ( query
)
1513 rrset
= dns
. rrset
. from_text ( name
,
1518 response
. answer
. append ( rrset
)
1520 query2
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
1521 response2
= dns
. message
. make_response ( query2
)
1522 rrset2
= dns
. rrset
. from_text ( name
,
1527 response2
. answer
. append ( rrset2
)
1530 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1531 self
. assertTrue ( receivedQuery
)
1532 self
. assertTrue ( receivedResponse
)
1533 receivedQuery
. id = query
. id
1534 self
. assertEqual ( query
, receivedQuery
)
1535 self
. assertEqual ( response
, receivedResponse
)
1538 # next queries should hit the cache
1539 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1540 self
. assertEqual ( receivedResponse
, response
)
1542 # cache another entry
1543 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query2
, response2
)
1544 self
. assertTrue ( receivedQuery
)
1545 self
. assertTrue ( receivedResponse
)
1546 receivedQuery
. id = query2
. id
1547 self
. assertEqual ( query2
, receivedQuery
)
1548 self
. assertEqual ( response2
, receivedResponse
)
1551 # queries for name A and AAAA should hit the cache
1552 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1553 self
. assertEqual ( receivedResponse
, response
)
1555 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1556 self
. assertEqual ( receivedResponse
, response2
)
1558 # remove cached entries from name A
1559 self
. sendConsoleCommand ( "getPool( \"\" ):getCache():expungeByName(newDNSName( \" " + name
+ " \" ), DNSQType.A)" )
1562 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1563 self
. assertTrue ( receivedQuery
)
1564 self
. assertTrue ( receivedResponse
)
1565 receivedQuery
. id = query
. id
1566 self
. assertEqual ( query
, receivedQuery
)
1567 self
. assertEqual ( response
, receivedResponse
)
1570 # next queries for name A should hit the cache again
1571 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1572 self
. assertEqual ( receivedResponse
, response
)
1574 # queries for name AAAA should still hit the cache
1575 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1576 self
. assertEqual ( receivedResponse
, response2
)
1579 for key
in self
._ responsesCounter
:
1580 total
+= self
._ responsesCounter
[ key
]
1581 self
. assertEqual ( total
, misses
)
1583 def testCacheExpungeByNameAndSuffix ( self
):
1585 Cache: Expunge by name
1590 name
= 'expungebyname.suffix.cache.tests.powerdns.com.'
1591 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1592 response
= dns
. message
. make_response ( query
)
1593 rrset
= dns
. rrset
. from_text ( name
,
1598 response
. answer
. append ( rrset
)
1600 name2
= 'expungebyname.suffixother.cache.tests.powerdns.com.'
1601 query2
= dns
. message
. make_query ( name2
, 'A' , 'IN' )
1602 response2
= dns
. message
. make_response ( query2
)
1603 rrset2
= dns
. rrset
. from_text ( name2
,
1608 response2
. answer
. append ( rrset2
)
1611 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1612 self
. assertTrue ( receivedQuery
)
1613 self
. assertTrue ( receivedResponse
)
1614 receivedQuery
. id = query
. id
1615 self
. assertEqual ( query
, receivedQuery
)
1616 self
. assertEqual ( response
, receivedResponse
)
1619 # next queries should hit the cache
1620 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1621 self
. assertEqual ( receivedResponse
, response
)
1623 # cache another entry
1624 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query2
, response2
)
1625 self
. assertTrue ( receivedQuery
)
1626 self
. assertTrue ( receivedResponse
)
1627 receivedQuery
. id = query2
. id
1628 self
. assertEqual ( query2
, receivedQuery
)
1629 self
. assertEqual ( response2
, receivedResponse
)
1632 # queries for name and name 2 should hit the cache
1633 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1634 self
. assertEqual ( receivedResponse
, response
)
1636 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1637 self
. assertEqual ( receivedResponse
, response2
)
1639 # remove cached entries from name
1640 self
. sendConsoleCommand ( "getPool( \"\" ):getCache():expungeByName(newDNSName( \" suffix.cache.tests.powerdns.com. \" ), DNSQType.ANY, true)" )
1643 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1644 self
. assertTrue ( receivedQuery
)
1645 self
. assertTrue ( receivedResponse
)
1646 receivedQuery
. id = query
. id
1647 self
. assertEqual ( query
, receivedQuery
)
1648 self
. assertEqual ( response
, receivedResponse
)
1651 # next queries for name should hit the cache again
1652 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1653 self
. assertEqual ( receivedResponse
, response
)
1655 # queries for name2 should still hit the cache
1656 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1657 self
. assertEqual ( receivedResponse
, response2
)
1660 for key
in self
._ responsesCounter
:
1661 total
+= self
._ responsesCounter
[ key
]
1663 self
. assertEqual ( total
, misses
)
1665 def testCacheExpungeByNameAndTypeAndSuffix ( self
):
1667 Cache: Expunge by name and type
1672 name
= 'expungebynameandtype.suffixtype.cache.tests.powerdns.com.'
1673 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1674 response
= dns
. message
. make_response ( query
)
1675 rrset
= dns
. rrset
. from_text ( name
,
1680 response
. answer
. append ( rrset
)
1682 query2
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
1683 response2
= dns
. message
. make_response ( query2
)
1684 rrset2
= dns
. rrset
. from_text ( name
,
1689 response2
. answer
. append ( rrset2
)
1692 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1693 self
. assertTrue ( receivedQuery
)
1694 self
. assertTrue ( receivedResponse
)
1695 receivedQuery
. id = query
. id
1696 self
. assertEqual ( query
, receivedQuery
)
1697 self
. assertEqual ( response
, receivedResponse
)
1700 # next queries should hit the cache
1701 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1702 self
. assertEqual ( receivedResponse
, response
)
1704 # cache another entry
1705 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query2
, response2
)
1706 self
. assertTrue ( receivedQuery
)
1707 self
. assertTrue ( receivedResponse
)
1708 receivedQuery
. id = query2
. id
1709 self
. assertEqual ( query2
, receivedQuery
)
1710 self
. assertEqual ( response2
, receivedResponse
)
1713 # queries for name A and AAAA should hit the cache
1714 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1715 self
. assertEqual ( receivedResponse
, response
)
1717 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1718 self
. assertEqual ( receivedResponse
, response2
)
1720 # remove cached entries from name A
1721 self
. sendConsoleCommand ( "getPool( \"\" ):getCache():expungeByName(newDNSName( \" suffixtype.cache.tests.powerdns.com. \" ), DNSQType.A, true)" )
1724 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1725 self
. assertTrue ( receivedQuery
)
1726 self
. assertTrue ( receivedResponse
)
1727 receivedQuery
. id = query
. id
1728 self
. assertEqual ( query
, receivedQuery
)
1729 self
. assertEqual ( response
, receivedResponse
)
1732 # next queries for name A should hit the cache again
1733 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1734 self
. assertEqual ( receivedResponse
, response
)
1736 # queries for name AAAA should still hit the cache
1737 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
1738 self
. assertEqual ( receivedResponse
, response2
)
1741 for key
in self
._ responsesCounter
:
1742 total
+= self
._ responsesCounter
[ key
]
1743 self
. assertEqual ( total
, misses
)
1745 class TestCachingTTL ( DNSDistTest
):
1747 _maxCacheTTL
= 86400
1749 _config_params
= [ '_maxCacheTTL' , '_minCacheTTL' , '_testServerPort' ]
1750 _config_template
= """
1751 pc = newPacketCache(1000, {maxTTL= %d , minTTL= %d })
1752 getPool(""):setCache(pc)
1753 newServer{address="127.0.0.1: %d "}
1755 def testCacheShortTTL ( self
):
1757 Cache: Entries with a TTL shorter than minTTL
1762 name
= 'ttltooshort.cache.tests.powerdns.com.'
1763 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1764 response
= dns
. message
. make_response ( query
)
1765 rrset
= dns
. rrset
. from_text ( name
,
1770 response
. answer
. append ( rrset
)
1773 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1774 self
. assertTrue ( receivedQuery
)
1775 self
. assertTrue ( receivedResponse
)
1776 receivedQuery
. id = query
. id
1777 self
. assertEqual ( query
, receivedQuery
)
1778 self
. assertEqual ( response
, receivedResponse
)
1779 for an
in receivedResponse
. answer
:
1780 self
. assertEqual ( an
. ttl
, ttl
)
1783 # We should not have been cached
1784 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1785 self
. assertTrue ( receivedQuery
)
1786 self
. assertTrue ( receivedResponse
)
1787 receivedQuery
. id = query
. id
1788 self
. assertEqual ( query
, receivedQuery
)
1789 self
. assertEqual ( response
, receivedResponse
)
1790 for an
in receivedResponse
. answer
:
1791 self
. assertEqual ( an
. ttl
, ttl
)
1795 for key
in self
._ responsesCounter
:
1796 total
+= self
._ responsesCounter
[ key
]
1798 self
. assertEqual ( total
, misses
)
1800 def testCacheNXWithNoRR ( self
):
1802 Cache: NX with no RR
1806 name
= 'nxwithnorr.cache.tests.powerdns.com.'
1807 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1808 response
= dns
. message
. make_response ( query
)
1809 response
. set_rcode ( dns
. rcode
. NXDOMAIN
)
1812 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1813 self
. assertTrue ( receivedQuery
)
1814 self
. assertTrue ( receivedResponse
)
1815 receivedQuery
. id = query
. id
1816 self
. assertEqual ( query
, receivedQuery
)
1817 self
. assertEqual ( response
, receivedResponse
)
1820 # We should not have been cached
1821 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1822 self
. assertTrue ( receivedQuery
)
1823 self
. assertTrue ( receivedResponse
)
1824 receivedQuery
. id = query
. id
1825 self
. assertEqual ( query
, receivedQuery
)
1826 self
. assertEqual ( response
, receivedResponse
)
1830 for key
in self
._ responsesCounter
:
1831 total
+= self
._ responsesCounter
[ key
]
1833 self
. assertEqual ( total
, misses
)
1835 class TestCachingLongTTL ( DNSDistTest
):
1838 _config_params
= [ '_maxCacheTTL' , '_testServerPort' ]
1839 _config_template
= """
1840 pc = newPacketCache(1000, {maxTTL= %d })
1841 getPool(""):setCache(pc)
1842 newServer{address="127.0.0.1: %d "}
1844 def testCacheLongTTL ( self
):
1846 Cache: Entries with a longer TTL than the maximum
1851 name
= 'longttl.cache.tests.powerdns.com.'
1852 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1853 response
= dns
. message
. make_response ( query
)
1854 rrset
= dns
. rrset
. from_text ( name
,
1859 response
. answer
. append ( rrset
)
1862 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1863 self
. assertTrue ( receivedQuery
)
1864 self
. assertTrue ( receivedResponse
)
1865 receivedQuery
. id = query
. id
1866 self
. assertEqual ( query
, receivedQuery
)
1867 self
. assertEqual ( response
, receivedResponse
)
1868 for an
in receivedResponse
. answer
:
1869 self
. assertEqual ( an
. ttl
, ttl
)
1872 # next queries should hit the cache
1873 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1874 self
. assertEqual ( receivedResponse
, response
)
1875 for an
in receivedResponse
. answer
:
1876 self
. assertTrue ( an
. ttl
<= ttl
)
1878 time
. sleep ( self
._ maxCacheTTL
+ 1 )
1880 # we should not have cached for longer than max cache
1881 # so it should be a miss
1882 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1883 self
. assertTrue ( receivedQuery
)
1884 self
. assertTrue ( receivedResponse
)
1885 receivedQuery
. id = query
. id
1886 self
. assertEqual ( query
, receivedQuery
)
1887 self
. assertEqual ( response
, receivedResponse
)
1888 for an
in receivedResponse
. answer
:
1889 self
. assertEqual ( an
. ttl
, ttl
)
1893 for key
in self
._ responsesCounter
:
1894 total
+= self
._ responsesCounter
[ key
]
1896 self
. assertEqual ( total
, misses
)
1898 class TestCachingFailureTTL ( DNSDistTest
):
1900 _failureCacheTTL
= 2
1901 _config_params
= [ '_failureCacheTTL' , '_testServerPort' ]
1902 _config_template
= """
1903 pc = newPacketCache(1000, {maxTTL=86400, minTTL=0, temporaryFailureTTL= %d , staleTTL=60})
1904 getPool(""):setCache(pc)
1905 newServer{address="127.0.0.1: %d "}
1907 def testCacheServFailTTL ( self
):
1913 name
= 'servfail.failure.cache.tests.powerdns.com.'
1914 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1915 response
= dns
. message
. make_response ( query
)
1916 response
. set_rcode ( dns
. rcode
. SERVFAIL
)
1919 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1920 self
. assertTrue ( receivedQuery
)
1921 self
. assertTrue ( receivedResponse
)
1922 receivedQuery
. id = query
. id
1923 self
. assertEqual ( query
, receivedQuery
)
1924 self
. assertEqual ( response
, receivedResponse
)
1927 # next queries should hit the cache
1928 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1929 self
. assertEqual ( receivedResponse
, response
)
1931 time
. sleep ( self
._ failureCacheTTL
+ 1 )
1933 # we should not have cached for longer than failure cache
1934 # so it should be a miss
1935 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1936 self
. assertTrue ( receivedQuery
)
1937 self
. assertTrue ( receivedResponse
)
1938 receivedQuery
. id = query
. id
1939 self
. assertEqual ( query
, receivedQuery
)
1940 self
. assertEqual ( response
, receivedResponse
)
1944 for key
in self
._ responsesCounter
:
1945 total
+= self
._ responsesCounter
[ key
]
1947 self
. assertEqual ( total
, misses
)
1949 def testCacheRefusedTTL ( self
):
1955 name
= 'refused.failure.cache.tests.powerdns.com.'
1956 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1957 response
= dns
. message
. make_response ( query
)
1958 response
. set_rcode ( dns
. rcode
. REFUSED
)
1961 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1962 self
. assertTrue ( receivedQuery
)
1963 self
. assertTrue ( receivedResponse
)
1964 receivedQuery
. id = query
. id
1965 self
. assertEqual ( query
, receivedQuery
)
1966 self
. assertEqual ( response
, receivedResponse
)
1969 # next queries should hit the cache
1970 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
1971 self
. assertEqual ( receivedResponse
, response
)
1973 time
. sleep ( self
._ failureCacheTTL
+ 1 )
1975 # we should not have cached for longer than failure cache
1976 # so it should be a miss
1977 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
1978 self
. assertTrue ( receivedQuery
)
1979 self
. assertTrue ( receivedResponse
)
1980 receivedQuery
. id = query
. id
1981 self
. assertEqual ( query
, receivedQuery
)
1982 self
. assertEqual ( response
, receivedResponse
)
1986 for key
in self
._ responsesCounter
:
1987 total
+= self
._ responsesCounter
[ key
]
1989 self
. assertEqual ( total
, misses
)
1991 def testCacheHeaderOnlyRefusedTTL ( self
):
1993 Cache: Header-Only Refused TTL
1997 name
= 'header-only-refused.failure.cache.tests.powerdns.com.'
1998 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
1999 response
= dns
. message
. make_response ( query
)
2000 response
. set_rcode ( dns
. rcode
. REFUSED
)
2001 response
. question
= []
2004 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2005 self
. assertTrue ( receivedQuery
)
2006 self
. assertTrue ( receivedResponse
)
2007 receivedQuery
. id = query
. id
2008 self
. assertEqual ( query
, receivedQuery
)
2009 self
. assertEqual ( response
, receivedResponse
)
2012 # next queries should hit the cache
2013 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
2014 self
. assertEqual ( receivedResponse
, response
)
2016 time
. sleep ( self
._ failureCacheTTL
+ 1 )
2018 # we should not have cached for longer than failure cache
2019 # so it should be a miss
2020 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2021 self
. assertTrue ( receivedQuery
)
2022 self
. assertTrue ( receivedResponse
)
2023 receivedQuery
. id = query
. id
2024 self
. assertEqual ( query
, receivedQuery
)
2025 self
. assertEqual ( response
, receivedResponse
)
2029 for key
in self
._ responsesCounter
:
2030 total
+= self
._ responsesCounter
[ key
]
2032 self
. assertEqual ( total
, misses
)
2034 class TestCachingNegativeTTL ( DNSDistTest
):
2037 _config_params
= [ '_negCacheTTL' , '_testServerPort' ]
2038 _config_template
= """
2039 pc = newPacketCache(1000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL= %d })
2040 getPool(""):setCache(pc)
2041 newServer{address="127.0.0.1: %d "}
2044 def testCacheNegativeTTLNXDomain ( self
):
2046 Cache: Negative TTL on NXDOMAIN
2050 name
= 'nxdomain.negativettl.cache.tests.powerdns.com.'
2051 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
2052 response
= dns
. message
. make_response ( query
)
2053 response
. set_rcode ( dns
. rcode
. NXDOMAIN
)
2054 soa
= dns
. rrset
. from_text ( name
,
2058 'ns.' + name
+ ' hostmaster.' + name
+ ' 1 3600 3600 3600 60' )
2059 response
. authority
. append ( soa
)
2062 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2063 self
. assertTrue ( receivedQuery
)
2064 self
. assertTrue ( receivedResponse
)
2065 receivedQuery
. id = query
. id
2066 self
. assertEqual ( query
, receivedQuery
)
2067 self
. assertEqual ( response
, receivedResponse
)
2070 # next queries should hit the cache
2071 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
2072 self
. assertEqual ( receivedResponse
, response
)
2074 time
. sleep ( self
._ negCacheTTL
+ 1 )
2076 # we should not have cached for longer than the negative TTL
2077 # so it should be a miss
2078 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2079 self
. assertTrue ( receivedQuery
)
2080 self
. assertTrue ( receivedResponse
)
2081 receivedQuery
. id = query
. id
2082 self
. assertEqual ( query
, receivedQuery
)
2083 self
. assertEqual ( response
, receivedResponse
)
2087 for key
in self
._ responsesCounter
:
2088 total
+= self
._ responsesCounter
[ key
]
2090 self
. assertEqual ( total
, misses
)
2092 def testCacheNegativeTTLNoData ( self
):
2094 Cache: Negative TTL on NoData
2098 name
= 'nodata.negativettl.cache.tests.powerdns.com.'
2099 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
2100 response
= dns
. message
. make_response ( query
)
2101 response
. set_rcode ( dns
. rcode
. NOERROR
)
2102 soa
= dns
. rrset
. from_text ( name
,
2106 'ns.' + name
+ ' hostmaster.' + name
+ ' 1 3600 3600 3600 60' )
2107 response
. authority
. append ( soa
)
2110 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2111 self
. assertTrue ( receivedQuery
)
2112 self
. assertTrue ( receivedResponse
)
2113 receivedQuery
. id = query
. id
2114 self
. assertEqual ( query
, receivedQuery
)
2115 self
. assertEqual ( response
, receivedResponse
)
2118 # next queries should hit the cache
2119 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
2120 self
. assertEqual ( receivedResponse
, response
)
2122 time
. sleep ( self
._ negCacheTTL
+ 1 )
2124 # we should not have cached for longer than the negative TTL
2125 # so it should be a miss
2126 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2127 self
. assertTrue ( receivedQuery
)
2128 self
. assertTrue ( receivedResponse
)
2129 receivedQuery
. id = query
. id
2130 self
. assertEqual ( query
, receivedQuery
)
2131 self
. assertEqual ( response
, receivedResponse
)
2135 for key
in self
._ responsesCounter
:
2136 total
+= self
._ responsesCounter
[ key
]
2138 self
. assertEqual ( total
, misses
)
2140 class TestCachingDontAge ( DNSDistTest
):
2142 _config_template
= """
2143 pc = newPacketCache(100, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=true})
2144 getPool(""):setCache(pc)
2145 newServer{address="127.0.0.1: %d "}
2147 def testCacheDoesntDecreaseTTL ( self
):
2149 Cache: Cache doesn't decrease TTL with 'don't age' set
2151 dnsdist is configured to cache entries but without aging the TTL,
2152 we are sending one request (cache miss) and verify that the cache
2153 hits don't have a decreasing TTL.
2157 name
= 'cachedoesntdecreasettl.cache-dont-age.tests.powerdns.com.'
2158 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2159 response
= dns
. message
. make_response ( query
)
2160 rrset
= dns
. rrset
. from_text ( name
,
2165 response
. answer
. append ( rrset
)
2167 # first query to fill the cache
2168 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2169 self
. assertTrue ( receivedQuery
)
2170 self
. assertTrue ( receivedResponse
)
2171 receivedQuery
. id = query
. id
2172 self
. assertEqual ( query
, receivedQuery
)
2173 self
. assertEqual ( receivedResponse
, response
)
2176 # next queries should hit the cache
2177 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
2178 self
. assertEqual ( receivedResponse
, response
)
2179 for an
in receivedResponse
. answer
:
2180 self
. assertTrue ( an
. ttl
== ttl
)
2182 # now we wait a bit for the TTL to decrease
2185 # next queries should hit the cache
2186 ( _
, receivedResponse
) = self
. sendUDPQuery ( query
, response
= None , useQueue
= False )
2187 self
. assertEqual ( receivedResponse
, response
)
2188 for an
in receivedResponse
. answer
:
2189 self
. assertTrue ( an
. ttl
== ttl
)
2192 for key
in self
._ responsesCounter
:
2193 total
+= self
._ responsesCounter
[ key
]
2195 self
. assertEqual ( total
, misses
)
2197 class TestCachingECSWithoutPoolECS ( DNSDistTest
):
2199 _consoleKey
= DNSDistTest
. generateConsoleKey ()
2200 _consoleKeyB64
= base64
. b64encode ( _consoleKey
). decode ( 'ascii' )
2201 _config_params
= [ '_consoleKeyB64' , '_consolePort' , '_testServerPort' ]
2202 _config_template
= """
2203 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
2204 getPool(""):setCache(pc)
2206 controlSocket("127.0.0.1: %d ")
2207 newServer{address="127.0.0.1: %d ", useClientSubnet=true}
2210 def testCached ( self
):
2212 Cache: Cached entry with ECS is a miss when no backend are available
2215 name
= 'cached.cache-ecs-without-pool-ecs.tests.powerdns.com.'
2216 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2217 response
= dns
. message
. make_response ( query
)
2218 rrset
= dns
. rrset
. from_text ( name
,
2223 response
. answer
. append ( rrset
)
2225 # first query to fill the cache
2226 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2227 sender
= getattr ( self
, method
)
2228 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2229 self
. assertTrue ( receivedQuery
)
2230 self
. assertTrue ( receivedResponse
)
2231 receivedQuery
. id = query
. id
2232 self
. assertEqual ( query
, receivedQuery
)
2233 self
. assertEqual ( receivedResponse
, response
)
2235 # next queries should hit the cache
2236 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2237 sender
= getattr ( self
, method
)
2238 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2239 self
. assertEqual ( receivedResponse
, response
)
2241 # we mark the backend as down
2242 self
. sendConsoleCommand ( "getServer(0):setDown()" )
2244 # we should NOT get a cached entry since it has ECS and we haven't asked the pool
2245 # to add ECS when no backend is up
2246 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2247 sender
= getattr ( self
, method
)
2248 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2249 self
. assertEqual ( receivedResponse
, None )
2251 class TestCachingECSWithPoolECS ( DNSDistTest
):
2253 _consoleKey
= DNSDistTest
. generateConsoleKey ()
2254 _consoleKeyB64
= base64
. b64encode ( _consoleKey
). decode ( 'ascii' )
2255 _config_params
= [ '_consoleKeyB64' , '_consolePort' , '_testServerPort' ]
2256 _config_template
= """
2257 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
2258 getPool(""):setCache(pc)
2259 getPool(""):setECS(true)
2261 controlSocket("127.0.0.1: %d ")
2262 newServer{address="127.0.0.1: %d ", useClientSubnet=true}
2265 def testCached ( self
):
2267 Cache: Cached entry with ECS is a hit when no backend are available
2270 name
= 'cached.cache-ecs-with-pool-ecs.tests.powerdns.com.'
2271 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2272 response
= dns
. message
. make_response ( query
)
2273 rrset
= dns
. rrset
. from_text ( name
,
2278 response
. answer
. append ( rrset
)
2280 # first query to fill the cache
2281 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2282 sender
= getattr ( self
, method
)
2283 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2284 self
. assertTrue ( receivedQuery
)
2285 self
. assertTrue ( receivedResponse
)
2286 receivedQuery
. id = query
. id
2287 self
. assertEqual ( query
, receivedQuery
)
2288 self
. assertEqual ( receivedResponse
, response
)
2290 # next queries should hit the cache
2291 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2292 sender
= getattr ( self
, method
)
2293 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2294 self
. assertEqual ( receivedResponse
, response
)
2296 # we mark the backend as down
2297 self
. sendConsoleCommand ( "getServer(0):setDown()" )
2299 # we should STILL get a cached entry since it has ECS and we have asked the pool
2300 # to add ECS when no backend is up
2301 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2302 sender
= getattr ( self
, method
)
2303 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2304 self
. assertEqual ( receivedResponse
, response
)
2306 class TestCachingCollisionNoECSParsing ( DNSDistTest
):
2308 _config_template
= """
2309 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
2310 getPool(""):setCache(pc)
2311 newServer{address="127.0.0.1: %d "}
2314 def testCacheCollisionNoECSParsing ( self
):
2316 Cache: Collision with no ECS parsing
2318 name
= 'collision-no-ecs-parsing.cache.tests.powerdns.com.'
2319 ecso
= clientsubnetoption
. ClientSubnetOption ( '10.0.226.63' , 32 )
2320 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2321 query
. flags
= dns
. flags
. RD
2322 response
= dns
. message
. make_response ( query
)
2323 rrset
= dns
. rrset
. from_text ( name
,
2328 response
. answer
. append ( rrset
)
2330 # first query should to fill the cache
2331 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2332 self
. assertTrue ( receivedQuery
)
2333 self
. assertTrue ( receivedResponse
)
2334 receivedQuery
. id = query
. id
2335 self
. assertEqual ( query
, receivedQuery
)
2336 self
. assertEqual ( receivedResponse
, response
)
2338 # second query will hash to the same key, triggering a collision which
2339 # will not be detected because the qname, qtype, qclass and flags will
2340 # match and EDNS Client Subnet parsing has not been enabled
2341 ecso2
= clientsubnetoption
. ClientSubnetOption ( '10.1.60.19' , 32 )
2342 query2
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso2
], payload
= 512 )
2343 query2
. flags
= dns
. flags
. RD
2344 ( _
, receivedResponse
) = self
. sendUDPQuery ( query2
, response
= None , useQueue
= False )
2345 receivedResponse
. id = response
. id
2346 self
. assertEqual ( receivedResponse
, response
)
2348 class TestCachingCollisionWithECSParsing ( DNSDistTest
):
2350 _config_template
= """
2351 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=3600, parseECS=true})
2352 getPool(""):setCache(pc)
2353 newServer{address="127.0.0.1: %d "}
2356 def testCacheCollisionWithECSParsing ( self
):
2358 Cache: Collision with ECS parsing
2360 name
= 'collision-with-ecs-parsing.cache.tests.powerdns.com.'
2361 ecso
= clientsubnetoption
. ClientSubnetOption ( '10.0.150.206' , 32 )
2362 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2363 query
. flags
= dns
. flags
. RD
2364 response
= dns
. message
. make_response ( query
)
2365 rrset
= dns
. rrset
. from_text ( name
,
2370 response
. answer
. append ( rrset
)
2372 # first query should to fill the cache
2373 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query
, response
)
2374 self
. assertTrue ( receivedQuery
)
2375 self
. assertTrue ( receivedResponse
)
2376 receivedQuery
. id = query
. id
2377 self
. assertEqual ( query
, receivedQuery
)
2378 self
. assertEqual ( receivedResponse
, response
)
2380 # second query will hash to the same key, triggering a collision which
2381 # _will_ be detected this time because the qname, qtype, qclass and flags will
2382 # match but EDNS Client Subnet parsing is now enabled and will detect the issue
2383 ecso2
= clientsubnetoption
. ClientSubnetOption ( '10.0.212.51' , 32 )
2384 query2
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso2
], payload
= 512 )
2385 query2
. flags
= dns
. flags
. RD
2386 response2
= dns
. message
. make_response ( query2
)
2387 rrset
= dns
. rrset
. from_text ( name
,
2392 response2
. answer
. append ( rrset
)
2393 ( receivedQuery
, receivedResponse
) = self
. sendUDPQuery ( query2
, response2
)
2394 self
. assertEqual ( receivedResponse
, response2
)
2396 class TestCachingScopeZero ( DNSDistTest
):
2398 _config_template
= """
2399 -- Be careful to enable ECS parsing in the packet cache, otherwise scope zero is disabled
2400 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=3600, parseECS=true})
2401 getPool(""):setCache(pc)
2402 newServer{address="127.0.0.1: %d ", useClientSubnet=true}
2403 -- to simulate a second client coming from a different IP address,
2404 -- we will force the ECS value added to the query if RD is set (note that we need
2405 -- to unset it using rules before the first cache lookup)
2406 addAction(RDRule(), SetECSAction("192.0.2.1/32"))
2407 addAction(RDRule(), SetNoRecurseAction())
2410 def testScopeZero ( self
):
2412 Cache: Test the scope-zero feature, backend returns a scope of zero
2415 name
= 'scope-zero.cache.tests.powerdns.com.'
2416 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2417 query
. flags
&= ~dns
. flags
. RD
2418 ecso
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.0' , 24 )
2419 expectedQuery
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2420 expectedQuery
. flags
&= ~dns
. flags
. RD
2421 ecsoResponse
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.1' , 24 , 0 )
2422 expectedResponse
= dns
. message
. make_response ( query
)
2423 scopedResponse
= dns
. message
. make_response ( query
)
2424 scopedResponse
. use_edns ( edns
= True , payload
= 4096 , options
=[ ecsoResponse
])
2425 rrset
= dns
. rrset
. from_text ( name
,
2430 scopedResponse
. answer
. append ( rrset
)
2431 expectedResponse
. answer
. append ( rrset
)
2433 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2434 sender
= getattr ( self
, method
)
2435 ( receivedQuery
, receivedResponse
) = sender ( query
, scopedResponse
)
2436 receivedQuery
. id = expectedQuery
. id
2437 self
. checkMessageEDNSWithECS ( expectedQuery
, receivedQuery
)
2438 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2440 # next query should hit the cache, nothing special about that
2441 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2442 sender
= getattr ( self
, method
)
2443 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2444 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2446 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2447 query
. flags
&= dns
. flags
. RD
2448 # next query FROM A DIFFERENT CLIENT since RD is now set should STILL hit the cache
2449 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2450 sender
= getattr ( self
, method
)
2451 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2452 receivedResponse
. id = expectedResponse
. id
2453 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2455 name
= 'scope-zero-with-ecs.cache.tests.powerdns.com.'
2456 ecso
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.1' , 24 )
2457 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2458 query
. flags
&= ~dns
. flags
. RD
2459 expectedQuery
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2460 expectedQuery
. flags
&= ~dns
. flags
. RD
2461 expectedResponse
= dns
. message
. make_response ( query
)
2462 expectedResponse
. use_edns ( edns
= True , payload
= 4096 , options
=[ ecsoResponse
])
2463 expectedResponse
. answer
. append ( rrset
)
2464 scopedResponse
= dns
. message
. make_response ( query
)
2465 scopedResponse
. use_edns ( edns
= True , payload
= 4096 , options
=[ ecsoResponse
])
2466 scopedResponse
. answer
. append ( rrset
)
2467 # this query has ECS, it should NOT be able to use the scope-zero cached entry since the hash will be
2469 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2470 sender
= getattr ( self
, method
)
2471 ( receivedQuery
, receivedResponse
) = sender ( query
, scopedResponse
)
2472 receivedQuery
. id = expectedQuery
. id
2473 self
. checkMessageEDNSWithECS ( expectedQuery
, receivedQuery
)
2474 self
. checkMessageEDNSWithECS ( receivedResponse
, expectedResponse
)
2476 # it should still have been cached, though, so the next query should be a hit
2477 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2478 sender
= getattr ( self
, method
)
2479 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2480 self
. checkMessageEDNSWithECS ( receivedResponse
, expectedResponse
)
2482 def testScopeNotZero ( self
):
2484 Cache: Test the scope-zero feature, backend returns a scope of non-zero
2487 name
= 'scope-not-zero.cache.tests.powerdns.com.'
2488 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2489 query
. flags
&= ~dns
. flags
. RD
2490 ecso
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.0' , 24 )
2491 expectedQuery
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2492 expectedQuery
. flags
&= ~dns
. flags
. RD
2493 ecso2
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.1' , 32 )
2494 expectedQuery2
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso2
], payload
= 512 )
2495 expectedQuery2
. flags
&= ~dns
. flags
. RD
2496 ecsoResponse
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.1' , 24 , 24 )
2497 ecsoResponse2
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.1' , 32 , 24 )
2498 rrset
= dns
. rrset
. from_text ( name
,
2503 expectedResponse
= dns
. message
. make_response ( query
)
2504 expectedResponse
. answer
. append ( rrset
)
2505 scopedResponse
= dns
. message
. make_response ( query
)
2506 scopedResponse
. use_edns ( edns
= True , payload
= 4096 , options
=[ ecsoResponse
])
2507 scopedResponse
. answer
. append ( rrset
)
2508 scopedResponse2
= dns
. message
. make_response ( query
)
2509 scopedResponse2
. use_edns ( edns
= True , payload
= 4096 , options
=[ ecsoResponse2
])
2510 scopedResponse2
. answer
. append ( rrset
)
2512 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2513 sender
= getattr ( self
, method
)
2514 ( receivedQuery
, receivedResponse
) = sender ( query
, scopedResponse
)
2515 receivedQuery
. id = expectedQuery
. id
2516 self
. checkMessageEDNSWithECS ( expectedQuery
, receivedQuery
)
2517 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2519 # next query should hit the cache, nothing special about that
2520 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2521 sender
= getattr ( self
, method
)
2522 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2523 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2525 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2526 query
. flags
&= dns
. flags
. RD
2527 expectedResponse
= dns
. message
. make_response ( query
)
2528 expectedResponse
. answer
. append ( rrset
)
2529 # next query FROM A DIFFERENT CLIENT since RD is now set should NOT hit the cache
2530 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2531 sender
= getattr ( self
, method
)
2532 ( receivedQuery
, receivedResponse
) = sender ( query
, scopedResponse2
)
2533 receivedQuery
. id = expectedQuery2
. id
2534 self
. checkMessageEDNSWithECS ( expectedQuery2
, receivedQuery
)
2535 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2537 def testNoECS ( self
):
2539 Cache: Test the scope-zero feature, backend returns no ECS at all
2542 name
= 'scope-zero-no-ecs.cache.tests.powerdns.com.'
2543 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2544 query
. flags
&= ~dns
. flags
. RD
2545 ecso
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.0' , 24 )
2546 expectedQuery
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2547 expectedQuery
. flags
&= ~dns
. flags
. RD
2548 ecso2
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.1' , 32 )
2549 expectedQuery2
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso2
], payload
= 512 )
2550 expectedQuery2
. flags
&= ~dns
. flags
. RD
2551 rrset
= dns
. rrset
. from_text ( name
,
2556 response
= dns
. message
. make_response ( query
)
2557 response
. answer
. append ( rrset
)
2559 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2560 sender
= getattr ( self
, method
)
2561 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2562 receivedQuery
. id = expectedQuery
. id
2563 self
. checkMessageEDNSWithECS ( expectedQuery
, receivedQuery
)
2564 self
. checkMessageNoEDNS ( receivedResponse
, response
)
2566 # next query should hit the cache, nothing special about that
2567 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2568 sender
= getattr ( self
, method
)
2569 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2570 self
. checkMessageNoEDNS ( receivedResponse
, response
)
2572 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2573 query
. flags
&= dns
. flags
. RD
2574 response
= dns
. message
. make_response ( query
)
2575 response
. answer
. append ( rrset
)
2576 # next query FROM A DIFFERENT CLIENT since RD is now set should NOT hit the cache
2577 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2578 sender
= getattr ( self
, method
)
2579 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2580 receivedQuery
. id = expectedQuery2
. id
2581 self
. checkMessageEDNSWithECS ( expectedQuery2
, receivedQuery
)
2582 self
. checkMessageNoEDNS ( receivedResponse
, response
)
2584 class TestCachingScopeZeroButNoSubnetcheck ( DNSDistTest
):
2586 _config_template
= """
2587 -- We disable ECS parsing in the packet cache, meaning scope zero is disabled
2588 pc = newPacketCache(100, {maxTTL=86400, minTTL=1, temporaryFailureTTL=60, staleTTL=60, dontAge=false, numberOfShards=1, deferrableInsertLock=true, maxNegativeTTL=3600, parseECS=false})
2589 getPool(""):setCache(pc)
2590 newServer{address="127.0.0.1: %d ", useClientSubnet=true}
2591 -- to simulate a second client coming from a different IP address,
2592 -- we will force the ECS value added to the query if RD is set (note that we need
2593 -- to unset it using rules before the first cache lookup)
2594 addAction(RDRule(), SetECSAction("192.0.2.1/32"))
2595 addAction(RDRule(), SetNoRecurseAction())
2598 def testScopeZero ( self
):
2600 Cache: Test that the scope-zero feature is disabled when ECS parsing is not enabled in the cache
2603 name
= 'scope-zero-no-subnet.cache.tests.powerdns.com.'
2604 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2605 query
. flags
&= ~dns
. flags
. RD
2606 ecso
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.0' , 24 )
2607 expectedQuery
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso
], payload
= 512 )
2608 expectedQuery
. flags
&= ~dns
. flags
. RD
2609 ecso2
= clientsubnetoption
. ClientSubnetOption ( '192.0.2.1' , 32 )
2610 expectedQuery2
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' , use_edns
= True , options
=[ ecso2
], payload
= 512 )
2611 expectedQuery2
. flags
&= ~dns
. flags
. RD
2612 ecsoResponse
= clientsubnetoption
. ClientSubnetOption ( '127.0.0.1' , 24 , 0 )
2613 expectedResponse
= dns
. message
. make_response ( query
)
2614 scopedResponse
= dns
. message
. make_response ( query
)
2615 scopedResponse
. use_edns ( edns
= True , payload
= 4096 , options
=[ ecsoResponse
])
2616 rrset
= dns
. rrset
. from_text ( name
,
2621 scopedResponse
. answer
. append ( rrset
)
2622 expectedResponse
. answer
. append ( rrset
)
2624 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2625 sender
= getattr ( self
, method
)
2626 ( receivedQuery
, receivedResponse
) = sender ( query
, scopedResponse
)
2627 receivedQuery
. id = expectedQuery
. id
2628 self
. checkMessageEDNSWithECS ( expectedQuery
, receivedQuery
)
2629 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2631 # next query should hit the cache, nothing special about that
2632 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2633 sender
= getattr ( self
, method
)
2634 ( _
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2635 self
. checkMessageNoEDNS ( receivedResponse
, expectedResponse
)
2637 query
= dns
. message
. make_query ( name
, 'AAAA' , 'IN' )
2638 query
. flags
&= dns
. flags
. RD
2639 response
= dns
. message
. make_response ( query
)
2640 response
. answer
. append ( rrset
)
2641 # next query FROM A DIFFERENT CLIENT since RD is now set should NOT hit the cache
2642 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2643 sender
= getattr ( self
, method
)
2644 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2645 receivedQuery
. id = expectedQuery2
. id
2646 self
. checkMessageEDNSWithECS ( expectedQuery2
, receivedQuery
)
2647 self
. checkMessageNoEDNS ( receivedResponse
, response
)
2649 class TestCachingAlteredHeader ( DNSDistTest
):
2651 _config_template
= """
2652 pc = newPacketCache(100)
2653 getPool(""):setCache(pc)
2654 addAction("cache-set-rd.tests.powerdns.com.", SetNoRecurseAction())
2655 newServer{address="127.0.0.1: %d "}
2658 def testCachingAlteredHeader ( self
):
2660 Cache: The header has been altered via a rule
2662 name
= 'cache-set-rd.tests.powerdns.com.'
2663 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
2664 # the query reaching the backend will never have the RD flag set
2665 expectedQuery
= dns
. message
. make_query ( name
, 'A' , 'IN' )
2666 expectedQuery
. flags
&= ~dns
. flags
. RD
2667 response
= dns
. message
. make_response ( query
)
2668 response
. flags
&= ~dns
. flags
. RD
2669 rrset
= dns
. rrset
. from_text ( name
,
2674 response
. answer
. append ( rrset
)
2676 # first query has RD=1
2677 query
. flags |
= dns
. flags
. RD
2678 expectedResponse
= dns
. message
. make_response ( query
)
2679 rrset
= dns
. rrset
. from_text ( name
,
2684 expectedResponse
. answer
. append ( rrset
)
2686 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2687 sender
= getattr ( self
, method
)
2688 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2689 self
. assertTrue ( receivedQuery
)
2690 self
. assertTrue ( receivedResponse
)
2691 receivedQuery
. id = expectedQuery
. id
2692 self
. assertEqual ( expectedQuery
, receivedQuery
)
2693 self
. assertEqual ( receivedResponse
, expectedResponse
)
2695 # next query should hit the cache
2696 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2697 sender
= getattr ( self
, method
)
2698 ( receivedQuery
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2700 # same query with RD=0, should hit the cache as well
2701 query
. flags
&= ~dns
. flags
. RD
2702 expectedResponse
= dns
. message
. make_response ( query
)
2703 rrset
= dns
. rrset
. from_text ( name
,
2708 expectedResponse
. answer
. append ( rrset
)
2709 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2710 sender
= getattr ( self
, method
)
2711 ( receivedQuery
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2712 self
. assertFalse ( receivedQuery
)
2713 self
. assertTrue ( receivedResponse
)
2714 self
. assertEqual ( receivedResponse
, expectedResponse
)
2716 class TestCachingBackendSettingRD ( DNSDistTest
):
2718 _config_template
= """
2719 pc = newPacketCache(100)
2720 getPool(""):setCache(pc)
2721 newServer{address="127.0.0.1: %d "}
2724 def testCachingBackendSetRD ( self
):
2726 Cache: The backend sets RD=1 in the response even if the query had RD=0
2728 name
= 'backend-sets-rd.tests.powerdns.com.'
2729 query
= dns
. message
. make_query ( name
, 'A' , 'IN' )
2730 query
. flags
&= ~dns
. flags
. RD
2731 expectedQuery
= dns
. message
. make_query ( name
, 'A' , 'IN' )
2732 expectedQuery
. flags
&= ~dns
. flags
. RD
2733 response
= dns
. message
. make_response ( query
)
2734 response
. flags |
= dns
. flags
. RD
2735 rrset
= dns
. rrset
. from_text ( name
,
2740 response
. answer
. append ( rrset
)
2742 expectedResponse
= dns
. message
. make_response ( query
)
2743 expectedResponse
. flags
&= ~dns
. flags
. RD
2744 rrset
= dns
. rrset
. from_text ( name
,
2749 expectedResponse
. answer
. append ( rrset
)
2751 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2752 sender
= getattr ( self
, method
)
2753 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2754 self
. assertTrue ( receivedQuery
)
2755 self
. assertTrue ( receivedResponse
)
2756 receivedQuery
. id = expectedQuery
. id
2757 self
. assertEqual ( expectedQuery
, receivedQuery
)
2758 self
. assertEqual ( receivedResponse
, expectedResponse
)
2760 # exact same query should be cached
2761 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2762 sender
= getattr ( self
, method
)
2763 ( receivedQuery
, receivedResponse
) = sender ( query
, response
= None , useQueue
= False )
2764 self
. assertFalse ( receivedQuery
)
2765 self
. assertTrue ( receivedResponse
)
2766 self
. assertEqual ( receivedResponse
, expectedResponse
)
2768 # same query with RD=1, should NOT hit the cache
2769 query
. flags |
= dns
. flags
. RD
2770 expectedResponse
= dns
. message
. make_response ( query
)
2771 rrset
= dns
. rrset
. from_text ( name
,
2776 expectedResponse
. answer
. append ( rrset
)
2778 for method
in ( "sendUDPQuery" , "sendTCPQuery" ):
2779 sender
= getattr ( self
, method
)
2780 ( receivedQuery
, receivedResponse
) = sender ( query
, response
)
2781 self
. assertTrue ( receivedQuery
)
2782 self
. assertTrue ( receivedResponse
)
2783 self
. assertEqual ( receivedResponse
, expectedResponse
)