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(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
, 16, 1, 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 g_PC
->insert(&q
, &r
, 10);
168 catch(PDNSException
& e
) {
169 cerr
<<"Had error: "<<e
.reason
<<endl
;
173 static void *threadPCReader(void* a
)
176 unsigned int offset
=(unsigned int)(unsigned long)a
;
177 vector
<DNSZoneRecord
> entry
;
178 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
180 DNSName qname
= DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
182 DNSPacketWriter
pw(pak
, qname
, QType::A
);
184 q
.parse((char*)&pak
[0], pak
.size());
187 if(!g_PC
->get(&q
, &r
)) {
194 catch(PDNSException
& e
) {
195 cerr
<<"Had error in threadPCReader: "<<e
.reason
<<endl
;
199 BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded
) {
202 PC
.setMaxEntries(1000000);
207 for(int i
=0; i
< 4; ++i
)
208 pthread_create(&tid
[i
], 0, threadPCMangler
, (void*)(i
*1000000UL));
210 for(int i
=0; i
< 4 ; ++i
)
211 pthread_join(tid
[i
], &res
);
213 BOOST_CHECK_EQUAL(PC
.size() + S
.read("deferred-packetcache-inserts"), 400000);
214 BOOST_CHECK_SMALL(1.0*S
.read("deferred-packetcache-inserts"), 10000.0);
216 for(int i
=0; i
< 4; ++i
)
217 pthread_create(&tid
[i
], 0, threadPCReader
, (void*)(i
*1000000UL));
218 for(int i
=0; i
< 4 ; ++i
)
219 pthread_join(tid
[i
], &res
);
222 cerr<<"Misses: "<<S.read("packetcache-miss")<<endl;
223 cerr<<"Hits: "<<S.read("packetcache-hit")<<endl;
224 cerr<<"Deferred inserts: "<<S.read("deferred-packetcache-inserts")<<endl;
225 cerr<<"Deferred lookups: "<<S.read("deferred-packetcache-lookup")<<endl;
227 BOOST_CHECK_EQUAL(g_PCmissing
+ S
.read("packetcache-hit"), 400000);
228 BOOST_CHECK_GT(S
.read("deferred-packetcache-inserts") + S
.read("deferred-packetcache-lookup"), g_PCmissing
);
230 catch(PDNSException
& e
) {
231 cerr
<<"Had error: "<<e
.reason
<<endl
;
238 static void *cacheCleaner(void*)
241 while(!g_stopCleaning
) {
247 catch(PDNSException
& e
) {
248 cerr
<<"Had error in cacheCleaner: "<<e
.reason
<<endl
;
252 BOOST_AUTO_TEST_CASE(test_QueryCacheClean
) {
255 QC
.setMaxEntries(10000);
256 vector
<DNSZoneRecord
> records
;
258 for(unsigned int counter
= 0; counter
< 1000000; ++counter
) {
259 QC
.insert(DNSName("hello ")+DNSName(std::to_string(counter
)), QType(QType::A
), records
, 1, 1);
267 pthread_create(&tid
[0], 0, threadQCReader
, (void*)(0*1000000UL));
268 pthread_create(&tid
[1], 0, threadQCReader
, (void*)(1*1000000UL));
269 pthread_create(&tid
[2], 0, threadQCReader
, (void*)(2*1000000UL));
270 // pthread_create(&tid[2], 0, threadMangler, (void*)(0*1000000UL));
271 pthread_create(&tid
[3], 0, cacheCleaner
, 0);
274 for(int i
=0; i
< 3 ; ++i
)
275 pthread_join(tid
[i
], &res
);
277 pthread_join(tid
[3], &res
);
279 catch(PDNSException
& e
) {
280 cerr
<<"Had error in test_QueryCacheClean: "<<e
.reason
<<endl
;
285 BOOST_AUTO_TEST_CASE(test_AuthPacketCache
) {
287 ::arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
291 PC
.setMaxEntries(100000);
294 DNSPacket
q(true), differentIDQ(true), ednsQ(true), ednsVersion42(true), ednsDO(true), ecs1(true), ecs2(true), ecs3(true);
295 DNSPacket
r(false), r2(false);
298 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
299 q
.parse((char*)&pak
[0], pak
.size());
301 differentIDQ
.parse((char*)&pak
[0], pak
.size());
302 differentIDQ
.setID(4242);
304 pw
.addOpt(512, 0, 0);
306 ednsQ
.parse((char*)&pak
[0], pak
.size());
311 DNSPacketWriter::optvect_t opts
;
312 EDNSSubnetOpts ecsOpts
;
314 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
315 pw
.addOpt(512, 0, 0, DNSPacketWriter::optvect_t(), 42);
317 ednsVersion42
.parse((char*)&pak
[0], pak
.size());
322 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
323 pw
.addOpt(512, 0, EDNSOpts::DNSSECOK
);
325 ednsDO
.parse((char*)&pak
[0], pak
.size());
330 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.1"), 32);
331 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
332 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
333 pw
.addOpt(512, 0, 0, opts
);
335 ecs1
.parse((char*)&pak
[0], pak
.size());
341 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
342 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.2"), 32);
343 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
344 pw
.addOpt(512, 0, 0, opts
);
346 ecs2
.parse((char*)&pak
[0], pak
.size());
352 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
353 ecsOpts
.source
= Netmask(ComboAddress("192.0.2.3"), 16);
354 opts
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(ecsOpts
)));
355 pw
.addOpt(512, 0, 0, opts
);
357 ecs3
.parse((char*)&pak
[0], pak
.size());
363 DNSPacketWriter
pw(pak
, DNSName("www.powerdns.com"), QType::A
);
364 pw
.startRecord(DNSName("www.powerdns.com"), QType::A
, 16, 1, DNSResourceRecord::ANSWER
);
365 pw
.xfrIP(htonl(0x7f000001));
368 r
.parse((char*)&pak
[0], pak
.size());
371 /* this call is required so the correct hash is set into q->d_hash */
372 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
374 PC
.insert(&q
, &r
, 3600);
375 BOOST_CHECK_EQUAL(PC
.size(), 1);
377 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
378 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
380 /* different QID, still should match */
381 BOOST_CHECK_EQUAL(PC
.get(&differentIDQ
, &r2
), true);
382 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
384 /* with EDNS, should not match */
385 BOOST_CHECK_EQUAL(PC
.get(&ednsQ
, &r2
), false);
386 /* inserting the EDNS-enabled one too */
387 PC
.insert(&ednsQ
, &r
, 3600);
388 BOOST_CHECK_EQUAL(PC
.size(), 2);
390 /* different EDNS versions, should not match */
391 BOOST_CHECK_EQUAL(PC
.get(&ednsVersion42
, &r2
), false);
393 /* EDNS DO set, should not match */
394 BOOST_CHECK_EQUAL(PC
.get(&ednsDO
, &r2
), false);
396 /* EDNS Client Subnet set, should not match
397 since not only we don't skip the actual option, but the
398 total EDNS opt RR is still different. */
399 BOOST_CHECK_EQUAL(PC
.get(&ecs1
, &r2
), false);
401 /* inserting the version with ECS Client Subnet set,
402 it should NOT replace the existing EDNS one. */
403 PC
.insert(&ecs1
, &r
, 3600);
404 BOOST_CHECK_EQUAL(PC
.size(), 3);
406 /* different subnet of same size, should NOT match
407 since we don't skip the option */
408 BOOST_CHECK_EQUAL(PC
.get(&ecs2
, &r2
), false);
409 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
411 /* different subnet of different size, should NOT match. */
412 BOOST_CHECK_EQUAL(PC
.get(&ecs3
, &r2
), false);
414 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com"), 3);
415 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
416 BOOST_CHECK_EQUAL(PC
.size(), 0);
418 PC
.insert(&q
, &r
, 3600);
419 BOOST_CHECK_EQUAL(PC
.size(), 1);
420 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
421 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
422 BOOST_CHECK_EQUAL(PC
.purge("com$"), 1);
423 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
424 BOOST_CHECK_EQUAL(PC
.size(), 0);
426 PC
.insert(&q
, &r
, 3600);
427 BOOST_CHECK_EQUAL(PC
.size(), 1);
428 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
429 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
430 BOOST_CHECK_EQUAL(PC
.purge("powerdns.com$"), 1);
431 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
432 BOOST_CHECK_EQUAL(PC
.size(), 0);
434 PC
.insert(&q
, &r
, 3600);
435 BOOST_CHECK_EQUAL(PC
.size(), 1);
436 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
437 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
438 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com$"), 1);
439 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), false);
440 BOOST_CHECK_EQUAL(PC
.size(), 0);
442 PC
.insert(&q
, &r
, 3600);
443 BOOST_CHECK_EQUAL(PC
.size(), 1);
444 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.net"), 0);
445 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
446 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
447 BOOST_CHECK_EQUAL(PC
.size(), 1);
449 BOOST_CHECK_EQUAL(PC
.purge("net$"), 0);
450 BOOST_CHECK_EQUAL(PC
.get(&q
, &r2
), true);
451 BOOST_CHECK_EQUAL(r2
.qdomain
, r
.qdomain
);
452 BOOST_CHECK_EQUAL(PC
.size(), 1);
454 BOOST_CHECK_EQUAL(PC
.purge("www.powerdns.com$"), 1);
455 BOOST_CHECK_EQUAL(PC
.size(), 0);
457 catch(PDNSException
& e
) {
458 cerr
<<"Had error in AuthPacketCache: "<<e
.reason
<<endl
;
463 BOOST_AUTO_TEST_SUITE_END()