]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-packetcache_cc.cc
Update rules-actions.rst
[thirdparty/pdns.git] / pdns / test-packetcache_cc.cc
CommitLineData
fbe23e18 1#define BOOST_TEST_DYN_LINK
2#define BOOST_TEST_NO_MAIN
3
870a0fe4
AT
4#ifdef HAVE_CONFIG_H
5#include "config.h"
6#endif
fbe23e18 7#include <boost/test/unit_test.hpp>
8#include <boost/test/floating_point_comparison.hpp>
9#include "iputils.hh"
10#include "nameserver.hh"
11#include "statbag.hh"
bf269e28
RG
12#include "auth-packetcache.hh"
13#include "auth-querycache.hh"
fbe23e18 14#include "arguments.hh"
15#include <utility>
16extern StatBag S;
17
c7f29d3e 18BOOST_AUTO_TEST_SUITE(test_packetcache_cc)
fbe23e18 19
bf269e28
RG
20BOOST_AUTO_TEST_CASE(test_AuthQueryCacheSimple) {
21 AuthQueryCache QC;
22 QC.setMaxEntries(1000000);
fbe23e18 23
bf269e28 24 vector<DNSZoneRecord> records;
fbe23e18 25
bf269e28
RG
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);
fbe23e18 31
bf269e28 32 uint64_t counter=0;
fbe23e18 33 try {
34 for(counter = 0; counter < 100000; ++counter) {
335da0ba 35 DNSName a=DNSName("hello ")+DNSName(std::to_string(counter));
46e4b77c 36 BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
37
bf269e28
RG
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);
fbe23e18 42 }
43
bf269e28
RG
44 BOOST_CHECK_EQUAL(QC.size(), counter);
45
46 uint64_t delcounter=0;
fbe23e18 47 for(delcounter=0; delcounter < counter/100; ++delcounter) {
335da0ba 48 DNSName a=DNSName("hello ")+DNSName(std::to_string(delcounter));
bf269e28 49 BOOST_CHECK_EQUAL(QC.purge(a.toString()), 1);
fbe23e18 50 }
bf269e28
RG
51
52 BOOST_CHECK_EQUAL(QC.size(), counter-delcounter);
53
54 uint64_t matches=0;
7a59dc5a 55 vector<DNSZoneRecord> entry;
bf269e28 56 int64_t expected=counter-delcounter;
fbe23e18 57 for(; delcounter < counter; ++delcounter) {
bf269e28 58 if(QC.getEntry(DNSName("hello ")+DNSName(std::to_string(delcounter)), QType(QType::A), entry, 1)) {
fbe23e18 59 matches++;
60 }
61 }
62 BOOST_CHECK_EQUAL(matches, expected);
bf269e28 63 BOOST_CHECK_EQUAL(entry.size(), records.size());
fbe23e18 64 }
65 catch(PDNSException& e) {
66 cerr<<"Had error: "<<e.reason<<endl;
67 throw;
68 }
69
70}
71
bf269e28
RG
72static AuthQueryCache* g_QC;
73static AtomicCounter g_QCmissing;
fbe23e18 74
bf269e28 75static void *threadQCMangler(void* a)
fbe23e18 76try
77{
bf269e28 78 vector<DNSZoneRecord> records;
fbe23e18 79 unsigned int offset=(unsigned int)(unsigned long)a;
80 for(unsigned int counter=0; counter < 100000; ++counter)
bf269e28 81 g_QC->insert(DNSName("hello ")+DNSName(std::to_string(counter+offset)), QType(QType::A), records, 3600, 1);
fbe23e18 82 return 0;
83}
84 catch(PDNSException& e) {
85 cerr<<"Had error: "<<e.reason<<endl;
86 throw;
87 }
88
bf269e28 89static void *threadQCReader(void* a)
fbe23e18 90try
91{
92 unsigned int offset=(unsigned int)(unsigned long)a;
7a59dc5a 93 vector<DNSZoneRecord> entry;
fbe23e18 94 for(unsigned int counter=0; counter < 100000; ++counter)
bf269e28
RG
95 if(!g_QC->getEntry(DNSName("hello ")+DNSName(std::to_string(counter+offset)), QType(QType::A), entry, 1)) {
96 g_QCmissing++;
fbe23e18 97 }
98 return 0;
99}
100catch(PDNSException& e) {
bf269e28 101 cerr<<"Had error in threadQCReader: "<<e.reason<<endl;
fbe23e18 102 throw;
103}
104
bf269e28
RG
105BOOST_AUTO_TEST_CASE(test_QueryCacheThreaded) {
106 try {
48215c19 107 g_QCmissing = 0;
bf269e28
RG
108 AuthQueryCache QC;
109 QC.setMaxEntries(1000000);
110 g_QC=&QC;
111 pthread_t tid[4];
112 for(int i=0; i < 4; ++i)
113 pthread_create(&tid[i], 0, threadQCMangler, (void*)(i*1000000UL));
114 void* res;
115 for(int i=0; i < 4 ; ++i)
116 pthread_join(tid[i], &res);
117
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);
120
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);
125
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
128 }
129 catch(PDNSException& e) {
130 cerr<<"Had error: "<<e.reason<<endl;
131 throw;
132 }
133
134}
135
136static AuthPacketCache* g_PC;
137static AtomicCounter g_PCmissing;
138
139static void *threadPCMangler(void* a)
140try
141{
142 unsigned int offset=(unsigned int)(unsigned long)a;
143 for(unsigned int counter=0; counter < 100000; ++counter) {
144 vector<uint8_t> pak;
145 DNSName qname = DNSName("hello ")+DNSName(std::to_string(counter+offset));
146
147 DNSPacketWriter pw(pak, qname, QType::A);
148 DNSPacket q(true);
149 q.parse((char*)&pak[0], pak.size());
150
151 pak.clear();
152 DNSPacketWriter pw2(pak, qname, QType::A);
f776457f 153 pw2.startRecord(qname, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER);
bf269e28
RG
154 pw2.xfrIP(htonl(0x7f000001));
155 pw2.commit();
156
157 DNSPacket r(false);
158 r.parse((char*)&pak[0], pak.size());
159
6ac1a991
RG
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
163 */
164 q.setHash(g_PC->canHashPacket(q.getString()));
bf269e28 165
f776457f
RG
166 const unsigned int maxTTL = 3600;
167 g_PC->insert(&q, &r, maxTTL);
bf269e28
RG
168 }
169
170 return 0;
171}
172 catch(PDNSException& e) {
173 cerr<<"Had error: "<<e.reason<<endl;
174 throw;
175 }
176
177static void *threadPCReader(void* a)
178try
179{
180 unsigned int offset=(unsigned int)(unsigned long)a;
181 vector<DNSZoneRecord> entry;
182 for(unsigned int counter=0; counter < 100000; ++counter) {
183 vector<uint8_t> pak;
184 DNSName qname = DNSName("hello ")+DNSName(std::to_string(counter+offset));
185
186 DNSPacketWriter pw(pak, qname, QType::A);
187 DNSPacket q(true);
188 q.parse((char*)&pak[0], pak.size());
189 DNSPacket r(false);
190
191 if(!g_PC->get(&q, &r)) {
192 g_PCmissing++;
193 }
194 }
fbe23e18 195
bf269e28
RG
196 return 0;
197}
198catch(PDNSException& e) {
199 cerr<<"Had error in threadPCReader: "<<e.reason<<endl;
200 throw;
201}
20ac38f9 202
fbe23e18 203BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) {
204 try {
bf269e28
RG
205 AuthPacketCache PC;
206 PC.setMaxEntries(1000000);
f776457f 207 PC.setTTL(3600);
bf269e28 208
fbe23e18 209 g_PC=&PC;
fcbb4e00 210 g_PCmissing = 0;
fbe23e18 211 pthread_t tid[4];
bf269e28
RG
212 for(int i=0; i < 4; ++i)
213 pthread_create(&tid[i], 0, threadPCMangler, (void*)(i*1000000UL));
fbe23e18 214 void* res;
215 for(int i=0; i < 4 ; ++i)
216 pthread_join(tid[i], &res);
fbe23e18 217
bf269e28 218 BOOST_CHECK_EQUAL(PC.size() + S.read("deferred-packetcache-inserts"), 400000);
6ac1a991 219 BOOST_CHECK_EQUAL(S.read("deferred-packetcache-lookup"), 0);
bf269e28
RG
220 BOOST_CHECK_SMALL(1.0*S.read("deferred-packetcache-inserts"), 10000.0);
221
222 for(int i=0; i < 4; ++i)
223 pthread_create(&tid[i], 0, threadPCReader, (void*)(i*1000000UL));
fbe23e18 224 for(int i=0; i < 4 ; ++i)
225 pthread_join(tid[i], &res);
226
bf269e28
RG
227/*
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;
6ac1a991
RG
232 cerr<<g_PCmissing<<endl;
233 cerr<<PC.size()<<endl;
bf269e28 234*/
6ac1a991 235
bf269e28 236 BOOST_CHECK_EQUAL(g_PCmissing + S.read("packetcache-hit"), 400000);
6ac1a991 237 BOOST_CHECK_EQUAL(S.read("deferred-packetcache-inserts") + S.read("deferred-packetcache-lookup"), g_PCmissing);
fbe23e18 238 }
239 catch(PDNSException& e) {
240 cerr<<"Had error: "<<e.reason<<endl;
241 throw;
242 }
bf269e28 243
fbe23e18 244}
245
20ac38f9 246bool g_stopCleaning;
247static void *cacheCleaner(void*)
248try
249{
250 while(!g_stopCleaning) {
bf269e28 251 g_QC->cleanup();
20ac38f9 252 }
253
254 return 0;
255}
256catch(PDNSException& e) {
bf269e28 257 cerr<<"Had error in cacheCleaner: "<<e.reason<<endl;
20ac38f9 258 throw;
259}
260
bf269e28 261BOOST_AUTO_TEST_CASE(test_QueryCacheClean) {
20ac38f9 262 try {
bf269e28
RG
263 AuthQueryCache QC;
264 QC.setMaxEntries(10000);
265 vector<DNSZoneRecord> records;
20ac38f9 266
267 for(unsigned int counter = 0; counter < 1000000; ++counter) {
bf269e28 268 QC.insert(DNSName("hello ")+DNSName(std::to_string(counter)), QType(QType::A), records, 1, 1);
20ac38f9 269 }
270
271 sleep(1);
20ac38f9 272
bf269e28
RG
273 g_QC=&QC;
274 pthread_t tid[4];
20ac38f9 275
bf269e28
RG
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));
20ac38f9 279 // pthread_create(&tid[2], 0, threadMangler, (void*)(0*1000000UL));
280 pthread_create(&tid[3], 0, cacheCleaner, 0);
281
282 void *res;
283 for(int i=0; i < 3 ; ++i)
284 pthread_join(tid[i], &res);
285 g_stopCleaning=true;
286 pthread_join(tid[3], &res);
287 }
288 catch(PDNSException& e) {
bf269e28 289 cerr<<"Had error in test_QueryCacheClean: "<<e.reason<<endl;
20ac38f9 290 throw;
291 }
292}
c2ff5f42 293
bf269e28 294BOOST_AUTO_TEST_CASE(test_AuthPacketCache) {
c2ff5f42 295 try {
296 ::arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
297
bf269e28
RG
298 AuthPacketCache PC;
299 PC.setTTL(20);
300 PC.setMaxEntries(100000);
301
c2ff5f42 302 vector<uint8_t> pak;
bf269e28
RG
303 DNSPacket q(true), differentIDQ(true), ednsQ(true), ednsVersion42(true), ednsDO(true), ecs1(true), ecs2(true), ecs3(true);
304 DNSPacket r(false), r2(false);
c2ff5f42 305
bf269e28
RG
306 {
307 DNSPacketWriter pw(pak, DNSName("www.powerdns.com"), QType::A);
308 q.parse((char*)&pak[0], pak.size());
c2ff5f42 309
bf269e28
RG
310 differentIDQ.parse((char*)&pak[0], pak.size());
311 differentIDQ.setID(4242);
c2ff5f42 312
bf269e28
RG
313 pw.addOpt(512, 0, 0);
314 pw.commit();
315 ednsQ.parse((char*)&pak[0], pak.size());
316
317 pak.clear();
318 }
319
320 DNSPacketWriter::optvect_t opts;
321 EDNSSubnetOpts ecsOpts;
322 {
323 DNSPacketWriter pw(pak, DNSName("www.powerdns.com"), QType::A);
324 pw.addOpt(512, 0, 0, DNSPacketWriter::optvect_t(), 42);
325 pw.commit();
326 ednsVersion42.parse((char*)&pak[0], pak.size());
327 pak.clear();
328 }
329
330 {
331 DNSPacketWriter pw(pak, DNSName("www.powerdns.com"), QType::A);
332 pw.addOpt(512, 0, EDNSOpts::DNSSECOK);
333 pw.commit();
334 ednsDO.parse((char*)&pak[0], pak.size());
335 pak.clear();
336 }
337
338 {
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);
343 pw.commit();
344 ecs1.parse((char*)&pak[0], pak.size());
345 pak.clear();
346 opts.clear();
347 }
348
349 {
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);
354 pw.commit();
355 ecs2.parse((char*)&pak[0], pak.size());
356 pak.clear();
357 opts.clear();
358 }
359
360 {
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);
365 pw.commit();
366 ecs3.parse((char*)&pak[0], pak.size());
367 pak.clear();
368 opts.clear();
369 }
370
371 {
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));
375 pw.commit();
376
377 r.parse((char*)&pak[0], pak.size());
378 }
379
380 /* this call is required so the correct hash is set into q->d_hash */
381 BOOST_CHECK_EQUAL(PC.get(&q, &r2), false);
c2ff5f42 382
071d2d90 383 PC.insert(&q, &r, 3600);
bf269e28
RG
384 BOOST_CHECK_EQUAL(PC.size(), 1);
385
386 BOOST_CHECK_EQUAL(PC.get(&q, &r2), true);
387 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
388
389 /* different QID, still should match */
390 BOOST_CHECK_EQUAL(PC.get(&differentIDQ, &r2), true);
391 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
392
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);
398
399 /* different EDNS versions, should not match */
400 BOOST_CHECK_EQUAL(PC.get(&ednsVersion42, &r2), false);
401
402 /* EDNS DO set, should not match */
403 BOOST_CHECK_EQUAL(PC.get(&ednsDO, &r2), false);
c2ff5f42 404
bf269e28
RG
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);
409
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);
414
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);
660ec637 418 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
c2ff5f42 419
bf269e28
RG
420 /* different subnet of different size, should NOT match. */
421 BOOST_CHECK_EQUAL(PC.get(&ecs3, &r2), false);
422
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);
c2ff5f42 426
071d2d90 427 PC.insert(&q, &r, 3600);
bf269e28
RG
428 BOOST_CHECK_EQUAL(PC.size(), 1);
429 BOOST_CHECK_EQUAL(PC.get(&q, &r2), true);
660ec637 430 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
bf269e28
RG
431 BOOST_CHECK_EQUAL(PC.purge("com$"), 1);
432 BOOST_CHECK_EQUAL(PC.get(&q, &r2), false);
433 BOOST_CHECK_EQUAL(PC.size(), 0);
c2ff5f42 434
071d2d90 435 PC.insert(&q, &r, 3600);
bf269e28
RG
436 BOOST_CHECK_EQUAL(PC.size(), 1);
437 BOOST_CHECK_EQUAL(PC.get(&q, &r2), true);
660ec637 438 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
bf269e28
RG
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);
c2ff5f42 442
071d2d90 443 PC.insert(&q, &r, 3600);
bf269e28
RG
444 BOOST_CHECK_EQUAL(PC.size(), 1);
445 BOOST_CHECK_EQUAL(PC.get(&q, &r2), true);
660ec637 446 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
bf269e28
RG
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);
c2ff5f42 450
071d2d90 451 PC.insert(&q, &r, 3600);
bf269e28
RG
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);
660ec637 455 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
bf269e28
RG
456 BOOST_CHECK_EQUAL(PC.size(), 1);
457
458 BOOST_CHECK_EQUAL(PC.purge("net$"), 0);
459 BOOST_CHECK_EQUAL(PC.get(&q, &r2), true);
660ec637 460 BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
bf269e28
RG
461 BOOST_CHECK_EQUAL(PC.size(), 1);
462
463 BOOST_CHECK_EQUAL(PC.purge("www.powerdns.com$"), 1);
c2ff5f42 464 BOOST_CHECK_EQUAL(PC.size(), 0);
465 }
466 catch(PDNSException& e) {
bf269e28 467 cerr<<"Had error in AuthPacketCache: "<<e.reason<<endl;
c2ff5f42 468 throw;
469 }
bf269e28 470}
fbe23e18 471
472BOOST_AUTO_TEST_SUITE_END()