]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-dnsdistpacketcache_cc.cc
dnsdist: Store the initial query time in the internal state as well
[thirdparty/pdns.git] / pdns / test-dnsdistpacketcache_cc.cc
CommitLineData
886e2cf2
RG
1#define BOOST_TEST_DYN_LINK
2#define BOOST_TEST_NO_MAIN
3
4#include <boost/test/unit_test.hpp>
5
78e3ac9e 6#include "ednscookies.hh"
8dcdbdb1 7#include "ednsoptions.hh"
78e3ac9e 8#include "ednssubnet.hh"
1ea747c0 9#include "dnsdist.hh"
886e2cf2 10#include "iputils.hh"
886e2cf2 11#include "dnswriter.hh"
1ea747c0 12#include "dnsdist-cache.hh"
5ffb2f83 13#include "gettime.hh"
fa980c59 14#include "packetcache.hh"
886e2cf2 15
c7f29d3e 16BOOST_AUTO_TEST_SUITE(test_dnsdistpacketcache_cc)
886e2cf2 17
d84ea5be
RG
18static bool receivedOverUDP = true;
19
886e2cf2
RG
20BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
21 const size_t maxEntries = 150000;
22 DNSDistPacketCache PC(maxEntries, 86400, 1);
690b86b7 23 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
886e2cf2 24
592b1d99
RG
25 size_t counter = 0;
26 size_t skipped = 0;
d7728daf 27 bool dnssecOK = false;
f6e76e12 28 const time_t now = time(nullptr);
592b1d99
RG
29 InternalQueryState ids;
30 ids.qtype = QType::A;
31 ids.qclass = QClass::IN;
32 ids.protocol = dnsdist::Protocol::DoUDP;
33
886e2cf2 34 try {
f6e76e12 35 for (counter = 0; counter < 100000; ++counter) {
592b1d99
RG
36 auto a = DNSName(std::to_string(counter))+DNSName(" hello");
37 ids.qname = a;
886e2cf2 38
32fbb2ab
RG
39 PacketBuffer query;
40 GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
886e2cf2
RG
41 pwQ.getHeader()->rd = 1;
42
32fbb2ab
RG
43 PacketBuffer response;
44 GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::A, QClass::IN, 0);
886e2cf2
RG
45 pwR.getHeader()->rd = 1;
46 pwR.getHeader()->ra = 1;
47 pwR.getHeader()->qr = 1;
48 pwR.getHeader()->id = pwQ.getHeader()->id;
f627611d 49 pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
886e2cf2
RG
50 pwR.xfr32BitInt(0x01020304);
51 pwR.commit();
886e2cf2 52
886e2cf2 53 uint32_t key = 0;
78e3ac9e 54 boost::optional<Netmask> subnet;
d5d15da1 55 DNSQuestion dq(ids, query);
d84ea5be 56 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
886e2cf2 57 BOOST_CHECK_EQUAL(found, false);
78e3ac9e 58 BOOST_CHECK(!subnet);
886e2cf2 59
d84ea5be 60 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
886e2cf2 61
d84ea5be 62 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
886e2cf2 63 if (found == true) {
341d2553
RG
64 BOOST_CHECK_EQUAL(dq.getData().size(), response.size());
65 int match = memcmp(dq.getData().data(), response.data(), dq.getData().size());
886e2cf2 66 BOOST_CHECK_EQUAL(match, 0);
78e3ac9e 67 BOOST_CHECK(!subnet);
886e2cf2
RG
68 }
69 else {
70 skipped++;
71 }
72 }
73
74 BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions());
75 BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped);
76
77 size_t deleted=0;
78 size_t delcounter=0;
f6e76e12 79 for (delcounter=0; delcounter < counter/1000; ++delcounter) {
592b1d99 80 ids.qname = DNSName(std::to_string(delcounter))+DNSName(" hello");
32fbb2ab 81 PacketBuffer query;
592b1d99 82 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
886e2cf2 83 pwQ.getHeader()->rd = 1;
886e2cf2 84 uint32_t key = 0;
78e3ac9e 85 boost::optional<Netmask> subnet;
d5d15da1 86 DNSQuestion dq(ids, query);
d84ea5be 87 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
886e2cf2 88 if (found == true) {
592b1d99 89 auto removed = PC.expungeByName(ids.qname);
690b86b7 90 BOOST_CHECK_EQUAL(removed, 1U);
f627611d 91 deleted += removed;
886e2cf2
RG
92 }
93 }
94 BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted);
95
96 size_t matches=0;
886e2cf2 97 size_t expected=counter-skipped-deleted;
f6e76e12 98 for (; delcounter < counter; ++delcounter) {
592b1d99 99 ids.qname = DNSName(std::to_string(delcounter))+DNSName(" hello");
32fbb2ab 100 PacketBuffer query;
592b1d99 101 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
886e2cf2 102 pwQ.getHeader()->rd = 1;
886e2cf2 103 uint32_t key = 0;
78e3ac9e 104 boost::optional<Netmask> subnet;
d5d15da1 105 DNSQuestion dq(ids, query);
d84ea5be 106 if (PC.get(dq, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) {
490dc586 107 matches++;
886e2cf2
RG
108 }
109 }
490dc586 110
6d1a9248 111 /* in the unlikely event that the test took so long that the entries did expire.. */
f6e76e12 112 auto expired = PC.purgeExpired(0, now);
f627611d
RG
113 BOOST_CHECK_EQUAL(matches + expired, expected);
114
115 auto remaining = PC.getSize();
116 auto removed = PC.expungeByName(DNSName(" hello"), QType::ANY, true);
690b86b7 117 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
f627611d 118 BOOST_CHECK_EQUAL(removed, remaining);
af9f7f64
RG
119
120 /* nothing to remove */
121 BOOST_CHECK_EQUAL(PC.purgeExpired(0, now), 0U);
886e2cf2 122 }
f6e76e12
RG
123 catch (const PDNSException& e) {
124 cerr<<"Had error: "<<e.reason<<endl;
125 throw;
126 }
127}
128
129BOOST_AUTO_TEST_CASE(test_PacketCacheSharded) {
130 const size_t maxEntries = 150000;
131 const size_t numberOfShards = 10;
132 DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, numberOfShards);
133 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
f6e76e12
RG
134
135 size_t counter = 0;
136 size_t skipped = 0;
137 ComboAddress remote;
138 bool dnssecOK = false;
139 const time_t now = time(nullptr);
592b1d99
RG
140 InternalQueryState ids;
141 ids.qtype = QType::AAAA;
142 ids.qclass = QClass::IN;
143 ids.protocol = dnsdist::Protocol::DoUDP;
f6e76e12
RG
144
145 try {
146 for (counter = 0; counter < 100000; ++counter) {
592b1d99 147 ids.qname = DNSName(std::to_string(counter) + ".powerdns.com.");
f6e76e12
RG
148
149 PacketBuffer query;
592b1d99 150 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::AAAA, QClass::IN, 0);
f6e76e12
RG
151 pwQ.getHeader()->rd = 1;
152
153 PacketBuffer response;
592b1d99 154 GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::AAAA, QClass::IN, 0);
f6e76e12
RG
155 pwR.getHeader()->rd = 1;
156 pwR.getHeader()->ra = 1;
157 pwR.getHeader()->qr = 1;
158 pwR.getHeader()->id = pwQ.getHeader()->id;
592b1d99 159 pwR.startRecord(ids.qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
f6e76e12
RG
160 ComboAddress v6("2001:db8::1");
161 pwR.xfrIP6(std::string(reinterpret_cast<const char*>(v6.sin6.sin6_addr.s6_addr), 16));
f6e76e12
RG
162 pwR.commit();
163
164 uint32_t key = 0;
165 boost::optional<Netmask> subnet;
d5d15da1 166 DNSQuestion dq(ids, query);
d84ea5be 167 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
f6e76e12
RG
168 BOOST_CHECK_EQUAL(found, false);
169 BOOST_CHECK(!subnet);
170
592b1d99 171 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::AAAA, QClass::IN, response, receivedOverUDP, 0, boost::none);
f6e76e12 172
d84ea5be 173 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
f6e76e12
RG
174 if (found == true) {
175 BOOST_CHECK_EQUAL(dq.getData().size(), response.size());
176 int match = memcmp(dq.getData().data(), response.data(), dq.getData().size());
177 BOOST_CHECK_EQUAL(match, 0);
178 BOOST_CHECK(!subnet);
179 }
180 else {
181 skipped++;
182 }
183 }
184
185 BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions());
186 BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped);
187
188 size_t matches = 0;
189 for (counter = 0; counter < 100000; ++counter) {
592b1d99 190 ids.qname = DNSName(std::to_string(counter) + ".powerdns.com.");
f6e76e12
RG
191
192 PacketBuffer query;
592b1d99 193 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::AAAA, QClass::IN, 0);
f6e76e12
RG
194 pwQ.getHeader()->rd = 1;
195 uint32_t key = 0;
196 boost::optional<Netmask> subnet;
d5d15da1 197 DNSQuestion dq(ids, query);
d84ea5be 198 if (PC.get(dq, pwQ.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP)) {
f6e76e12
RG
199 matches++;
200 }
201 }
202
203 BOOST_CHECK_EQUAL(matches, counter - skipped);
204
205 auto remaining = PC.getSize();
206
207 /* no entry should have expired */
208 auto expired = PC.purgeExpired(0, now);
209 BOOST_CHECK_EQUAL(expired, 0U);
210
211 /* but after the TTL .. let's ask for at most 1k entries */
b8a0a4a8 212 auto removed = PC.purgeExpired(1000, now + 7200 + 3600);
f6e76e12
RG
213 BOOST_CHECK_EQUAL(removed, remaining - 1000U);
214 BOOST_CHECK_EQUAL(PC.getSize(), 1000U);
215
216 /* now remove everything */
b8a0a4a8 217 removed = PC.purgeExpired(0, now + 7200 + 3600);
f6e76e12
RG
218 BOOST_CHECK_EQUAL(removed, 1000U);
219 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
af9f7f64
RG
220
221 /* nothing to remove */
222 BOOST_CHECK_EQUAL(PC.purgeExpired(0, now), 0U);
f6e76e12
RG
223 }
224 catch (const PDNSException& e) {
886e2cf2
RG
225 cerr<<"Had error: "<<e.reason<<endl;
226 throw;
227 }
228}
229
30014e5f
RG
230BOOST_AUTO_TEST_CASE(test_PacketCacheTCP) {
231 const size_t maxEntries = 150000;
232 DNSDistPacketCache PC(maxEntries, 86400, 1);
592b1d99
RG
233 InternalQueryState ids;
234 ids.qtype = QType::A;
235 ids.qclass = QClass::IN;
236 ids.protocol = dnsdist::Protocol::DoUDP;
30014e5f
RG
237
238 ComboAddress remote;
239 bool dnssecOK = false;
240 try {
592b1d99
RG
241 DNSName a("tcp");
242 ids.qname = a;
30014e5f
RG
243
244 PacketBuffer query;
245 GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::AAAA, QClass::IN, 0);
246 pwQ.getHeader()->rd = 1;
247
248 PacketBuffer response;
249 GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::AAAA, QClass::IN, 0);
250 pwR.getHeader()->rd = 1;
251 pwR.getHeader()->ra = 1;
252 pwR.getHeader()->qr = 1;
253 pwR.getHeader()->id = pwQ.getHeader()->id;
254 pwR.startRecord(a, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ANSWER);
255 ComboAddress v6("2001:db8::1");
256 pwR.xfrIP6(std::string(reinterpret_cast<const char*>(v6.sin6.sin6_addr.s6_addr), 16));
30014e5f
RG
257 pwR.commit();
258
259 {
260 /* UDP */
261 uint32_t key = 0;
262 boost::optional<Netmask> subnet;
d5d15da1 263 DNSQuestion dq(ids, query);
30014e5f
RG
264 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
265 BOOST_CHECK_EQUAL(found, false);
266 BOOST_CHECK(!subnet);
267
268 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
269 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
270 BOOST_CHECK_EQUAL(found, true);
271 BOOST_CHECK(!subnet);
272 }
273
274 {
275 /* same but over TCP */
276 uint32_t key = 0;
277 boost::optional<Netmask> subnet;
592b1d99 278 ids.protocol = dnsdist::Protocol::DoTCP;
d5d15da1 279 DNSQuestion dq(ids, query);
30014e5f
RG
280 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, !receivedOverUDP);
281 BOOST_CHECK_EQUAL(found, false);
282 BOOST_CHECK(!subnet);
283
284 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, !receivedOverUDP, RCode::NoError, boost::none);
285 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, !receivedOverUDP, 0, true);
286 BOOST_CHECK_EQUAL(found, true);
287 BOOST_CHECK(!subnet);
288 }
289 }
290 catch(PDNSException& e) {
291 cerr<<"Had error: "<<e.reason<<endl;
292 throw;
293 }
294}
295
acb8f5d5
CH
296BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) {
297 const size_t maxEntries = 150000;
298 DNSDistPacketCache PC(maxEntries, 86400, 1);
592b1d99
RG
299 InternalQueryState ids;
300 ids.qtype = QType::A;
301 ids.qclass = QClass::IN;
302 ids.protocol = dnsdist::Protocol::DoUDP;
acb8f5d5
CH
303
304 ComboAddress remote;
d7728daf 305 bool dnssecOK = false;
acb8f5d5
CH
306 try {
307 DNSName a = DNSName("servfail");
592b1d99 308 ids.qname = a;
acb8f5d5 309
32fbb2ab
RG
310 PacketBuffer query;
311 GenericDNSPacketWriter<PacketBuffer> pwQ(query, a, QType::A, QClass::IN, 0);
acb8f5d5
CH
312 pwQ.getHeader()->rd = 1;
313
32fbb2ab
RG
314 PacketBuffer response;
315 GenericDNSPacketWriter<PacketBuffer> pwR(response, a, QType::A, QClass::IN, 0);
acb8f5d5
CH
316 pwR.getHeader()->rd = 1;
317 pwR.getHeader()->ra = 0;
318 pwR.getHeader()->qr = 1;
319 pwR.getHeader()->rcode = RCode::ServFail;
320 pwR.getHeader()->id = pwQ.getHeader()->id;
321 pwR.commit();
acb8f5d5 322
acb8f5d5 323 uint32_t key = 0;
78e3ac9e 324 boost::optional<Netmask> subnet;
d5d15da1 325 DNSQuestion dq(ids, query);
d84ea5be 326 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
acb8f5d5 327 BOOST_CHECK_EQUAL(found, false);
78e3ac9e 328 BOOST_CHECK(!subnet);
acb8f5d5
CH
329
330 // Insert with failure-TTL of 0 (-> should not enter cache).
d84ea5be
RG
331 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(0));
332 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
acb8f5d5 333 BOOST_CHECK_EQUAL(found, false);
78e3ac9e 334 BOOST_CHECK(!subnet);
acb8f5d5 335
56459632 336 // Insert with failure-TTL non-zero (-> should enter cache).
d84ea5be
RG
337 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, receivedOverUDP, RCode::ServFail, boost::optional<uint32_t>(300));
338 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
acb8f5d5 339 BOOST_CHECK_EQUAL(found, true);
78e3ac9e 340 BOOST_CHECK(!subnet);
acb8f5d5
CH
341 }
342 catch(PDNSException& e) {
343 cerr<<"Had error: "<<e.reason<<endl;
344 throw;
345 }
346}
347
47698274
RG
348BOOST_AUTO_TEST_CASE(test_PacketCacheNoDataTTL) {
349 const size_t maxEntries = 150000;
350 DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
351
592b1d99
RG
352 ComboAddress remote;
353 bool dnssecOK = false;
354 InternalQueryState ids;
355 ids.qtype = QType::A;
356 ids.qclass = QClass::IN;
357 ids.protocol = dnsdist::Protocol::DoUDP;
47698274 358
47698274
RG
359 try {
360 DNSName name("nodata");
592b1d99 361 ids.qname = name;
32fbb2ab
RG
362 PacketBuffer query;
363 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
47698274
RG
364 pwQ.getHeader()->rd = 1;
365
32fbb2ab
RG
366 PacketBuffer response;
367 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
47698274
RG
368 pwR.getHeader()->rd = 1;
369 pwR.getHeader()->ra = 0;
370 pwR.getHeader()->qr = 1;
371 pwR.getHeader()->rcode = RCode::NoError;
372 pwR.getHeader()->id = pwQ.getHeader()->id;
373 pwR.commit();
374 pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
375 pwR.commit();
376 pwR.addOpt(4096, 0, 0);
377 pwR.commit();
378
47698274 379 uint32_t key = 0;
78e3ac9e 380 boost::optional<Netmask> subnet;
d5d15da1 381 DNSQuestion dq(ids, query);
d84ea5be 382 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
47698274 383 BOOST_CHECK_EQUAL(found, false);
78e3ac9e 384 BOOST_CHECK(!subnet);
47698274 385
d84ea5be
RG
386 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
387 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
47698274 388 BOOST_CHECK_EQUAL(found, true);
78e3ac9e
RG
389 BOOST_CHECK(!subnet);
390
47698274
RG
391 sleep(2);
392 /* it should have expired by now */
d84ea5be 393 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
47698274 394 BOOST_CHECK_EQUAL(found, false);
78e3ac9e 395 BOOST_CHECK(!subnet);
47698274
RG
396 }
397 catch(const PDNSException& e) {
398 cerr<<"Had error: "<<e.reason<<endl;
399 throw;
400 }
401}
402
403BOOST_AUTO_TEST_CASE(test_PacketCacheNXDomainTTL) {
404 const size_t maxEntries = 150000;
405 DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
406
592b1d99
RG
407 InternalQueryState ids;
408 ids.qtype = QType::A;
409 ids.qclass = QClass::IN;
410 ids.protocol = dnsdist::Protocol::DoUDP;
47698274
RG
411
412 ComboAddress remote;
d7728daf 413 bool dnssecOK = false;
47698274
RG
414 try {
415 DNSName name("nxdomain");
592b1d99 416 ids.qname = name;
32fbb2ab
RG
417 PacketBuffer query;
418 GenericDNSPacketWriter<PacketBuffer> pwQ(query, name, QType::A, QClass::IN, 0);
47698274
RG
419 pwQ.getHeader()->rd = 1;
420
32fbb2ab
RG
421 PacketBuffer response;
422 GenericDNSPacketWriter<PacketBuffer> pwR(response, name, QType::A, QClass::IN, 0);
47698274
RG
423 pwR.getHeader()->rd = 1;
424 pwR.getHeader()->ra = 0;
425 pwR.getHeader()->qr = 1;
426 pwR.getHeader()->rcode = RCode::NXDomain;
427 pwR.getHeader()->id = pwQ.getHeader()->id;
428 pwR.commit();
429 pwR.startRecord(name, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
430 pwR.commit();
431 pwR.addOpt(4096, 0, 0);
432 pwR.commit();
433
47698274 434 uint32_t key = 0;
78e3ac9e 435 boost::optional<Netmask> subnet;
d5d15da1 436 DNSQuestion dq(ids, query);
d84ea5be 437 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
47698274 438 BOOST_CHECK_EQUAL(found, false);
78e3ac9e 439 BOOST_CHECK(!subnet);
47698274 440
d84ea5be
RG
441 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
442 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
47698274 443 BOOST_CHECK_EQUAL(found, true);
78e3ac9e
RG
444 BOOST_CHECK(!subnet);
445
47698274
RG
446 sleep(2);
447 /* it should have expired by now */
d84ea5be 448 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true);
47698274 449 BOOST_CHECK_EQUAL(found, false);
78e3ac9e 450 BOOST_CHECK(!subnet);
47698274
RG
451 }
452 catch(const PDNSException& e) {
453 cerr<<"Had error: "<<e.reason<<endl;
454 throw;
455 }
456}
457
0c8759d8
RG
458BOOST_AUTO_TEST_CASE(test_PacketCacheTruncated) {
459 const size_t maxEntries = 150000;
460 DNSDistPacketCache PC(maxEntries, /* maxTTL */ 86400, /* minTTL */ 1, /* tempFailureTTL */ 60, /* maxNegativeTTL */ 1);
461
592b1d99
RG
462 InternalQueryState ids;
463 ids.qtype = QType::A;
464 ids.qclass = QClass::IN;
465 ids.protocol = dnsdist::Protocol::DoUDP;
d5d15da1 466 ids.queryRealTime.start(); // does not have to be accurate ("realTime") in tests
0c8759d8
RG
467 bool dnssecOK = false;
468
469 try {
592b1d99 470 ids.qname = DNSName("truncated");
0c8759d8 471 PacketBuffer query;
592b1d99 472 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
0c8759d8
RG
473 pwQ.getHeader()->rd = 1;
474
475 PacketBuffer response;
592b1d99 476 GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::A, QClass::IN, 0);
0c8759d8
RG
477 pwR.getHeader()->rd = 1;
478 pwR.getHeader()->ra = 0;
479 pwR.getHeader()->qr = 1;
480 pwR.getHeader()->tc = 1;
481 pwR.getHeader()->rcode = RCode::NoError;
482 pwR.getHeader()->id = pwQ.getHeader()->id;
483 pwR.commit();
592b1d99 484 pwR.startRecord(ids.qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
0c8759d8
RG
485 pwR.xfr32BitInt(0x01020304);
486 pwR.commit();
487
488 uint32_t key = 0;
489 boost::optional<Netmask> subnet;
d5d15da1 490 DNSQuestion dq(ids, query);
0c8759d8
RG
491 bool found = PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
492 BOOST_CHECK_EQUAL(found, false);
493 BOOST_CHECK(!subnet);
494
592b1d99 495 PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, RCode::NXDomain, boost::none);
0c8759d8
RG
496
497 bool allowTruncated = true;
498 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
499 BOOST_CHECK_EQUAL(found, true);
500 BOOST_CHECK(!subnet);
501
502 allowTruncated = false;
503 found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, receivedOverUDP, 0, true, allowTruncated);
504 BOOST_CHECK_EQUAL(found, false);
505}
506 catch(const PDNSException& e) {
507 cerr<<"Had error: "<<e.reason<<endl;
508 throw;
509 }
510}
511
dd026b9c 512static DNSDistPacketCache g_PC(500000);
886e2cf2 513
f0941861 514static void threadMangler(unsigned int offset)
886e2cf2 515{
592b1d99
RG
516 InternalQueryState ids;
517 ids.qtype = QType::A;
518 ids.qclass = QClass::IN;
519 ids.protocol = dnsdist::Protocol::DoUDP;
592b1d99 520
886e2cf2 521 try {
1ea747c0 522 ComboAddress remote;
d7728daf 523 bool dnssecOK = false;
886e2cf2 524 for(unsigned int counter=0; counter < 100000; ++counter) {
592b1d99 525 ids.qname = DNSName("hello ")+DNSName(std::to_string(counter+offset));
32fbb2ab 526 PacketBuffer query;
592b1d99 527 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
886e2cf2
RG
528 pwQ.getHeader()->rd = 1;
529
32fbb2ab 530 PacketBuffer response;
592b1d99 531 GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, QType::A, QClass::IN, 0);
886e2cf2
RG
532 pwR.getHeader()->rd = 1;
533 pwR.getHeader()->ra = 1;
534 pwR.getHeader()->qr = 1;
535 pwR.getHeader()->id = pwQ.getHeader()->id;
592b1d99 536 pwR.startRecord(ids.qname, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER);
886e2cf2
RG
537 pwR.xfr32BitInt(0x01020304);
538 pwR.commit();
886e2cf2 539
886e2cf2 540 uint32_t key = 0;
78e3ac9e 541 boost::optional<Netmask> subnet;
d5d15da1 542 DNSQuestion dq(ids, query);
d84ea5be 543 g_PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
886e2cf2 544
592b1d99 545 g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, ids.qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
886e2cf2
RG
546 }
547 }
548 catch(PDNSException& e) {
549 cerr<<"Had error: "<<e.reason<<endl;
550 throw;
551 }
886e2cf2
RG
552}
553
554AtomicCounter g_missing;
555
f0941861 556static void threadReader(unsigned int offset)
886e2cf2 557{
592b1d99
RG
558 InternalQueryState ids;
559 ids.qtype = QType::A;
560 ids.qclass = QClass::IN;
561 ids.qname = DNSName("www.powerdns.com.");
562 ids.protocol = dnsdist::Protocol::DoUDP;
592b1d99 563 bool dnssecOK = false;
886e2cf2
RG
564 try
565 {
1ea747c0 566 ComboAddress remote;
886e2cf2 567 for(unsigned int counter=0; counter < 100000; ++counter) {
592b1d99 568 ids.qname = DNSName("hello ")+DNSName(std::to_string(counter+offset));
32fbb2ab 569 PacketBuffer query;
592b1d99 570 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, QType::A, QClass::IN, 0);
886e2cf2
RG
571 pwQ.getHeader()->rd = 1;
572
886e2cf2 573 uint32_t key = 0;
78e3ac9e 574 boost::optional<Netmask> subnet;
d5d15da1 575 DNSQuestion dq(ids, query);
d84ea5be 576 bool found = g_PC.get(dq, 0, &key, subnet, dnssecOK, receivedOverUDP);
886e2cf2
RG
577 if (!found) {
578 g_missing++;
579 }
580 }
581 }
582 catch(PDNSException& e) {
583 cerr<<"Had error in threadReader: "<<e.reason<<endl;
584 throw;
585 }
886e2cf2
RG
586}
587
588BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) {
589 try {
f0941861
RG
590 std::vector<std::thread> threads;
591 for (int i = 0; i < 4; ++i) {
592 threads.push_back(std::thread(threadMangler, i*1000000UL));
593 }
594
595 for (auto& t : threads) {
596 t.join();
597 }
598
599 threads.clear();
886e2cf2 600
690b86b7 601 BOOST_CHECK_EQUAL(g_PC.getSize() + g_PC.getDeferredInserts() + g_PC.getInsertCollisions(), 400000U);
dd026b9c 602 BOOST_CHECK_SMALL(1.0*g_PC.getInsertCollisions(), 10000.0);
886e2cf2 603
f0941861
RG
604 for (int i = 0; i < 4; ++i) {
605 threads.push_back(std::thread(threadReader, i*1000000UL));
606 }
607
608 for (auto& t : threads) {
609 t.join();
610 }
886e2cf2 611
dd026b9c 612 BOOST_CHECK((g_PC.getDeferredInserts() + g_PC.getDeferredLookups() + g_PC.getInsertCollisions()) >= g_missing);
886e2cf2
RG
613 }
614 catch(PDNSException& e) {
615 cerr<<"Had error: "<<e.reason<<endl;
616 throw;
617 }
618
619}
620
78e3ac9e
RG
621BOOST_AUTO_TEST_CASE(test_PCCollision) {
622 const size_t maxEntries = 150000;
623 DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true);
690b86b7 624 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
78e3ac9e 625
592b1d99
RG
626 InternalQueryState ids;
627 ids.qtype = QType::AAAA;
628 ids.qclass = QClass::IN;
629 ids.qname = DNSName("www.powerdns.com.");
630 ids.protocol = dnsdist::Protocol::DoUDP;
78e3ac9e
RG
631 uint16_t qid = 0x42;
632 uint32_t key;
633 uint32_t secondKey;
634 boost::optional<Netmask> subnetOut;
d7728daf 635 bool dnssecOK = false;
78e3ac9e 636
fa980c59 637 /* lookup for a query with a first ECS value,
78e3ac9e
RG
638 insert a corresponding response */
639 {
32fbb2ab 640 PacketBuffer query;
592b1d99 641 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, QClass::IN, 0);
78e3ac9e
RG
642 pwQ.getHeader()->rd = 1;
643 pwQ.getHeader()->id = qid;
32fbb2ab 644 GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions;
78e3ac9e 645 EDNSSubnetOpts opt;
fa980c59 646 opt.source = Netmask("10.0.59.220/32");
e32a8d46 647 ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt));
78e3ac9e
RG
648 pwQ.addOpt(512, 0, 0, ednsOptions);
649 pwQ.commit();
650
78e3ac9e 651 ComboAddress remote("192.0.2.1");
d5d15da1
RG
652 ids.queryRealTime.start();
653 DNSQuestion dq(ids, query);
d84ea5be 654 bool found = PC.get(dq, 0, &key, subnetOut, dnssecOK, receivedOverUDP);
78e3ac9e
RG
655 BOOST_CHECK_EQUAL(found, false);
656 BOOST_REQUIRE(subnetOut);
657 BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
658
32fbb2ab 659 PacketBuffer response;
592b1d99 660 GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, ids.qtype, QClass::IN, 0);
78e3ac9e
RG
661 pwR.getHeader()->rd = 1;
662 pwR.getHeader()->id = qid;
592b1d99 663 pwR.startRecord(ids.qname, ids.qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
78e3ac9e
RG
664 ComboAddress v6("::1");
665 pwR.xfrCAWithoutPort(6, v6);
666 pwR.commit();
667 pwR.addOpt(512, 0, 0, ednsOptions);
668 pwR.commit();
669
592b1d99 670 PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, ids.qname, ids.qtype, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
690b86b7 671 BOOST_CHECK_EQUAL(PC.getSize(), 1U);
78e3ac9e 672
d84ea5be 673 found = PC.get(dq, 0, &key, subnetOut, dnssecOK, receivedOverUDP);
78e3ac9e
RG
674 BOOST_CHECK_EQUAL(found, true);
675 BOOST_REQUIRE(subnetOut);
676 BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
677 }
678
fa980c59 679 /* now lookup for the same query with a different ECS value,
78e3ac9e
RG
680 we should get the same key (collision) but no match */
681 {
32fbb2ab 682 PacketBuffer query;
592b1d99 683 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, QClass::IN, 0);
78e3ac9e
RG
684 pwQ.getHeader()->rd = 1;
685 pwQ.getHeader()->id = qid;
32fbb2ab 686 GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions;
78e3ac9e 687 EDNSSubnetOpts opt;
fa980c59 688 opt.source = Netmask("10.0.167.48/32");
e32a8d46 689 ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt));
78e3ac9e
RG
690 pwQ.addOpt(512, 0, 0, ednsOptions);
691 pwQ.commit();
692
78e3ac9e 693 ComboAddress remote("192.0.2.1");
d5d15da1
RG
694 ids.queryRealTime.start();
695 DNSQuestion dq(ids, query);
d84ea5be 696 bool found = PC.get(dq, 0, &secondKey, subnetOut, dnssecOK, receivedOverUDP);
78e3ac9e
RG
697 BOOST_CHECK_EQUAL(found, false);
698 BOOST_CHECK_EQUAL(secondKey, key);
699 BOOST_REQUIRE(subnetOut);
700 BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
690b86b7 701 BOOST_CHECK_EQUAL(PC.getLookupCollisions(), 1U);
78e3ac9e 702 }
fa980c59
RG
703
704#if 0
705 /* to be able to compute a new collision if the packet cache hashing code is updated */
706 {
707 DNSDistPacketCache pc(10000);
32fbb2ab 708 GenericDNSPacketWriter<PacketBuffer>::optvect_t ednsOptions;
fa980c59
RG
709 EDNSSubnetOpts opt;
710 std::map<uint32_t, Netmask> colMap;
711 size_t collisions = 0;
712 size_t total = 0;
713 //qname = DNSName("collision-with-ecs-parsing.cache.tests.powerdns.com.");
714
715 for (size_t idxA = 0; idxA < 256; idxA++) {
716 for (size_t idxB = 0; idxB < 256; idxB++) {
717 for (size_t idxC = 0; idxC < 256; idxC++) {
32fbb2ab 718 PacketBuffer secondQuery;
592b1d99 719 GenericDNSPacketWriter<PacketBuffer> pwFQ(secondQuery, ids.qname, QType::AAAA, QClass::IN, 0);
fa980c59
RG
720 pwFQ.getHeader()->rd = 1;
721 pwFQ.getHeader()->qr = false;
722 pwFQ.getHeader()->id = 0x42;
723 opt.source = Netmask("10." + std::to_string(idxA) + "." + std::to_string(idxB) + "." + std::to_string(idxC) + "/32");
724 ednsOptions.clear();
e32a8d46 725 ednsOptions.emplace_back(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt));
fa980c59
RG
726 pwFQ.addOpt(512, 0, 0, ednsOptions);
727 pwFQ.commit();
592b1d99 728 secondKey = pc.getKey(ids.qname.toDNSString(), ids.qname.wirelength(), secondQuery, false);
e32a8d46 729 auto pair = colMap.emplace(secondKey, opt.source);
fa980c59
RG
730 total++;
731 if (!pair.second) {
732 collisions++;
733 cerr<<"Collision between "<<colMap[secondKey].toString()<<" and "<<opt.source.toString()<<" for key "<<secondKey<<endl;
734 goto done;
735 }
736 }
737 }
738 }
739 done:
740 cerr<<"collisions: "<<collisions<<endl;
741 cerr<<"total: "<<total<<endl;
742 }
743#endif
78e3ac9e
RG
744}
745
d7728daf
RG
746BOOST_AUTO_TEST_CASE(test_PCDNSSECCollision) {
747 const size_t maxEntries = 150000;
748 DNSDistPacketCache PC(maxEntries, 86400, 1, 60, 3600, 60, false, 1, true, true);
690b86b7 749 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
d7728daf 750
592b1d99
RG
751 InternalQueryState ids;
752 ids.qtype = QType::AAAA;
753 ids.qclass = QClass::IN;
754 ids.qname = DNSName("www.powerdns.com.");
755 ids.protocol = dnsdist::Protocol::DoUDP;
d7728daf
RG
756 uint16_t qid = 0x42;
757 uint32_t key;
758 boost::optional<Netmask> subnetOut;
759
760 /* lookup for a query with DNSSEC OK,
761 insert a corresponding response with DO set,
762 check that it doesn't match without DO, but does with it */
763 {
32fbb2ab 764 PacketBuffer query;
592b1d99 765 GenericDNSPacketWriter<PacketBuffer> pwQ(query, ids.qname, ids.qtype, QClass::IN, 0);
d7728daf
RG
766 pwQ.getHeader()->rd = 1;
767 pwQ.getHeader()->id = qid;
768 pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
769 pwQ.commit();
770
d7728daf 771 ComboAddress remote("192.0.2.1");
d5d15da1 772 ids.queryRealTime.start();
592b1d99 773 ids.origRemote = remote;
d5d15da1 774 DNSQuestion dq(ids, query);
d84ea5be 775 bool found = PC.get(dq, 0, &key, subnetOut, true, receivedOverUDP);
d7728daf
RG
776 BOOST_CHECK_EQUAL(found, false);
777
32fbb2ab 778 PacketBuffer response;
592b1d99 779 GenericDNSPacketWriter<PacketBuffer> pwR(response, ids.qname, ids.qtype, QClass::IN, 0);
d7728daf
RG
780 pwR.getHeader()->rd = 1;
781 pwR.getHeader()->id = qid;
592b1d99 782 pwR.startRecord(ids.qname, ids.qtype, 100, QClass::IN, DNSResourceRecord::ANSWER);
d7728daf
RG
783 ComboAddress v6("::1");
784 pwR.xfrCAWithoutPort(6, v6);
785 pwR.commit();
786 pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
787 pwR.commit();
788
592b1d99 789 PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, ids.qname, ids.qtype, QClass::IN, response, receivedOverUDP, RCode::NoError, boost::none);
690b86b7 790 BOOST_CHECK_EQUAL(PC.getSize(), 1U);
d7728daf 791
d84ea5be 792 found = PC.get(dq, 0, &key, subnetOut, false, receivedOverUDP);
d7728daf
RG
793 BOOST_CHECK_EQUAL(found, false);
794
d84ea5be 795 found = PC.get(dq, 0, &key, subnetOut, true, receivedOverUDP);
d7728daf
RG
796 BOOST_CHECK_EQUAL(found, true);
797 }
798
799}
800
fec4382e
RG
801BOOST_AUTO_TEST_CASE(test_PacketCacheInspection) {
802 const size_t maxEntries = 100;
803 DNSDistPacketCache PC(maxEntries, 86400, 1);
804 BOOST_CHECK_EQUAL(PC.getSize(), 0U);
fec4382e
RG
805
806 ComboAddress remote;
807 bool dnssecOK = false;
808
809 uint32_t key = 0;
810
811 /* insert powerdns.com A 192.0.2.1, 192.0.2.2 */
812 {
813 DNSName qname("powerdns.com");
814 PacketBuffer query;
815 GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
816 pwQ.getHeader()->rd = 1;
817
818 PacketBuffer response;
819 GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
820 pwR.getHeader()->rd = 1;
821 pwR.getHeader()->ra = 1;
822 pwR.getHeader()->qr = 1;
823 pwR.getHeader()->id = pwQ.getHeader()->id;
824 {
825 ComboAddress addr("192.0.2.1");
826 pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
827 pwR.xfrCAWithoutPort(4, addr);
828 pwR.commit();
829 }
830 {
831 ComboAddress addr("192.0.2.2");
832 pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
833 pwR.xfrCAWithoutPort(4, addr);
834 pwR.commit();
835 }
836
837 PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
838 BOOST_CHECK_EQUAL(PC.getSize(), key);
839 }
840
841 /* insert powerdns1.com A 192.0.2.3, 192.0.2.4, AAAA 2001:db8::3, 2001:db8::4 */
842 {
843 DNSName qname("powerdns1.com");
844 PacketBuffer query;
845 GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
846 pwQ.getHeader()->rd = 1;
847
848 PacketBuffer response;
849 GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
850 pwR.getHeader()->rd = 1;
851 pwR.getHeader()->ra = 1;
852 pwR.getHeader()->qr = 1;
853 pwR.getHeader()->id = pwQ.getHeader()->id;
854 {
855 ComboAddress addr("192.0.2.3");
856 pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
857 pwR.xfrCAWithoutPort(4, addr);
858 pwR.commit();
859 }
860 {
861 ComboAddress addr("192.0.2.4");
862 pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
863 pwR.xfrCAWithoutPort(4, addr);
864 pwR.commit();
865 }
866 {
867 ComboAddress addr("2001:db8::3");
868 pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
869 pwR.xfrCAWithoutPort(6, addr);
870 pwR.commit();
871 }
872 {
873 ComboAddress addr("2001:db8::4");
874 pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
875 pwR.xfrCAWithoutPort(6, addr);
876 pwR.commit();
877 }
878
879 PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
880 BOOST_CHECK_EQUAL(PC.getSize(), key);
881 }
882
883 /* insert powerdns2.com NODATA */
884 {
885 DNSName qname("powerdns2.com");
886 PacketBuffer query;
887 GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
888 pwQ.getHeader()->rd = 1;
889
890 PacketBuffer response;
891 GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
892 pwR.getHeader()->rd = 1;
893 pwR.getHeader()->ra = 1;
894 pwR.getHeader()->qr = 1;
895 pwR.getHeader()->id = pwQ.getHeader()->id;
896 pwR.commit();
897 pwR.startRecord(qname, QType::SOA, 86400, QClass::IN, DNSResourceRecord::AUTHORITY);
898 pwR.commit();
899 pwR.addOpt(4096, 0, 0);
900 pwR.commit();
901
902 PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
903 BOOST_CHECK_EQUAL(PC.getSize(), key);
904 }
905
906 /* insert powerdns3.com AAAA 2001:db8::4, 2001:db8::5 */
907 {
908 DNSName qname("powerdns3.com");
909 PacketBuffer query;
910 GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
911 pwQ.getHeader()->rd = 1;
912
913 PacketBuffer response;
914 GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
915 pwR.getHeader()->rd = 1;
916 pwR.getHeader()->ra = 1;
917 pwR.getHeader()->qr = 1;
918 pwR.getHeader()->id = pwQ.getHeader()->id;
919 {
920 ComboAddress addr("2001:db8::4");
921 pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
922 pwR.xfrCAWithoutPort(6, addr);
923 pwR.commit();
924 }
925 {
926 ComboAddress addr("2001:db8::5");
927 pwR.startRecord(qname, QType::AAAA, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
928 pwR.xfrCAWithoutPort(6, addr);
929 pwR.commit();
930 }
931
932 PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
933 BOOST_CHECK_EQUAL(PC.getSize(), key);
934 }
935
936 /* insert powerdns4.com A 192.0.2.1 */
937 {
938 DNSName qname("powerdns4.com");
939 PacketBuffer query;
940 GenericDNSPacketWriter<PacketBuffer> pwQ(query, qname, QType::A, QClass::IN, 0);
941 pwQ.getHeader()->rd = 1;
942
943 PacketBuffer response;
944 GenericDNSPacketWriter<PacketBuffer> pwR(response, qname, QType::A, QClass::IN, 0);
945 pwR.getHeader()->rd = 1;
946 pwR.getHeader()->ra = 1;
947 pwR.getHeader()->qr = 1;
948 pwR.getHeader()->id = pwQ.getHeader()->id;
949 {
950 ComboAddress addr("192.0.2.1");
951 pwR.startRecord(qname, QType::A, 7200, QClass::IN, DNSResourceRecord::ADDITIONAL);
952 pwR.xfrCAWithoutPort(4, addr);
953 pwR.commit();
954 }
955
956 PC.insert(key++, boost::none, *getFlagsFromDNSHeader(pwQ.getHeader()), dnssecOK, qname, QType::A, QClass::IN, response, receivedOverUDP, 0, boost::none);
957 BOOST_CHECK_EQUAL(PC.getSize(), key);
958 }
959
960 {
961 auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.1"));
962 BOOST_CHECK_EQUAL(domains.size(), 2U);
963 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns.com")), 1U);
964 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns4.com")), 1U);
965 }
966 {
967 auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.2"));
968 BOOST_CHECK_EQUAL(domains.size(), 1U);
969 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns.com")), 1U);
970 }
971 {
972 auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.3"));
973 BOOST_CHECK_EQUAL(domains.size(), 1U);
974 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
975 }
976 {
977 auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.4"));
978 BOOST_CHECK_EQUAL(domains.size(), 1U);
979 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
980 }
981 {
982 auto domains = PC.getDomainsContainingRecords(ComboAddress("192.0.2.5"));
983 BOOST_CHECK_EQUAL(domains.size(), 0U);
984 }
985 {
986 auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::3"));
987 BOOST_CHECK_EQUAL(domains.size(), 1U);
988 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
989 }
990 {
991 auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::4"));
992 BOOST_CHECK_EQUAL(domains.size(), 2U);
993 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns1.com")), 1U);
994 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns3.com")), 1U);
995 }
996 {
997 auto domains = PC.getDomainsContainingRecords(ComboAddress("2001:db8::5"));
998 BOOST_CHECK_EQUAL(domains.size(), 1U);
999 BOOST_CHECK_EQUAL(domains.count(DNSName("powerdns3.com")), 1U);
1000 }
1001
1002 {
1003 auto records = PC.getRecordsForDomain(DNSName("powerdns.com"));
1004 BOOST_CHECK_EQUAL(records.size(), 2U);
1005 BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.1")), 1U);
1006 BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.2")), 1U);
1007 }
1008
1009 {
1010 auto records = PC.getRecordsForDomain(DNSName("powerdns1.com"));
1011 BOOST_CHECK_EQUAL(records.size(), 4U);
1012 BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.3")), 1U);
1013 BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.4")), 1U);
1014 BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::3")), 1U);
1015 BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U);
1016 }
1017
1018 {
1019 auto records = PC.getRecordsForDomain(DNSName("powerdns2.com"));
1020 BOOST_CHECK_EQUAL(records.size(), 0U);
1021 }
1022
1023 {
1024 auto records = PC.getRecordsForDomain(DNSName("powerdns3.com"));
1025 BOOST_CHECK_EQUAL(records.size(), 2U);
1026 BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U);
1027 BOOST_CHECK_EQUAL(records.count(ComboAddress("2001:db8::4")), 1U);
1028 }
1029
1030 {
1031 auto records = PC.getRecordsForDomain(DNSName("powerdns4.com"));
1032 BOOST_CHECK_EQUAL(records.size(), 1U);
1033 BOOST_CHECK_EQUAL(records.count(ComboAddress("192.0.2.1")), 1U);
1034 }
1035
1036 {
1037 auto records = PC.getRecordsForDomain(DNSName("powerdns5.com"));
1038 BOOST_CHECK_EQUAL(records.size(), 0U);
1039 }
1040}
1041
886e2cf2 1042BOOST_AUTO_TEST_SUITE_END()