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
) {
108 QC
.setMaxEntries(1000000);
111 for(int i
=0; i
< 4; ++i
)
112 pthread_create(&tid
[i
], 0, threadQCMangler
, (void*)(i
*1000000UL));
114 for(int i
=0; i
< 4 ; ++i
)
115 pthread_join(tid
[i
], &res
);
117 BOOST_CHECK_EQUAL(QC
.size() + S
.read("deferred-cache-inserts"), 400000);
118 BOOST_CHECK_SMALL(1.0*S
.read("deferred-cache-inserts"), 10000.0);
120 for(int i
=0; i
< 4; ++i
)
121 pthread_create(&tid
[i
], 0, threadQCReader
, (void*)(i
*1000000UL));
122 for(int i
=0; i
< 4 ; ++i
)
123 pthread_join(tid
[i
], &res
);
125 BOOST_CHECK(S
.read("deferred-cache-inserts") + S
.read("deferred-cache-lookup") >= g_QCmissing
);
126 // BOOST_CHECK_EQUAL(S.read("deferred-cache-lookup"), 0); // cache cleaning invalidates this
128 catch(PDNSException
& e
) {
129 cerr
<<"Had error: "<<e
.reason
<<endl
;
135 static AuthPacketCache
* g_PC
;
136 static AtomicCounter g_PCmissing
;
138 static void *threadPCMangler(void* a
)
141 unsigned int offset
=(unsigned int)(unsigned long)a
;
142 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
144 DNSName qname
= DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
146 DNSPacketWriter
pw(pak
, qname
, QType::A
);
148 q
.parse((char*)&pak
[0], pak
.size());
151 DNSPacketWriter
pw2(pak
, qname
, QType::A
);
152 pw2
.startRecord(qname
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
);
153 pw2
.xfrIP(htonl(0x7f000001));
157 r
.parse((char*)&pak
[0], pak
.size());
159 /* this step is necessary to get a valid hash
160 we directly compute the hash instead of querying the
161 cache because 1/ it's faster 2/ no deferred-lookup issues
163 q
.setHash(g_PC
->canHashPacket(q
.getString()));
165 const unsigned int maxTTL
= 3600;
166 g_PC
->insert(&q
, &r
, maxTTL
);
171 catch(PDNSException
& e
) {
172 cerr
<<"Had error: "<<e
.reason
<<endl
;
176 static void *threadPCReader(void* a
)
179 unsigned int offset
=(unsigned int)(unsigned long)a
;
180 vector
<DNSZoneRecord
> entry
;
181 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
183 DNSName qname
= DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
185 DNSPacketWriter
pw(pak
, qname
, QType::A
);
187 q
.parse((char*)&pak
[0], pak
.size());
190 if(!g_PC
->get(&q
, &r
)) {
197 catch(PDNSException
& e
) {
198 cerr
<<"Had error in threadPCReader: "<<e
.reason
<<endl
;
202 BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded
) {
205 PC
.setMaxEntries(1000000);
210 for(int i
=0; i
< 4; ++i
)
211 pthread_create(&tid
[i
], 0, threadPCMangler
, (void*)(i
*1000000UL));
213 for(int i
=0; i
< 4 ; ++i
)
214 pthread_join(tid
[i
], &res
);
216 BOOST_CHECK_EQUAL(PC
.size() + S
.read("deferred-packetcache-inserts"), 400000);
217 BOOST_CHECK_EQUAL(S
.read("deferred-packetcache-lookup"), 0);
218 BOOST_CHECK_SMALL(1.0*S
.read("deferred-packetcache-inserts"), 10000.0);
220 for(int i
=0; i
< 4; ++i
)
221 pthread_create(&tid
[i
], 0, threadPCReader
, (void*)(i
*1000000UL));
222 for(int i
=0; i
< 4 ; ++i
)
223 pthread_join(tid
[i
], &res
);
226 cerr<<"Misses: "<<S.read("packetcache-miss")<<endl;
227 cerr<<"Hits: "<<S.read("packetcache-hit")<<endl;
228 cerr<<"Deferred inserts: "<<S.read("deferred-packetcache-inserts")<<endl;
229 cerr<<"Deferred lookups: "<<S.read("deferred-packetcache-lookup")<<endl;
230 cerr<<g_PCmissing<<endl;
231 cerr<<PC.size()<<endl;
234 BOOST_CHECK_EQUAL(g_PCmissing
+ S
.read("packetcache-hit"), 400000);
235 BOOST_CHECK_EQUAL(S
.read("deferred-packetcache-inserts") + S
.read("deferred-packetcache-lookup"), g_PCmissing
);
237 catch(PDNSException
& e
) {
238 cerr
<<"Had error: "<<e
.reason
<<endl
;
245 static void *cacheCleaner(void*)
248 while(!g_stopCleaning
) {
254 catch(PDNSException
& e
) {
255 cerr
<<"Had error in cacheCleaner: "<<e
.reason
<<endl
;
259 BOOST_AUTO_TEST_CASE(test_QueryCacheClean
) {
262 QC
.setMaxEntries(10000);
263 vector
<DNSZoneRecord
> records
;
265 for(unsigned int counter
= 0; counter
< 1000000; ++counter
) {
266 QC
.insert(DNSName("hello ")+DNSName(std::to_string(counter
)), QType(QType::A
), records
, 1, 1);
274 pthread_create(&tid
[0], 0, threadQCReader
, (void*)(0*1000000UL));
275 pthread_create(&tid
[1], 0, threadQCReader
, (void*)(1*1000000UL));
276 pthread_create(&tid
[2], 0, threadQCReader
, (void*)(2*1000000UL));
277 // pthread_create(&tid[2], 0, threadMangler, (void*)(0*1000000UL));
278 pthread_create(&tid
[3], 0, cacheCleaner
, 0);
281 for(int i
=0; i
< 3 ; ++i
)
282 pthread_join(tid
[i
], &res
);
284 pthread_join(tid
[3], &res
);
286 catch(PDNSException
& e
) {
287 cerr
<<"Had error in test_QueryCacheClean: "<<e
.reason
<<endl
;
292 BOOST_AUTO_TEST_CASE(test_AuthPacketCache
) {
294 ::arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
298 PC
.setMaxEntries(100000);
301 DNSPacket
q(true), differentIDQ(true), ednsQ(true), ednsVersion42(true), ednsDO(true), ecs1(true), ecs2(true), ecs3(true);
302 DNSPacket
r(false), r2(false);
305 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
306 q
.parse((char*)&pak
[0], pak
.size());
308 differentIDQ
.parse((char*)&pak
[0], pak
.size());
309 differentIDQ
.setID(4242);
311 pw
.addOpt(512, 0, 0);
313 ednsQ
.parse((char*)&pak
[0], pak
.size());
318 DNSPacketWriter::optvect_t opts
;
319 EDNSSubnetOpts ecsOpts
;
321 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
322 pw
.addOpt(512, 0, 0, DNSPacketWriter::optvect_t(), 42);
324 ednsVersion42
.parse((char*)&pak
[0], pak
.size());
329 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
330 pw
.addOpt(512, 0, EDNSOpts::DNSSECOK
);
332 ednsDO
.parse((char*)&pak
[0], pak
.size());
337 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.1"), 32);
338 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
339 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
340 pw
.addOpt(512, 0, 0, opts
);
342 ecs1
.parse((char*)&pak
[0], pak
.size());
348 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
349 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.2"), 32);
350 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
351 pw
.addOpt(512, 0, 0, opts
);
353 ecs2
.parse((char*)&pak
[0], pak
.size());
359 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
360 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.3"), 16);
361 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
362 pw
.addOpt(512, 0, 0, opts
);
364 ecs3
.parse((char*)&pak
[0], pak
.size());
370 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
371 pw
.startRecord(DNSName("www.powerdns.com"), QType::A
, 16, 1, DNSResourceRecord::ANSWER
);
372 pw
.xfrIP(htonl(0x7f000001));
375 r
.parse((char*)&pak
[0], pak
.size());
378 /* this call is required so the correct hash is set into q->d_hash */
379 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
381 PC
.insert(&q
, &r
, 3600);
382 BOOST_CHECK_EQUAL(PC
.size(), 1);
384 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
385 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
387 /* different QID, still should match */
388 BOOST_CHECK_EQUAL(PC
.get(&differentIDQ
, &r2
), true);
389 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
391 /* with EDNS, should not match */
392 BOOST_CHECK_EQUAL(PC
.get(&ednsQ
, &r2
), false);
393 /* inserting the EDNS-enabled one too */
394 PC
.insert(&ednsQ
, &r
, 3600);
395 BOOST_CHECK_EQUAL(PC
.size(), 2);
397 /* different EDNS versions, should not match */
398 BOOST_CHECK_EQUAL(PC
.get(&ednsVersion42
, &r2
), false);
400 /* EDNS DO set, should not match */
401 BOOST_CHECK_EQUAL(PC
.get(&ednsDO
, &r2
), false);
403 /* EDNS Client Subnet set, should not match
404 since not only we don't skip the actual option, but the
405 total EDNS opt RR is still different. */
406 BOOST_CHECK_EQUAL(PC
.get(&ecs1
, &r2
), false);
408 /* inserting the version with ECS Client Subnet set,
409 it should NOT replace the existing EDNS one. */
410 PC
.insert(&ecs1
, &r
, 3600);
411 BOOST_CHECK_EQUAL(PC
.size(), 3);
413 /* different subnet of same size, should NOT match
414 since we don't skip the option */
415 BOOST_CHECK_EQUAL(PC
.get(&ecs2
, &r2
), false);
416 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
418 /* different subnet of different size, should NOT match. */
419 BOOST_CHECK_EQUAL(PC
.get(&ecs3
, &r2
), false);
421 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com"), 3);
422 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
423 BOOST_CHECK_EQUAL(PC
.size(), 0);
425 PC
.insert(&q
, &r
, 3600);
426 BOOST_CHECK_EQUAL(PC
.size(), 1);
427 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
428 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
429 BOOST_CHECK_EQUAL(PC
.purge("com$"), 1);
430 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
431 BOOST_CHECK_EQUAL(PC
.size(), 0);
433 PC
.insert(&q
, &r
, 3600);
434 BOOST_CHECK_EQUAL(PC
.size(), 1);
435 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
436 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
437 BOOST_CHECK_EQUAL(PC
.purge("powerdns.com$"), 1);
438 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
439 BOOST_CHECK_EQUAL(PC
.size(), 0);
441 PC
.insert(&q
, &r
, 3600);
442 BOOST_CHECK_EQUAL(PC
.size(), 1);
443 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
444 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
445 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com$"), 1);
446 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
447 BOOST_CHECK_EQUAL(PC
.size(), 0);
449 PC
.insert(&q
, &r
, 3600);
450 BOOST_CHECK_EQUAL(PC
.size(), 1);
451 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.net"), 0);
452 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
453 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
454 BOOST_CHECK_EQUAL(PC
.size(), 1);
456 BOOST_CHECK_EQUAL(PC
.purge("net$"), 0);
457 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
458 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
459 BOOST_CHECK_EQUAL(PC
.size(), 1);
461 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com$"), 1);
462 BOOST_CHECK_EQUAL(PC
.size(), 0);
464 catch(PDNSException
& e
) {
465 cerr
<<"Had error in AuthPacketCache: "<<e
.reason
<<endl
;
470 BOOST_AUTO_TEST_SUITE_END()