1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
7 #include <boost/test/unit_test.hpp>
8 #include <boost/test/floating_point_comparison.hpp>
10 #include "nameserver.hh"
12 #include "auth-packetcache.hh"
13 #include "auth-querycache.hh"
14 #include "arguments.hh"
18 BOOST_AUTO_TEST_SUITE(test_packetcache_cc
)
20 BOOST_AUTO_TEST_CASE(test_AuthQueryCacheSimple
) {
22 QC
.setMaxEntries(1000000);
24 vector
<DNSZoneRecord
> records
;
26 BOOST_CHECK_EQUAL(QC
.size(), 0);
27 QC
.insert(DNSName("hello"), QType(QType::A
), records
, 3600, 1);
28 BOOST_CHECK_EQUAL(QC
.size(), 1);
29 BOOST_CHECK_EQUAL(QC
.purge(), 1);
30 BOOST_CHECK_EQUAL(QC
.size(), 0);
34 for(counter
= 0; counter
< 100000; ++counter
) {
35 DNSName a
=DNSName("hello ")+DNSName(std::to_string(counter
));
36 BOOST_CHECK_EQUAL(DNSName(a
.toString()), a
);
38 QC
.insert(a
, QType(QType::A
), records
, 3600, 1);
39 if(!QC
.purge(a
.toString()))
40 BOOST_FAIL("Could not remove entry we just added to the query cache!");
41 QC
.insert(a
, QType(QType::A
), records
, 3600, 1);
44 BOOST_CHECK_EQUAL(QC
.size(), counter
);
46 uint64_t delcounter
=0;
47 for(delcounter
=0; delcounter
< counter
/100; ++delcounter
) {
48 DNSName a
=DNSName("hello ")+DNSName(std::to_string(delcounter
));
49 BOOST_CHECK_EQUAL(QC
.purge(a
.toString()), 1);
52 BOOST_CHECK_EQUAL(QC
.size(), counter
-delcounter
);
55 vector
<DNSZoneRecord
> entry
;
56 int64_t expected
=counter
-delcounter
;
57 for(; delcounter
< counter
; ++delcounter
) {
58 if(QC
.getEntry(DNSName("hello ")+DNSName(std::to_string(delcounter
)), QType(QType::A
), entry
, 1)) {
62 BOOST_CHECK_EQUAL(matches
, expected
);
63 BOOST_CHECK_EQUAL(entry
.size(), records
.size());
65 catch(PDNSException
& e
) {
66 cerr
<<"Had error: "<<e
.reason
<<endl
;
72 static AuthQueryCache
* g_QC
;
73 static AtomicCounter g_QCmissing
;
75 static void *threadQCMangler(void* a
)
78 vector
<DNSZoneRecord
> records
;
79 unsigned int offset
=(unsigned int)(unsigned long)a
;
80 for(unsigned int counter
=0; counter
< 100000; ++counter
)
81 g_QC
->insert(DNSName("hello ")+DNSName(std::to_string(counter
+offset
)), QType(QType::A
), records
, 3600, 1);
84 catch(PDNSException
& e
) {
85 cerr
<<"Had error: "<<e
.reason
<<endl
;
89 static void *threadQCReader(void* a
)
92 unsigned int offset
=(unsigned int)(unsigned long)a
;
93 vector
<DNSZoneRecord
> entry
;
94 for(unsigned int counter
=0; counter
< 100000; ++counter
)
95 if(!g_QC
->getEntry(DNSName("hello ")+DNSName(std::to_string(counter
+offset
)), QType(QType::A
), entry
, 1)) {
100 catch(PDNSException
& e
) {
101 cerr
<<"Had error in threadQCReader: "<<e
.reason
<<endl
;
105 BOOST_AUTO_TEST_CASE(test_QueryCacheThreaded
) {
109 QC
.setMaxEntries(1000000);
112 for(int i
=0; i
< 4; ++i
)
113 pthread_create(&tid
[i
], 0, threadQCMangler
, (void*)(i
*1000000UL));
115 for(int i
=0; i
< 4 ; ++i
)
116 pthread_join(tid
[i
], &res
);
118 BOOST_CHECK_EQUAL(QC
.size() + S
.read("deferred-cache-inserts"), 400000);
119 BOOST_CHECK_SMALL(1.0*S
.read("deferred-cache-inserts"), 10000.0);
121 for(int i
=0; i
< 4; ++i
)
122 pthread_create(&tid
[i
], 0, threadQCReader
, (void*)(i
*1000000UL));
123 for(int i
=0; i
< 4 ; ++i
)
124 pthread_join(tid
[i
], &res
);
126 BOOST_CHECK(S
.read("deferred-cache-inserts") + S
.read("deferred-cache-lookup") >= g_QCmissing
);
127 // BOOST_CHECK_EQUAL(S.read("deferred-cache-lookup"), 0); // cache cleaning invalidates this
129 catch(PDNSException
& e
) {
130 cerr
<<"Had error: "<<e
.reason
<<endl
;
136 static AuthPacketCache
* g_PC
;
137 static AtomicCounter g_PCmissing
;
139 static void *threadPCMangler(void* a
)
142 unsigned int offset
=(unsigned int)(unsigned long)a
;
143 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
145 DNSName qname
= DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
147 DNSPacketWriter
pw(pak
, qname
, QType::A
);
149 q
.parse((char*)&pak
[0], pak
.size());
152 DNSPacketWriter
pw2(pak
, qname
, QType::A
);
153 pw2
.startRecord(qname
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
);
154 pw2
.xfrIP(htonl(0x7f000001));
158 r
.parse((char*)&pak
[0], pak
.size());
160 /* this step is necessary to get a valid hash
161 we directly compute the hash instead of querying the
162 cache because 1/ it's faster 2/ no deferred-lookup issues
164 q
.setHash(g_PC
->canHashPacket(q
.getString()));
166 const unsigned int maxTTL
= 3600;
167 g_PC
->insert(&q
, &r
, maxTTL
);
172 catch(PDNSException
& e
) {
173 cerr
<<"Had error: "<<e
.reason
<<endl
;
177 static void *threadPCReader(void* a
)
180 unsigned int offset
=(unsigned int)(unsigned long)a
;
181 vector
<DNSZoneRecord
> entry
;
182 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
184 DNSName qname
= DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
186 DNSPacketWriter
pw(pak
, qname
, QType::A
);
188 q
.parse((char*)&pak
[0], pak
.size());
191 if(!g_PC
->get(&q
, &r
)) {
198 catch(PDNSException
& e
) {
199 cerr
<<"Had error in threadPCReader: "<<e
.reason
<<endl
;
203 BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded
) {
206 PC
.setMaxEntries(1000000);
212 for(int i
=0; i
< 4; ++i
)
213 pthread_create(&tid
[i
], 0, threadPCMangler
, (void*)(i
*1000000UL));
215 for(int i
=0; i
< 4 ; ++i
)
216 pthread_join(tid
[i
], &res
);
218 BOOST_CHECK_EQUAL(PC
.size() + S
.read("deferred-packetcache-inserts"), 400000);
219 BOOST_CHECK_EQUAL(S
.read("deferred-packetcache-lookup"), 0);
220 BOOST_CHECK_SMALL(1.0*S
.read("deferred-packetcache-inserts"), 10000.0);
222 for(int i
=0; i
< 4; ++i
)
223 pthread_create(&tid
[i
], 0, threadPCReader
, (void*)(i
*1000000UL));
224 for(int i
=0; i
< 4 ; ++i
)
225 pthread_join(tid
[i
], &res
);
228 cerr<<"Misses: "<<S.read("packetcache-miss")<<endl;
229 cerr<<"Hits: "<<S.read("packetcache-hit")<<endl;
230 cerr<<"Deferred inserts: "<<S.read("deferred-packetcache-inserts")<<endl;
231 cerr<<"Deferred lookups: "<<S.read("deferred-packetcache-lookup")<<endl;
232 cerr<<g_PCmissing<<endl;
233 cerr<<PC.size()<<endl;
236 BOOST_CHECK_EQUAL(g_PCmissing
+ S
.read("packetcache-hit"), 400000);
237 BOOST_CHECK_EQUAL(S
.read("deferred-packetcache-inserts") + S
.read("deferred-packetcache-lookup"), g_PCmissing
);
239 catch(PDNSException
& e
) {
240 cerr
<<"Had error: "<<e
.reason
<<endl
;
247 static void *cacheCleaner(void*)
250 while(!g_stopCleaning
) {
256 catch(PDNSException
& e
) {
257 cerr
<<"Had error in cacheCleaner: "<<e
.reason
<<endl
;
261 BOOST_AUTO_TEST_CASE(test_QueryCacheClean
) {
264 QC
.setMaxEntries(10000);
265 vector
<DNSZoneRecord
> records
;
267 for(unsigned int counter
= 0; counter
< 1000000; ++counter
) {
268 QC
.insert(DNSName("hello ")+DNSName(std::to_string(counter
)), QType(QType::A
), records
, 1, 1);
276 pthread_create(&tid
[0], 0, threadQCReader
, (void*)(0*1000000UL));
277 pthread_create(&tid
[1], 0, threadQCReader
, (void*)(1*1000000UL));
278 pthread_create(&tid
[2], 0, threadQCReader
, (void*)(2*1000000UL));
279 // pthread_create(&tid[2], 0, threadMangler, (void*)(0*1000000UL));
280 pthread_create(&tid
[3], 0, cacheCleaner
, 0);
283 for(int i
=0; i
< 3 ; ++i
)
284 pthread_join(tid
[i
], &res
);
286 pthread_join(tid
[3], &res
);
288 catch(PDNSException
& e
) {
289 cerr
<<"Had error in test_QueryCacheClean: "<<e
.reason
<<endl
;
294 BOOST_AUTO_TEST_CASE(test_AuthPacketCache
) {
296 ::arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
300 PC
.setMaxEntries(100000);
303 DNSPacket
q(true), differentIDQ(true), ednsQ(true), ednsVersion42(true), ednsDO(true), ecs1(true), ecs2(true), ecs3(true);
304 DNSPacket
r(false), r2(false);
307 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
308 q
.parse((char*)&pak
[0], pak
.size());
310 differentIDQ
.parse((char*)&pak
[0], pak
.size());
311 differentIDQ
.setID(4242);
313 pw
.addOpt(512, 0, 0);
315 ednsQ
.parse((char*)&pak
[0], pak
.size());
320 DNSPacketWriter::optvect_t opts
;
321 EDNSSubnetOpts ecsOpts
;
323 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
324 pw
.addOpt(512, 0, 0, DNSPacketWriter::optvect_t(), 42);
326 ednsVersion42
.parse((char*)&pak
[0], pak
.size());
331 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
332 pw
.addOpt(512, 0, EDNSOpts::DNSSECOK
);
334 ednsDO
.parse((char*)&pak
[0], pak
.size());
339 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.1"), 32);
340 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
341 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
342 pw
.addOpt(512, 0, 0, opts
);
344 ecs1
.parse((char*)&pak
[0], pak
.size());
350 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
351 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.2"), 32);
352 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
353 pw
.addOpt(512, 0, 0, opts
);
355 ecs2
.parse((char*)&pak
[0], pak
.size());
361 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
362 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.3"), 16);
363 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
364 pw
.addOpt(512, 0, 0, opts
);
366 ecs3
.parse((char*)&pak
[0], pak
.size());
372 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
373 pw
.startRecord(DNSName("www.powerdns.com"), QType::A
, 16, 1, DNSResourceRecord::ANSWER
);
374 pw
.xfrIP(htonl(0x7f000001));
377 r
.parse((char*)&pak
[0], pak
.size());
380 /* this call is required so the correct hash is set into q->d_hash */
381 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
383 PC
.insert(&q
, &r
, 3600);
384 BOOST_CHECK_EQUAL(PC
.size(), 1);
386 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
387 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
389 /* different QID, still should match */
390 BOOST_CHECK_EQUAL(PC
.get(&differentIDQ
, &r2
), true);
391 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
393 /* with EDNS, should not match */
394 BOOST_CHECK_EQUAL(PC
.get(&ednsQ
, &r2
), false);
395 /* inserting the EDNS-enabled one too */
396 PC
.insert(&ednsQ
, &r
, 3600);
397 BOOST_CHECK_EQUAL(PC
.size(), 2);
399 /* different EDNS versions, should not match */
400 BOOST_CHECK_EQUAL(PC
.get(&ednsVersion42
, &r2
), false);
402 /* EDNS DO set, should not match */
403 BOOST_CHECK_EQUAL(PC
.get(&ednsDO
, &r2
), false);
405 /* EDNS Client Subnet set, should not match
406 since not only we don't skip the actual option, but the
407 total EDNS opt RR is still different. */
408 BOOST_CHECK_EQUAL(PC
.get(&ecs1
, &r2
), false);
410 /* inserting the version with ECS Client Subnet set,
411 it should NOT replace the existing EDNS one. */
412 PC
.insert(&ecs1
, &r
, 3600);
413 BOOST_CHECK_EQUAL(PC
.size(), 3);
415 /* different subnet of same size, should NOT match
416 since we don't skip the option */
417 BOOST_CHECK_EQUAL(PC
.get(&ecs2
, &r2
), false);
418 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
420 /* different subnet of different size, should NOT match. */
421 BOOST_CHECK_EQUAL(PC
.get(&ecs3
, &r2
), false);
423 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com"), 3);
424 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
425 BOOST_CHECK_EQUAL(PC
.size(), 0);
427 PC
.insert(&q
, &r
, 3600);
428 BOOST_CHECK_EQUAL(PC
.size(), 1);
429 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
430 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
431 BOOST_CHECK_EQUAL(PC
.purge("com$"), 1);
432 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
433 BOOST_CHECK_EQUAL(PC
.size(), 0);
435 PC
.insert(&q
, &r
, 3600);
436 BOOST_CHECK_EQUAL(PC
.size(), 1);
437 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
438 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
439 BOOST_CHECK_EQUAL(PC
.purge("powerdns.com$"), 1);
440 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
441 BOOST_CHECK_EQUAL(PC
.size(), 0);
443 PC
.insert(&q
, &r
, 3600);
444 BOOST_CHECK_EQUAL(PC
.size(), 1);
445 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
446 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
447 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com$"), 1);
448 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
449 BOOST_CHECK_EQUAL(PC
.size(), 0);
451 PC
.insert(&q
, &r
, 3600);
452 BOOST_CHECK_EQUAL(PC
.size(), 1);
453 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.net"), 0);
454 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
455 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
456 BOOST_CHECK_EQUAL(PC
.size(), 1);
458 BOOST_CHECK_EQUAL(PC
.purge("net$"), 0);
459 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
460 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
461 BOOST_CHECK_EQUAL(PC
.size(), 1);
463 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com$"), 1);
464 BOOST_CHECK_EQUAL(PC
.size(), 0);
466 catch(PDNSException
& e
) {
467 cerr
<<"Had error in AuthPacketCache: "<<e
.reason
<<endl
;
472 BOOST_AUTO_TEST_SUITE_END()