1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
4 #include <boost/test/unit_test.hpp>
6 #include "ednscookies.hh"
7 #include "ednsoptions.hh"
8 #include "ednssubnet.hh"
11 #include "dnswriter.hh"
12 #include "dnsdist-cache.hh"
15 BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc
)
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
27 bool dnssecOK
= false;
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
);
33 vector
<uint8_t> query
;
34 DNSPacketWriter
pwQ(query
, a
, QType::A
, QClass::IN
, 0);
35 pwQ
.getHeader()->rd
= 1;
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);
46 uint16_t responseLen
= response
.size();
48 char responseBuf
[4096];
49 uint16_t responseBufSize
= sizeof(responseBuf
);
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);
58 PC
.insert(key
, subnet
, *(getFlagsFromDNSHeader(dh
)), dnssecOK
, a
, QType::A
, QClass::IN
, (const char*) response
.data(), responseLen
, false, 0, boost::none
);
60 found
= PC
.get(dq
, a
.wirelength(), pwR
.getHeader()->id
, responseBuf
, &responseBufSize
, &key
, subnet
, dnssecOK
, 0, true);
62 BOOST_CHECK_EQUAL(responseBufSize
, responseLen
);
63 int match
= memcmp(responseBuf
, response
.data(), responseLen
);
64 BOOST_CHECK_EQUAL(match
, 0);
72 BOOST_CHECK_EQUAL(skipped
, PC
.getInsertCollisions());
73 BOOST_CHECK_EQUAL(PC
.getSize(), counter
- skipped
);
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
);
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
);
89 auto removed
= PC
.expungeByName(a
);
90 BOOST_CHECK_EQUAL(removed
, 1);
94 BOOST_CHECK_EQUAL(PC
.getSize(), counter
- skipped
- deleted
);
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();
106 boost::optional
<Netmask
> subnet
;
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
)) {
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
);
119 auto remaining
= PC
.getSize();
120 auto removed
= PC
.expungeByName(DNSName(" hello"), QType::ANY
, true);
121 BOOST_CHECK_EQUAL(PC
.getSize(), 0);
122 BOOST_CHECK_EQUAL(removed
, remaining
);
124 catch(PDNSException
& e
) {
125 cerr
<<"Had error: "<<e
.reason
<<endl
;
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
137 bool dnssecOK
= false;
139 DNSName a
= DNSName("servfail");
140 BOOST_CHECK_EQUAL(DNSName(a
.toString()), a
);
142 vector
<uint8_t> query
;
143 DNSPacketWriter
pwQ(query
, a
, QType::A
, QClass::IN
, 0);
144 pwQ
.getHeader()->rd
= 1;
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
;
154 uint16_t responseLen
= response
.size();
156 char responseBuf
[4096];
157 uint16_t responseBufSize
= sizeof(responseBuf
);
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
);
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
);
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
);
178 catch(PDNSException
& e
) {
179 cerr
<<"Had error: "<<e
.reason
<<endl
;
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);
188 struct timespec queryTime
;
189 gettime(&queryTime
); // does not have to be accurate ("realTime") in tests
192 bool dnssecOK
= false;
194 DNSName
name("nodata");
195 vector
<uint8_t> query
;
196 DNSPacketWriter
pwQ(query
, name
, QType::A
, QClass::IN
, 0);
197 pwQ
.getHeader()->rd
= 1;
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
;
207 pwR
.startRecord(name
, QType::SOA
, 86400, QClass::IN
, DNSResourceRecord::AUTHORITY
);
209 pwR
.addOpt(4096, 0, 0);
212 uint16_t responseLen
= response
.size();
214 char responseBuf
[4096];
215 uint16_t responseBufSize
= sizeof(responseBuf
);
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
);
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
);
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
);
235 catch(const PDNSException
& e
) {
236 cerr
<<"Had error: "<<e
.reason
<<endl
;
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);
245 struct timespec queryTime
;
246 gettime(&queryTime
); // does not have to be accurate ("realTime") in tests
249 bool dnssecOK
= false;
251 DNSName
name("nxdomain");
252 vector
<uint8_t> query
;
253 DNSPacketWriter
pwQ(query
, name
, QType::A
, QClass::IN
, 0);
254 pwQ
.getHeader()->rd
= 1;
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
;
264 pwR
.startRecord(name
, QType::SOA
, 86400, QClass::IN
, DNSResourceRecord::AUTHORITY
);
266 pwR
.addOpt(4096, 0, 0);
269 uint16_t responseLen
= response
.size();
271 char responseBuf
[4096];
272 uint16_t responseBufSize
= sizeof(responseBuf
);
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
);
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
);
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
);
292 catch(const PDNSException
& e
) {
293 cerr
<<"Had error: "<<e
.reason
<<endl
;
298 static DNSDistPacketCache
PC(500000);
300 static void *threadMangler(void* off
)
302 struct timespec queryTime
;
303 gettime(&queryTime
); // does not have to be accurate ("realTime") in tests
306 bool dnssecOK
= false;
307 unsigned int offset
=(unsigned int)(unsigned long)off
;
308 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
309 DNSName a
=DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
310 vector
<uint8_t> query
;
311 DNSPacketWriter
pwQ(query
, a
, QType::A
, QClass::IN
, 0);
312 pwQ
.getHeader()->rd
= 1;
314 vector
<uint8_t> response
;
315 DNSPacketWriter
pwR(response
, a
, QType::A
, QClass::IN
, 0);
316 pwR
.getHeader()->rd
= 1;
317 pwR
.getHeader()->ra
= 1;
318 pwR
.getHeader()->qr
= 1;
319 pwR
.getHeader()->id
= pwQ
.getHeader()->id
;
320 pwR
.startRecord(a
, QType::A
, 3600, QClass::IN
, DNSResourceRecord::ANSWER
);
321 pwR
.xfr32BitInt(0x01020304);
323 uint16_t responseLen
= response
.size();
325 char responseBuf
[4096];
326 uint16_t responseBufSize
= sizeof(responseBuf
);
328 boost::optional
<Netmask
> subnet
;
329 auto dh
= reinterpret_cast<dnsheader
*>(query
.data());
330 DNSQuestion
dq(&a
, QType::A
, QClass::IN
, 0, &remote
, &remote
, dh
, query
.size(), query
.size(), false, &queryTime
);
331 PC
.get(dq
, a
.wirelength(), 0, responseBuf
, &responseBufSize
, &key
, subnet
, dnssecOK
);
333 PC
.insert(key
, subnet
, *(getFlagsFromDNSHeader(dh
)), dnssecOK
, a
, QType::A
, QClass::IN
, (const char*) response
.data(), responseLen
, false, 0, boost::none
);
336 catch(PDNSException
& e
) {
337 cerr
<<"Had error: "<<e
.reason
<<endl
;
343 AtomicCounter g_missing
;
345 static void *threadReader(void* off
)
347 bool dnssecOK
= false;
348 struct timespec queryTime
;
349 gettime(&queryTime
); // does not have to be accurate ("realTime") in tests
352 unsigned int offset
=(unsigned int)(unsigned long)off
;
353 vector
<DNSResourceRecord
> entry
;
355 for(unsigned int counter
=0; counter
< 100000; ++counter
) {
356 DNSName a
=DNSName("hello ")+DNSName(std::to_string(counter
+offset
));
357 vector
<uint8_t> query
;
358 DNSPacketWriter
pwQ(query
, a
, QType::A
, QClass::IN
, 0);
359 pwQ
.getHeader()->rd
= 1;
361 char responseBuf
[4096];
362 uint16_t responseBufSize
= sizeof(responseBuf
);
364 boost::optional
<Netmask
> subnet
;
365 DNSQuestion
dq(&a
, QType::A
, QClass::IN
, 0, &remote
, &remote
, (struct dnsheader
*) query
.data(), query
.size(), query
.size(), false, &queryTime
);
366 bool found
= PC
.get(dq
, a
.wirelength(), 0, responseBuf
, &responseBufSize
, &key
, subnet
, dnssecOK
);
372 catch(PDNSException
& e
) {
373 cerr
<<"Had error in threadReader: "<<e
.reason
<<endl
;
379 BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded
) {
382 for(int i
=0; i
< 4; ++i
)
383 pthread_create(&tid
[i
], 0, threadMangler
, (void*)(i
*1000000UL));
385 for(int i
=0; i
< 4 ; ++i
)
386 pthread_join(tid
[i
], &res
);
388 BOOST_CHECK_EQUAL(PC
.getSize() + PC
.getDeferredInserts() + PC
.getInsertCollisions(), 400000);
389 BOOST_CHECK_SMALL(1.0*PC
.getInsertCollisions(), 10000.0);
391 for(int i
=0; i
< 4; ++i
)
392 pthread_create(&tid
[i
], 0, threadReader
, (void*)(i
*1000000UL));
393 for(int i
=0; i
< 4 ; ++i
)
394 pthread_join(tid
[i
], &res
);
396 BOOST_CHECK((PC
.getDeferredInserts() + PC
.getDeferredLookups() + PC
.getInsertCollisions()) >= g_missing
);
398 catch(PDNSException
& e
) {
399 cerr
<<"Had error: "<<e
.reason
<<endl
;
405 BOOST_AUTO_TEST_CASE(test_PCCollision
) {
406 const size_t maxEntries
= 150000;
407 DNSDistPacketCache
PC(maxEntries
, 86400, 1, 60, 3600, 60, false, 1, true, true);
408 BOOST_CHECK_EQUAL(PC
.getSize(), 0);
410 DNSName
qname("www.powerdns.com.");
411 uint16_t qtype
= QType::AAAA
;
415 boost::optional
<Netmask
> subnetOut
;
416 bool dnssecOK
= false;
418 /* lookup for a query with an ECS value of 10.0.118.46/32,
419 insert a corresponding response */
421 vector
<uint8_t> query
;
422 DNSPacketWriter
pwQ(query
, qname
, qtype
, QClass::IN
, 0);
423 pwQ
.getHeader()->rd
= 1;
424 pwQ
.getHeader()->id
= qid
;
425 DNSPacketWriter::optvect_t ednsOptions
;
427 opt
.source
= Netmask("10.0.118.46/32");
428 ednsOptions
.push_back(std::make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(opt
)));
429 pwQ
.addOpt(512, 0, 0, ednsOptions
);
432 char responseBuf
[4096];
433 uint16_t responseBufSize
= sizeof(responseBuf
);
434 ComboAddress
remote("192.0.2.1");
435 struct timespec queryTime
;
437 DNSQuestion
dq(&qname
, QType::AAAA
, QClass::IN
, 0, &remote
, &remote
, pwQ
.getHeader(), query
.size(), query
.size(), false, &queryTime
);
438 bool found
= PC
.get(dq
, qname
.wirelength(), 0, responseBuf
, &responseBufSize
, &key
, subnetOut
, dnssecOK
);
439 BOOST_CHECK_EQUAL(found
, false);
440 BOOST_REQUIRE(subnetOut
);
441 BOOST_CHECK_EQUAL(subnetOut
->toString(), opt
.source
.toString());
443 vector
<uint8_t> response
;
444 DNSPacketWriter
pwR(response
, qname
, qtype
, QClass::IN
, 0);
445 pwR
.getHeader()->rd
= 1;
446 pwR
.getHeader()->id
= qid
;
447 pwR
.startRecord(qname
, qtype
, 100, QClass::IN
, DNSResourceRecord::ANSWER
);
448 ComboAddress
v6("::1");
449 pwR
.xfrCAWithoutPort(6, v6
);
451 pwR
.addOpt(512, 0, 0, ednsOptions
);
454 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
);
455 BOOST_CHECK_EQUAL(PC
.getSize(), 1);
457 found
= PC
.get(dq
, qname
.wirelength(), 0, responseBuf
, &responseBufSize
, &key
, subnetOut
, dnssecOK
);
458 BOOST_CHECK_EQUAL(found
, true);
459 BOOST_REQUIRE(subnetOut
);
460 BOOST_CHECK_EQUAL(subnetOut
->toString(), opt
.source
.toString());
463 /* now lookup for the same query with an ECS value of 10.0.123.193/32
464 we should get the same key (collision) but no match */
466 vector
<uint8_t> query
;
467 DNSPacketWriter
pwQ(query
, qname
, qtype
, QClass::IN
, 0);
468 pwQ
.getHeader()->rd
= 1;
469 pwQ
.getHeader()->id
= qid
;
470 DNSPacketWriter::optvect_t ednsOptions
;
472 opt
.source
= Netmask("10.0.123.193/32");
473 ednsOptions
.push_back(std::make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(opt
)));
474 pwQ
.addOpt(512, 0, 0, ednsOptions
);
477 char responseBuf
[4096];
478 uint16_t responseBufSize
= sizeof(responseBuf
);
479 ComboAddress
remote("192.0.2.1");
480 struct timespec queryTime
;
482 DNSQuestion
dq(&qname
, QType::AAAA
, QClass::IN
, 0, &remote
, &remote
, pwQ
.getHeader(), query
.size(), query
.size(), false, &queryTime
);
483 bool found
= PC
.get(dq
, qname
.wirelength(), 0, responseBuf
, &responseBufSize
, &secondKey
, subnetOut
, dnssecOK
);
484 BOOST_CHECK_EQUAL(found
, false);
485 BOOST_CHECK_EQUAL(secondKey
, key
);
486 BOOST_REQUIRE(subnetOut
);
487 BOOST_CHECK_EQUAL(subnetOut
->toString(), opt
.source
.toString());
488 BOOST_CHECK_EQUAL(PC
.getLookupCollisions(), 1);
492 BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision
) {
493 const size_t maxEntries
= 150000;
494 DNSDistPacketCache
PC(maxEntries
, 86400, 1, 60, 3600, 60, false, 1, true, true);
495 BOOST_CHECK_EQUAL(PC
.getSize(), 0);
497 DNSName
qname("www.powerdns.com.");
498 uint16_t qtype
= QType::AAAA
;
501 boost::optional
<Netmask
> subnetOut
;
503 /* lookup for a query with DNSSEC OK,
504 insert a corresponding response with DO set,
505 check that it doesn't match without DO, but does with it */
507 vector
<uint8_t> query
;
508 DNSPacketWriter
pwQ(query
, qname
, qtype
, QClass::IN
, 0);
509 pwQ
.getHeader()->rd
= 1;
510 pwQ
.getHeader()->id
= qid
;
511 pwQ
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
514 char responseBuf
[4096];
515 uint16_t responseBufSize
= sizeof(responseBuf
);
516 ComboAddress
remote("192.0.2.1");
517 struct timespec queryTime
;
519 DNSQuestion
dq(&qname
, QType::AAAA
, QClass::IN
, 0, &remote
, &remote
, pwQ
.getHeader(), query
.size(), query
.size(), false, &queryTime
);
520 bool found
= PC
.get(dq
, qname
.wirelength(), 0, responseBuf
, &responseBufSize
, &key
, subnetOut
, true);
521 BOOST_CHECK_EQUAL(found
, false);
523 vector
<uint8_t> response
;
524 DNSPacketWriter
pwR(response
, qname
, qtype
, QClass::IN
, 0);
525 pwR
.getHeader()->rd
= 1;
526 pwR
.getHeader()->id
= qid
;
527 pwR
.startRecord(qname
, qtype
, 100, QClass::IN
, DNSResourceRecord::ANSWER
);
528 ComboAddress
v6("::1");
529 pwR
.xfrCAWithoutPort(6, v6
);
531 pwR
.addOpt(512, 0, EDNS_HEADER_FLAG_DO
);
534 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
);
535 BOOST_CHECK_EQUAL(PC
.getSize(), 1);
537 found
= PC
.get(dq
, qname
.wirelength(), 0, responseBuf
, &responseBufSize
, &key
, subnetOut
, false);
538 BOOST_CHECK_EQUAL(found
, false);
540 found
= PC
.get(dq
, qname
.wirelength(), 0, responseBuf
, &responseBufSize
, &key
, subnetOut
, true);
541 BOOST_CHECK_EQUAL(found
, true);
546 BOOST_AUTO_TEST_SUITE_END()