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 DNSPacket
cached(false);
161 g_PC
->get(&q
, &cached
);
163 const unsigned int maxTTL
= 3600;
164 g_PC
->insert(&q
, &r
, maxTTL
);
169 catch(PDNSException
& e
) {
170 cerr
<<"Had error: "<<e
.reason
<<endl
;
174 static void *threadPCReader(void* a
)
177 unsigned int offset
=(unsigned int)(unsigned long)a
;
178 vector
<DNSZoneRecord
> entry
;
179 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
181 DNSName qname
= DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
183 DNSPacketWriter
pw(pak
, qname
, QType::A
);
185 q
.parse((char*)&pak
[0], pak
.size());
188 if(!g_PC
->get(&q
, &r
)) {
195 catch(PDNSException
& e
) {
196 cerr
<<"Had error in threadPCReader: "<<e
.reason
<<endl
;
200 BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded
) {
203 PC
.setMaxEntries(1000000);
208 for(int i
=0; i
< 4; ++i
)
209 pthread_create(&tid
[i
], 0, threadPCMangler
, (void*)(i
*1000000UL));
211 for(int i
=0; i
< 4 ; ++i
)
212 pthread_join(tid
[i
], &res
);
214 BOOST_CHECK_EQUAL(PC
.size() + S
.read("deferred-packetcache-inserts"), 400000);
215 BOOST_CHECK_SMALL(1.0*S
.read("deferred-packetcache-inserts"), 10000.0);
217 for(int i
=0; i
< 4; ++i
)
218 pthread_create(&tid
[i
], 0, threadPCReader
, (void*)(i
*1000000UL));
219 for(int i
=0; i
< 4 ; ++i
)
220 pthread_join(tid
[i
], &res
);
223 cerr<<"Misses: "<<S.read("packetcache-miss")<<endl;
224 cerr<<"Hits: "<<S.read("packetcache-hit")<<endl;
225 cerr<<"Deferred inserts: "<<S.read("deferred-packetcache-inserts")<<endl;
226 cerr<<"Deferred lookups: "<<S.read("deferred-packetcache-lookup")<<endl;
228 BOOST_CHECK_EQUAL(g_PCmissing
+ S
.read("packetcache-hit"), 400000);
229 BOOST_CHECK_GT(S
.read("deferred-packetcache-inserts") + S
.read("deferred-packetcache-lookup"), g_PCmissing
);
231 catch(PDNSException
& e
) {
232 cerr
<<"Had error: "<<e
.reason
<<endl
;
239 static void *cacheCleaner(void*)
242 while(!g_stopCleaning
) {
248 catch(PDNSException
& e
) {
249 cerr
<<"Had error in cacheCleaner: "<<e
.reason
<<endl
;
253 BOOST_AUTO_TEST_CASE(test_QueryCacheClean
) {
256 QC
.setMaxEntries(10000);
257 vector
<DNSZoneRecord
> records
;
259 for(unsigned int counter
= 0; counter
< 1000000; ++counter
) {
260 QC
.insert(DNSName("hello ")+DNSName(std::to_string(counter
)), QType(QType::A
), records
, 1, 1);
268 pthread_create(&tid
[0], 0, threadQCReader
, (void*)(0*1000000UL));
269 pthread_create(&tid
[1], 0, threadQCReader
, (void*)(1*1000000UL));
270 pthread_create(&tid
[2], 0, threadQCReader
, (void*)(2*1000000UL));
271 // pthread_create(&tid[2], 0, threadMangler, (void*)(0*1000000UL));
272 pthread_create(&tid
[3], 0, cacheCleaner
, 0);
275 for(int i
=0; i
< 3 ; ++i
)
276 pthread_join(tid
[i
], &res
);
278 pthread_join(tid
[3], &res
);
280 catch(PDNSException
& e
) {
281 cerr
<<"Had error in test_QueryCacheClean: "<<e
.reason
<<endl
;
286 BOOST_AUTO_TEST_CASE(test_AuthPacketCache
) {
288 ::arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
292 PC
.setMaxEntries(100000);
295 DNSPacket
q(true), differentIDQ(true), ednsQ(true), ednsVersion42(true), ednsDO(true), ecs1(true), ecs2(true), ecs3(true);
296 DNSPacket
r(false), r2(false);
299 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
300 q
.parse((char*)&pak
[0], pak
.size());
302 differentIDQ
.parse((char*)&pak
[0], pak
.size());
303 differentIDQ
.setID(4242);
305 pw
.addOpt(512, 0, 0);
307 ednsQ
.parse((char*)&pak
[0], pak
.size());
312 DNSPacketWriter::optvect_t opts
;
313 EDNSSubnetOpts ecsOpts
;
315 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
316 pw
.addOpt(512, 0, 0, DNSPacketWriter::optvect_t(), 42);
318 ednsVersion42
.parse((char*)&pak
[0], pak
.size());
323 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
324 pw
.addOpt(512, 0, EDNSOpts::DNSSECOK
);
326 ednsDO
.parse((char*)&pak
[0], pak
.size());
331 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.1"), 32);
332 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
333 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
334 pw
.addOpt(512, 0, 0, opts
);
336 ecs1
.parse((char*)&pak
[0], pak
.size());
342 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
343 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.2"), 32);
344 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
345 pw
.addOpt(512, 0, 0, opts
);
347 ecs2
.parse((char*)&pak
[0], pak
.size());
353 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
354 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.3"), 16);
355 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
356 pw
.addOpt(512, 0, 0, opts
);
358 ecs3
.parse((char*)&pak
[0], pak
.size());
364 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
365 pw
.startRecord(DNSName("www.powerdns.com"), QType::A
, 16, 1, DNSResourceRecord::ANSWER
);
366 pw
.xfrIP(htonl(0x7f000001));
369 r
.parse((char*)&pak
[0], pak
.size());
372 /* this call is required so the correct hash is set into q->d_hash */
373 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
375 PC
.insert(&q
, &r
, 3600);
376 BOOST_CHECK_EQUAL(PC
.size(), 1);
378 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
379 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
381 /* different QID, still should match */
382 BOOST_CHECK_EQUAL(PC
.get(&differentIDQ
, &r2
), true);
383 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
385 /* with EDNS, should not match */
386 BOOST_CHECK_EQUAL(PC
.get(&ednsQ
, &r2
), false);
387 /* inserting the EDNS-enabled one too */
388 PC
.insert(&ednsQ
, &r
, 3600);
389 BOOST_CHECK_EQUAL(PC
.size(), 2);
391 /* different EDNS versions, should not match */
392 BOOST_CHECK_EQUAL(PC
.get(&ednsVersion42
, &r2
), false);
394 /* EDNS DO set, should not match */
395 BOOST_CHECK_EQUAL(PC
.get(&ednsDO
, &r2
), false);
397 /* EDNS Client Subnet set, should not match
398 since not only we don't skip the actual option, but the
399 total EDNS opt RR is still different. */
400 BOOST_CHECK_EQUAL(PC
.get(&ecs1
, &r2
), false);
402 /* inserting the version with ECS Client Subnet set,
403 it should NOT replace the existing EDNS one. */
404 PC
.insert(&ecs1
, &r
, 3600);
405 BOOST_CHECK_EQUAL(PC
.size(), 3);
407 /* different subnet of same size, should NOT match
408 since we don't skip the option */
409 BOOST_CHECK_EQUAL(PC
.get(&ecs2
, &r2
), false);
410 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
412 /* different subnet of different size, should NOT match. */
413 BOOST_CHECK_EQUAL(PC
.get(&ecs3
, &r2
), false);
415 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com"), 3);
416 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
417 BOOST_CHECK_EQUAL(PC
.size(), 0);
419 PC
.insert(&q
, &r
, 3600);
420 BOOST_CHECK_EQUAL(PC
.size(), 1);
421 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
422 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
423 BOOST_CHECK_EQUAL(PC
.purge("com$"), 1);
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("powerdns.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("www.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
.purge("www.powerdns.net"), 0);
446 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
447 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
448 BOOST_CHECK_EQUAL(PC
.size(), 1);
450 BOOST_CHECK_EQUAL(PC
.purge("net$"), 0);
451 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
452 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
453 BOOST_CHECK_EQUAL(PC
.size(), 1);
455 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com$"), 1);
456 BOOST_CHECK_EQUAL(PC
.size(), 0);
458 catch(PDNSException
& e
) {
459 cerr
<<"Had error in AuthPacketCache: "<<e
.reason
<<endl
;
464 BOOST_AUTO_TEST_SUITE_END()