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