]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-dnsdistpacketcache_cc.cc
Merge pull request #9070 from rgacogne/boost-173
[thirdparty/pdns.git] / pdns / test-dnsdistpacketcache_cc.cc
1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
3
4 #include <boost/test/unit_test.hpp>
5
6 #include "ednscookies.hh"
7 #include "ednsoptions.hh"
8 #include "ednssubnet.hh"
9 #include "dnsdist.hh"
10 #include "iputils.hh"
11 #include "dnswriter.hh"
12 #include "dnsdist-cache.hh"
13 #include "gettime.hh"
14
15 BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc)
16
17 BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
18 const size_t maxEntries = 150000;
19 DNSDistPacketCache PC(maxEntries, 86400, 1);
20 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
21 struct timespec queryTime;
22 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
23
24 size_t counter=0;
25 size_t skipped=0;
26 ComboAddress remote;
27 bool dnssecOK = false;
28 try {
29 for(counter = 0; counter < 100000; ++counter) {
30 DNSName a=DNSName(std::to_string(counter))+DNSName(" hello");
31 BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
32
33 vector<uint8_t> query;
34 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
35 pwQ.getHeader()->rd = 1;
36
37 vector<uint8_t> response;
38 DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
39 pwR.getHeader()->rd = 1;
40 pwR.getHeader()->ra = 1;
41 pwR.getHeader()->qr = 1;
42 pwR.getHeader()->id = pwQ.getHeader()->id;
43 pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
44 pwR.xfr32BitInt(0x01020304);
45 pwR.commit();
46 uint16_t responseLen = response.size();
47
48 char responseBuf[4096];
49 uint16_t responseBufSize = sizeof(responseBuf);
50 uint32_t key = 0;
51 boost::optional<Netmask> subnet;
52 auto dh = reinterpret_cast<dnsheader*>(query.data());
53 DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
54 bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
55 BOOST_CHECK_EQUAL(found, false);
56 BOOST_CHECK(!subnet);
57
58 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
59
60 found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
61 if (found == true) {
62 BOOST_CHECK_EQUAL(responseBufSize, responseLen);
63 int match = memcmp(responseBuf, response.data(), responseLen);
64 BOOST_CHECK_EQUAL(match, 0);
65 BOOST_CHECK(!subnet);
66 }
67 else {
68 skipped++;
69 }
70 }
71
72 BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions());
73 BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped);
74
75 size_t deleted=0;
76 size_t delcounter=0;
77 for(delcounter=0; delcounter < counter/1000; ++delcounter) {
78 DNSName a=DNSName(std::to_string(delcounter))+DNSName(" hello");
79 vector<uint8_t> query;
80 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
81 pwQ.getHeader()->rd = 1;
82 char responseBuf[4096];
83 uint16_t responseBufSize = sizeof(responseBuf);
84 uint32_t key = 0;
85 boost::optional<Netmask> subnet;
86 DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
87 bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
88 if (found == true) {
89 auto removed = PC.expungeByName(a);
90 BOOST_CHECK_EQUAL(removed, 1U);
91 deleted += removed;
92 }
93 }
94 BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted);
95
96 size_t matches=0;
97 vector<DNSResourceRecord> entry;
98 size_t expected=counter-skipped-deleted;
99 for(; delcounter < counter; ++delcounter) {
100 DNSName a(DNSName(std::to_string(delcounter))+DNSName(" hello"));
101 vector<uint8_t> query;
102 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
103 pwQ.getHeader()->rd = 1;
104 uint16_t len = query.size();
105 uint32_t key = 0;
106 boost::optional<Netmask> subnet;
107 char response[4096];
108 uint16_t responseSize = sizeof(response);
109 DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), len, query.size(), false, &queryTime);
110 if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key, subnet, dnssecOK)) {
111 matches++;
112 }
113 }
114
115 /* in the unlikely event that the test took so long that the entries did expire.. */
116 auto expired = PC.purgeExpired();
117 BOOST_CHECK_EQUAL(matches + expired, expected);
118
119 auto remaining = PC.getSize();
120 auto removed = PC.expungeByName(DNSName(" hello"), QType::ANY, true);
121 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
122 BOOST_CHECK_EQUAL(removed, remaining);
123 }
124 catch(PDNSException& e) {
125 cerr<<"Had error: "<<e.reason<<endl;
126 throw;
127 }
128 }
129
130 BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) {
131 const size_t maxEntries = 150000;
132 DNSDistPacketCache PC(maxEntries, 86400, 1);
133 struct timespec queryTime;
134 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
135
136 ComboAddress remote;
137 bool dnssecOK = false;
138 try {
139 DNSName a = DNSName("servfail");
140 BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
141
142 vector<uint8_t> query;
143 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
144 pwQ.getHeader()->rd = 1;
145
146 vector<uint8_t> response;
147 DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
148 pwR.getHeader()->rd = 1;
149 pwR.getHeader()->ra = 0;
150 pwR.getHeader()->qr = 1;
151 pwR.getHeader()->rcode = RCode::ServFail;
152 pwR.getHeader()->id = pwQ.getHeader()->id;
153 pwR.commit();
154 uint16_t responseLen = response.size();
155
156 char responseBuf[4096];
157 uint16_t responseBufSize = sizeof(responseBuf);
158 uint32_t key = 0;
159 boost::optional<Netmask> subnet;
160 auto dh = reinterpret_cast<dnsheader*>(query.data());
161 DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
162 bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
163 BOOST_CHECK_EQUAL(found, false);
164 BOOST_CHECK(!subnet);
165
166 // Insert with failure-TTL of 0 (-> should not enter cache).
167 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(0));
168 found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
169 BOOST_CHECK_EQUAL(found, false);
170 BOOST_CHECK(!subnet);
171
172 // Insert with failure-TTL non-zero (-> should enter cache).
173 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(300));
174 found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
175 BOOST_CHECK_EQUAL(found, true);
176 BOOST_CHECK(!subnet);
177 }
178 catch(PDNSException& e) {
179 cerr<<"Had error: "<<e.reason<<endl;
180 throw;
181 }
182 }
183
184 BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) {
185 const size_t maxEntries = 150000;
186 DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
187
188 struct timespec queryTime;
189 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
190
191 ComboAddress remote;
192 bool dnssecOK = false;
193 try {
194 DNSName name("nodata");
195 vector<uint8_t> query;
196 DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0);
197 pwQ.getHeader()->rd = 1;
198
199 vector<uint8_t> response;
200 DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0);
201 pwR.getHeader()->rd = 1;
202 pwR.getHeader()->ra = 0;
203 pwR.getHeader()->qr = 1;
204 pwR.getHeader()->rcode = RCode::NoError;
205 pwR.getHeader()->id = pwQ.getHeader()->id;
206 pwR.commit();
207 pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
208 pwR.commit();
209 pwR.addOpt(4096, 0, 0);
210 pwR.commit();
211
212 uint16_t responseLen = response.size();
213
214 char responseBuf[4096];
215 uint16_t responseBufSize = sizeof(responseBuf);
216 uint32_t key = 0;
217 boost::optional<Netmask> subnet;
218 auto dh = reinterpret_cast<dnsheader*>(query.data());
219 DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
220 bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
221 BOOST_CHECK_EQUAL(found, false);
222 BOOST_CHECK(!subnet);
223
224 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NoError, boost::none);
225 found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
226 BOOST_CHECK_EQUAL(found, true);
227 BOOST_CHECK(!subnet);
228
229 sleep(2);
230 /* it should have expired by now */
231 found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
232 BOOST_CHECK_EQUAL(found, false);
233 BOOST_CHECK(!subnet);
234 }
235 catch(const PDNSException& e) {
236 cerr<<"Had error: "<<e.reason<<endl;
237 throw;
238 }
239 }
240
241 BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) {
242 const size_t maxEntries = 150000;
243 DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
244
245 struct timespec queryTime;
246 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
247
248 ComboAddress remote;
249 bool dnssecOK = false;
250 try {
251 DNSName name("nxdomain");
252 vector<uint8_t> query;
253 DNSPacketWriter pwQ(query, name, QType::A, QClass::IN, 0);
254 pwQ.getHeader()->rd = 1;
255
256 vector<uint8_t> response;
257 DNSPacketWriter pwR(response, name, QType::A, QClass::IN, 0);
258 pwR.getHeader()->rd = 1;
259 pwR.getHeader()->ra = 0;
260 pwR.getHeader()->qr = 1;
261 pwR.getHeader()->rcode = RCode::NXDomain;
262 pwR.getHeader()->id = pwQ.getHeader()->id;
263 pwR.commit();
264 pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
265 pwR.commit();
266 pwR.addOpt(4096, 0, 0);
267 pwR.commit();
268
269 uint16_t responseLen = response.size();
270
271 char responseBuf[4096];
272 uint16_t responseBufSize = sizeof(responseBuf);
273 uint32_t key = 0;
274 boost::optional<Netmask> subnet;
275 auto dh = reinterpret_cast<dnsheader*>(query.data());
276 DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
277 bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
278 BOOST_CHECK_EQUAL(found, false);
279 BOOST_CHECK(!subnet);
280
281 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NXDomain, boost::none);
282 found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
283 BOOST_CHECK_EQUAL(found, true);
284 BOOST_CHECK(!subnet);
285
286 sleep(2);
287 /* it should have expired by now */
288 found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
289 BOOST_CHECK_EQUAL(found, false);
290 BOOST_CHECK(!subnet);
291 }
292 catch(const PDNSException& e) {
293 cerr<<"Had error: "<<e.reason<<endl;
294 throw;
295 }
296 }
297
298 static DNSDistPacketCache g_PC(500000);
299
300 static void threadMangler(unsigned int offset)
301 {
302 struct timespec queryTime;
303 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
304 try {
305 ComboAddress remote;
306 bool dnssecOK = false;
307 for(unsigned int counter=0; counter < 100000; ++counter) {
308 DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
309 vector<uint8_t> query;
310 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
311 pwQ.getHeader()->rd = 1;
312
313 vector<uint8_t> response;
314 DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
315 pwR.getHeader()->rd = 1;
316 pwR.getHeader()->ra = 1;
317 pwR.getHeader()->qr = 1;
318 pwR.getHeader()->id = pwQ.getHeader()->id;
319 pwR.startRecord(a, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER);
320 pwR.xfr32BitInt(0x01020304);
321 pwR.commit();
322 uint16_t responseLen = response.size();
323
324 char responseBuf[4096];
325 uint16_t responseBufSize = sizeof(responseBuf);
326 uint32_t key = 0;
327 boost::optional<Netmask> subnet;
328 auto dh = reinterpret_cast<dnsheader*>(query.data());
329 DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
330 g_PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
331
332 g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
333 }
334 }
335 catch(PDNSException& e) {
336 cerr<<"Had error: "<<e.reason<<endl;
337 throw;
338 }
339 }
340
341 AtomicCounter g_missing;
342
343 static void threadReader(unsigned int offset)
344 {
345 bool dnssecOK = false;
346 struct timespec queryTime;
347 gettime(&queryTime); // does not have to be accurate ("realTime") in tests
348 try
349 {
350 vector<DNSResourceRecord> entry;
351 ComboAddress remote;
352 for(unsigned int counter=0; counter < 100000; ++counter) {
353 DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
354 vector<uint8_t> query;
355 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
356 pwQ.getHeader()->rd = 1;
357
358 char responseBuf[4096];
359 uint16_t responseBufSize = sizeof(responseBuf);
360 uint32_t key = 0;
361 boost::optional<Netmask> subnet;
362 DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
363 bool found = g_PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
364 if (!found) {
365 g_missing++;
366 }
367 }
368 }
369 catch(PDNSException& e) {
370 cerr<<"Had error in threadReader: "<<e.reason<<endl;
371 throw;
372 }
373 }
374
375 BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) {
376 try {
377 std::vector<std::thread> threads;
378 for (int i = 0; i < 4; ++i) {
379 threads.push_back(std::thread(threadMangler, i*1000000UL));
380 }
381
382 for (auto& t : threads) {
383 t.join();
384 }
385
386 threads.clear();
387
388 BOOST_CHECK_EQUAL(g_PC.getSize() + g_PC.getDeferredInserts() + g_PC.getInsertCollisions(), 400000U);
389 BOOST_CHECK_SMALL(1.0*g_PC.getInsertCollisions(), 10000.0);
390
391 for (int i = 0; i < 4; ++i) {
392 threads.push_back(std::thread(threadReader, i*1000000UL));
393 }
394
395 for (auto& t : threads) {
396 t.join();
397 }
398
399 BOOST_CHECK((g_PC.getDeferredInserts() + g_PC.getDeferredLookups() + g_PC.getInsertCollisions()) >= g_missing);
400 }
401 catch(PDNSException& e) {
402 cerr<<"Had error: "<<e.reason<<endl;
403 throw;
404 }
405
406 }
407
408 BOOST_AUTO_TEST_CASE(test_PCCollision) {
409 const size_t maxEntries = 150000;
410 DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true);
411 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
412
413 DNSName qname("www.powerdns.com.");
414 uint16_t qtype = QType::AAAA;
415 uint16_t qid = 0x42;
416 uint32_t key;
417 uint32_t secondKey;
418 boost::optional<Netmask> subnetOut;
419 bool dnssecOK = false;
420
421 /* lookup for a query with an ECS value of 10.0.118.46/32,
422 insert a corresponding response */
423 {
424 vector<uint8_t> query;
425 DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
426 pwQ.getHeader()->rd = 1;
427 pwQ.getHeader()->id = qid;
428 DNSPacketWriter::optvect_t ednsOptions;
429 EDNSSubnetOpts opt;
430 opt.source = Netmask("10.0.118.46/32");
431 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
432 pwQ.addOpt(512, 0, 0, ednsOptions);
433 pwQ.commit();
434
435 char responseBuf[4096];
436 uint16_t responseBufSize = sizeof(responseBuf);
437 ComboAddress remote("192.0.2.1");
438 struct timespec queryTime;
439 gettime(&queryTime);
440 DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
441 bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
442 BOOST_CHECK_EQUAL(found, false);
443 BOOST_REQUIRE(subnetOut);
444 BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
445
446 vector<uint8_t> response;
447 DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0);
448 pwR.getHeader()->rd = 1;
449 pwR.getHeader()->id = qid;
450 pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
451 ComboAddress v6("::1");
452 pwR.xfrCAWithoutPort(6, v6);
453 pwR.commit();
454 pwR.addOpt(512, 0, 0, ednsOptions);
455 pwR.commit();
456
457 PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none);
458 BOOST_CHECK_EQUAL(PC.getSize(), 1U);
459
460 found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
461 BOOST_CHECK_EQUAL(found, true);
462 BOOST_REQUIRE(subnetOut);
463 BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
464 }
465
466 /* now lookup for the same query with an ECS value of 10.0.123.193/32
467 we should get the same key (collision) but no match */
468 {
469 vector<uint8_t> query;
470 DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
471 pwQ.getHeader()->rd = 1;
472 pwQ.getHeader()->id = qid;
473 DNSPacketWriter::optvect_t ednsOptions;
474 EDNSSubnetOpts opt;
475 opt.source = Netmask("10.0.123.193/32");
476 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
477 pwQ.addOpt(512, 0, 0, ednsOptions);
478 pwQ.commit();
479
480 char responseBuf[4096];
481 uint16_t responseBufSize = sizeof(responseBuf);
482 ComboAddress remote("192.0.2.1");
483 struct timespec queryTime;
484 gettime(&queryTime);
485 DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
486 bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &secondKey, subnetOut, dnssecOK);
487 BOOST_CHECK_EQUAL(found, false);
488 BOOST_CHECK_EQUAL(secondKey, key);
489 BOOST_REQUIRE(subnetOut);
490 BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
491 BOOST_CHECK_EQUAL(PC.getLookupCollisions(), 1U);
492 }
493 }
494
495 BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
496 const size_t maxEntries = 150000;
497 DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true);
498 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
499
500 DNSName qname("www.powerdns.com.");
501 uint16_t qtype = QType::AAAA;
502 uint16_t qid = 0x42;
503 uint32_t key;
504 boost::optional<Netmask> subnetOut;
505
506 /* lookup for a query with DNSSEC OK,
507 insert a corresponding response with DO set,
508 check that it doesn't match without DO, but does with it */
509 {
510 vector<uint8_t> query;
511 DNSPacketWriter pwQ(query, qname, qtype, QClass::IN, 0);
512 pwQ.getHeader()->rd = 1;
513 pwQ.getHeader()->id = qid;
514 pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
515 pwQ.commit();
516
517 char responseBuf[4096];
518 uint16_t responseBufSize = sizeof(responseBuf);
519 ComboAddress remote("192.0.2.1");
520 struct timespec queryTime;
521 gettime(&queryTime);
522 DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
523 bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
524 BOOST_CHECK_EQUAL(found, false);
525
526 vector<uint8_t> response;
527 DNSPacketWriter pwR(response, qname, qtype, QClass::IN, 0);
528 pwR.getHeader()->rd = 1;
529 pwR.getHeader()->id = qid;
530 pwR.startRecord(qname, qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
531 ComboAddress v6("::1");
532 pwR.xfrCAWithoutPort(6, v6);
533 pwR.commit();
534 pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
535 pwR.commit();
536
537 PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none);
538 BOOST_CHECK_EQUAL(PC.getSize(), 1U);
539
540 found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, false);
541 BOOST_CHECK_EQUAL(found, false);
542
543 found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
544 BOOST_CHECK_EQUAL(found, true);
545 }
546
547 }
548
549 BOOST_AUTO_TEST_SUITE_END()