1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
7 #include <boost/test/unit_test.hpp>
10 #include "recursor_cache.hh"
12 BOOST_AUTO_TEST_SUITE(recursorcache_cc
)
14 BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple
)
18 std::vector
<DNSRecord
> records
;
19 std::vector
<std::shared_ptr
<DNSRecord
>> authRecords
;
20 std::vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
21 time_t now
= time(nullptr);
23 time_t ttd
= now
+ 30;
24 DNSName
power("powerdns.com.");
26 ComboAddress
dr0Content("2001:DB8::");
28 dr0
.d_type
= QType::AAAA
;
29 dr0
.d_class
= QClass::IN
;
30 dr0
.d_content
= std::make_shared
<AAAARecordContent
>(dr0Content
);
31 dr0
.d_ttl
= static_cast<uint32_t>(ttd
);
32 dr0
.d_place
= DNSResourceRecord::ANSWER
;
34 records
.push_back(dr0
);
36 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
37 MRC
.replace(now
, DNSName("hello"), QType(QType::A
), records
, signatures
, authRecords
, true, boost::none
);
38 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
39 BOOST_CHECK_GT(MRC
.bytes(), 1U);
40 BOOST_CHECK_EQUAL(MRC
.doWipeCache(DNSName("hello"), false, QType::A
), 1U);
41 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
42 BOOST_CHECK_EQUAL(MRC
.bytes(), 0U);
46 for (counter
= 0; counter
< 100000; ++counter
) {
47 DNSName a
= DNSName("hello ") + DNSName(std::to_string(counter
));
48 BOOST_CHECK_EQUAL(DNSName(a
.toString()), a
);
50 MRC
.replace(now
, a
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::none
);
51 if (!MRC
.doWipeCache(a
, false))
52 BOOST_FAIL("Could not remove entry we just added to the cache!");
53 MRC
.replace(now
, a
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::none
);
56 BOOST_CHECK_EQUAL(MRC
.size(), counter
);
58 uint64_t delcounter
= 0;
59 for (delcounter
= 0; delcounter
< counter
/ 100; ++delcounter
) {
60 DNSName a
= DNSName("hello ") + DNSName(std::to_string(delcounter
));
61 BOOST_CHECK_EQUAL(MRC
.doWipeCache(a
, false, QType::A
), 1U);
64 BOOST_CHECK_EQUAL(MRC
.size(), counter
- delcounter
);
66 std::vector
<DNSRecord
> retrieved
;
67 ComboAddress
who("192.0.2.1");
69 int64_t expected
= counter
- delcounter
;
71 for (; delcounter
< counter
; ++delcounter
) {
72 if (MRC
.get(now
, DNSName("hello ") + DNSName(std::to_string(delcounter
)), QType(QType::A
), false, &retrieved
, who
) > 0) {
74 BOOST_REQUIRE_EQUAL(retrieved
.size(), records
.size());
75 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0Content
.toString());
78 BOOST_CHECK_EQUAL(matches
, expected
);
80 MRC
.doWipeCache(DNSName("."), true);
81 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
84 ComboAddress
dr1Content("2001:DB8::1");
86 dr1
.d_type
= QType::AAAA
;
87 dr1
.d_class
= QClass::IN
;
88 dr1
.d_content
= std::make_shared
<AAAARecordContent
>(dr1Content
);
89 dr1
.d_ttl
= static_cast<uint32_t>(ttd
);
90 dr1
.d_place
= DNSResourceRecord::ANSWER
;
93 ComboAddress
dr2Content("192.0.2.42");
95 dr2
.d_type
= QType::A
;
96 dr2
.d_class
= QClass::IN
;
97 dr2
.d_content
= std::make_shared
<ARecordContent
>(dr2Content
);
98 dr2
.d_ttl
= static_cast<uint32_t>(ttd
);
99 // the place should not matter to the cache
100 dr2
.d_place
= DNSResourceRecord::AUTHORITY
;
102 // insert a subnet specific entry
104 records
.push_back(dr1
);
105 MRC
.replace(now
, power
, QType(QType::AAAA
), records
, signatures
, authRecords
, true, boost::optional
<Netmask
>("192.0.2.1/25"));
106 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
108 // subnet specific should be returned for a matching subnet
109 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::AAAA
), false, &retrieved
, ComboAddress("192.0.2.2")), (ttd
- now
));
110 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
111 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
113 // subnet specific should not be returned for a different subnet
114 BOOST_CHECK_LT(MRC
.get(now
, power
, QType(QType::AAAA
), false, &retrieved
, ComboAddress("127.0.0.1")), 0);
115 BOOST_CHECK_EQUAL(retrieved
.size(), 0U);
118 MRC
.doWipeCache(DNSName("."), true);
119 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
121 // insert a NON-subnet specific entry
123 records
.push_back(dr2
);
124 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::none
);
125 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
127 // NON-subnet specific should always be returned
128 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("127.0.0.1")), (ttd
- now
));
129 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
130 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
132 // insert a subnet specific entry for the same name but a different QType
134 records
.push_back(dr1
);
135 MRC
.replace(now
, power
, QType(QType::AAAA
), records
, signatures
, authRecords
, true, boost::optional
<Netmask
>("192.0.2.1/25"));
136 // we should not have replaced the existing entry
137 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
139 // insert a TXT one, we will use that later
141 records
.push_back(dr1
);
142 MRC
.replace(now
, power
, QType(QType::TXT
), records
, signatures
, authRecords
, true, boost::none
);
143 // we should not have replaced any existing entry
144 BOOST_CHECK_EQUAL(MRC
.size(), 3U);
146 // we should still get the NON-subnet specific entry
147 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("127.0.0.1")), (ttd
- now
));
148 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
149 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
151 // we should get the subnet specific entry if we are from the right subnet
152 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::AAAA
), false, &retrieved
, ComboAddress("192.0.2.3")), (ttd
- now
));
153 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
154 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
156 // but nothing from a different subnet
157 BOOST_CHECK_LT(MRC
.get(now
, power
, QType(QType::AAAA
), false, &retrieved
, ComboAddress("127.0.0.1")), 0);
158 BOOST_CHECK_EQUAL(retrieved
.size(), 0U);
160 // QType::ANY should return any qtype, so from the right subnet we should get all of them
161 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::ANY
), false, &retrieved
, ComboAddress("192.0.2.3")), (ttd
- now
));
162 BOOST_CHECK_EQUAL(retrieved
.size(), 3U);
163 for (const auto& rec
: retrieved
) {
164 BOOST_CHECK(rec
.d_type
== QType::A
|| rec
.d_type
== QType::AAAA
|| rec
.d_type
== QType::TXT
);
166 // check that the place is always set to ANSWER
167 for (const auto& rec
: retrieved
) {
168 BOOST_CHECK(rec
.d_place
== DNSResourceRecord::ANSWER
);
171 // but only the non-subnet specific from the another subnet
172 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::ANY
), false, &retrieved
, ComboAddress("127.0.0.1")), (ttd
- now
));
173 BOOST_CHECK_EQUAL(retrieved
.size(), 2U);
174 for (const auto& rec
: retrieved
) {
175 BOOST_CHECK(rec
.d_type
== QType::A
|| rec
.d_type
== QType::TXT
);
178 // QType::ADDR should return both A and AAAA but no TXT, so two entries from the right subnet
179 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::ADDR
), false, &retrieved
, ComboAddress("192.0.2.3")), (ttd
- now
));
180 BOOST_CHECK_EQUAL(retrieved
.size(), 2U);
182 bool gotAAAA
= false;
183 for (const auto& rec
: retrieved
) {
184 BOOST_CHECK(rec
.d_type
== QType::A
|| rec
.d_type
== QType::AAAA
);
185 if (rec
.d_type
== QType::A
) {
188 else if (rec
.d_type
== QType::AAAA
) {
193 BOOST_CHECK(gotAAAA
);
195 // but only the non-subnet specific one from the another subnet
196 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::ADDR
), false, &retrieved
, ComboAddress("127.0.0.1")), (ttd
- now
));
197 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
198 BOOST_CHECK(retrieved
.at(0).d_type
== QType::A
);
200 // entries are only valid until ttd, we should not get anything after that because they are expired
201 BOOST_CHECK_LT(MRC
.get(ttd
+ 5, power
, QType(QType::ADDR
), false, &retrieved
, ComboAddress("127.0.0.1")), 0);
202 BOOST_CHECK_EQUAL(retrieved
.size(), 0U);
204 // let's age the records for our existing QType::TXT entry so they are now only valid for 5s
206 BOOST_CHECK_EQUAL(MRC
.doAgeCache(now
, power
, QType::TXT
, newTTL
), true);
208 // we should still be able to retrieve it
209 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::TXT
), false, &retrieved
, ComboAddress("127.0.0.1")), static_cast<int32_t>(newTTL
));
210 BOOST_CHECK_EQUAL(retrieved
.size(), 1U);
211 BOOST_CHECK(retrieved
.at(0).d_type
== QType::TXT
);
212 // please note that this is still a TTD at this point
213 BOOST_CHECK_EQUAL(retrieved
.at(0).d_ttl
, now
+ newTTL
);
215 // but 10s later it should be gone
216 BOOST_CHECK_LT(MRC
.get(now
+ 10, power
, QType(QType::TXT
), false, &retrieved
, ComboAddress("127.0.0.1")), 0);
217 BOOST_CHECK_EQUAL(retrieved
.size(), 0U);
220 MRC
.doWipeCache(DNSName("."), true);
221 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
224 // insert auth record
225 records
.push_back(dr2
);
226 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::none
);
227 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
228 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("127.0.0.1")), (ttd
- now
));
229 BOOST_CHECK_EQUAL(retrieved
.size(), 1U);
232 ComboAddress
dr3Content("192.0.2.84");
234 dr3
.d_type
= QType::A
;
235 dr3
.d_class
= QClass::IN
;
236 dr3
.d_content
= std::make_shared
<ARecordContent
>(dr3Content
);
237 dr3
.d_ttl
= static_cast<uint32_t>(ttd
+ 100);
238 // the place should not matter to the cache
239 dr3
.d_place
= DNSResourceRecord::AUTHORITY
;
241 // this is important for our tests
242 BOOST_REQUIRE_GT(dr3
.d_ttl
, ttd
);
245 records
.push_back(dr3
);
247 // non-auth should not replace valid auth
248 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, false, boost::none
);
249 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
250 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("127.0.0.1")), (ttd
- now
));
251 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
252 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
254 // but non-auth _should_ replace expired auth
255 MRC
.replace(ttd
+ 1, power
, QType(QType::A
), records
, signatures
, authRecords
, false, boost::none
);
256 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
257 BOOST_CHECK_EQUAL(MRC
.get(ttd
+ 1, power
, QType(QType::A
), false, &retrieved
, ComboAddress("127.0.0.1")), (dr3
.d_ttl
- (ttd
+ 1)));
258 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
259 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr3Content
.toString());
261 // auth should replace non-auth
263 records
.push_back(dr2
);
264 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, false, boost::none
);
265 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
266 // let's first check that non-auth is not returned when we need authoritative data
267 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), true, &retrieved
, ComboAddress("127.0.0.1")), -now
);
268 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("127.0.0.1")), (ttd
- now
));
269 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
270 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
272 /**** Most specific netmask tests ****/
275 MRC
.doWipeCache(DNSName("."), true);
276 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
279 // insert an entry for 192.0.0.1/8
281 records
.push_back(dr2
);
282 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::optional
<Netmask
>("192.0.0.1/8"));
283 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
285 /* same as dr2 except for the actual IP */
287 ComboAddress
dr4Content("192.0.2.126");
289 dr4
.d_type
= QType::A
;
290 dr4
.d_class
= QClass::IN
;
291 dr4
.d_content
= std::make_shared
<ARecordContent
>(dr4Content
);
292 dr4
.d_ttl
= static_cast<uint32_t>(ttd
);
293 dr4
.d_place
= DNSResourceRecord::AUTHORITY
;
295 // insert another entry but for 192.168.0.1/31
297 records
.push_back(dr4
);
298 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::optional
<Netmask
>("192.168.0.1/31"));
299 // we should not have replaced any existing entry
300 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
302 // insert the same than the first one but for 192.168.0.2/32
304 records
.push_back(dr2
);
305 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::optional
<Netmask
>("192.168.0.2/32"));
306 // we should not have replaced any existing entry
307 BOOST_CHECK_EQUAL(MRC
.size(), 3U);
309 // we should get the most specific entry for 192.168.0.1, so the second one
310 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.168.0.1")), (ttd
- now
));
311 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
312 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr4Content
.toString());
315 MRC
.doWipeCache(DNSName("."), true);
316 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
319 // insert an entry for 192.0.0.1/8, non auth
321 records
.push_back(dr2
);
322 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, false, boost::optional
<Netmask
>("192.0.0.1/8"));
323 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
325 // we should not get it when we need authoritative data
326 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), true, &retrieved
, ComboAddress("192.168.0.1")), -1);
327 BOOST_REQUIRE_EQUAL(retrieved
.size(), 0U);
329 // but we should when we are OK with non-auth
330 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.168.0.1")), (ttd
- now
));
331 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
332 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
334 catch (const PDNSException
& e
) {
335 cerr
<< "Had error: " << e
.reason
<< endl
;
340 BOOST_AUTO_TEST_CASE(test_RecursorCacheGhost
)
342 MemRecursorCache MRC
;
344 std::vector
<DNSRecord
> records
;
345 std::vector
<std::shared_ptr
<DNSRecord
>> authRecords
;
346 std::vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
347 time_t now
= time(nullptr);
349 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
351 /* insert NS coming from a delegation */
352 time_t ttd
= now
+ 30;
353 DNSName
ghost("ghost.powerdns.com.");
355 std::string
ns1Content("ns1.ghost.powerdns.com.");
357 ns1
.d_type
= QType::NS
;
358 ns1
.d_class
= QClass::IN
;
359 ns1
.d_content
= std::make_shared
<NSRecordContent
>(ns1Content
);
360 ns1
.d_ttl
= static_cast<uint32_t>(ttd
);
361 ns1
.d_place
= DNSResourceRecord::ANSWER
;
362 records
.push_back(ns1
);
363 MRC
.replace(now
, ns1
.d_name
, QType(ns1
.d_type
), records
, signatures
, authRecords
, true, boost::none
);
364 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
366 /* try to raise the TTL, simulating the delegated authoritative server
367 raising the TTL so the zone stays alive */
369 ns1
.d_ttl
= static_cast<uint32_t>(ttd
+ 3600);
370 records
.push_back(ns1
);
371 MRC
.replace(now
, ns1
.d_name
, QType(ns1
.d_type
), records
, signatures
, authRecords
, true, boost::none
);
372 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
374 /* the TTL should not have been raisd */
375 std::vector
<DNSRecord
> retrieved
;
376 BOOST_CHECK_EQUAL(MRC
.get(now
, ghost
, QType(QType::NS
), false, &retrieved
, ComboAddress("192.0.2.2")), (ttd
- now
));
377 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
378 BOOST_CHECK_EQUAL(retrieved
.at(0).d_ttl
, static_cast<uint32_t>(ttd
));
381 BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries
)
383 MemRecursorCache
MRC(1);
385 std::vector
<DNSRecord
> records
;
386 std::vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
387 std::vector
<std::shared_ptr
<DNSRecord
>> authRecs
;
388 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
389 time_t now
= time(nullptr);
390 DNSName
power1("powerdns.com.");
391 DNSName
power2("powerdns-1.com.");
392 time_t ttd
= now
- 30;
393 std::vector
<DNSRecord
> retrieved
;
394 ComboAddress
who("192.0.2.1");
396 /* entry for power, which expired 30s ago */
398 ComboAddress
dr1Content("2001:DB8::1");
400 dr1
.d_type
= QType::AAAA
;
401 dr1
.d_class
= QClass::IN
;
402 dr1
.d_content
= std::make_shared
<AAAARecordContent
>(dr1Content
);
403 dr1
.d_ttl
= static_cast<uint32_t>(ttd
);
404 dr1
.d_place
= DNSResourceRecord::ANSWER
;
406 /* entry for power1, which expired 30 ago too */
408 ComboAddress
dr2Content("2001:DB8::2");
410 dr2
.d_type
= QType::AAAA
;
411 dr2
.d_class
= QClass::IN
;
412 dr2
.d_content
= std::make_shared
<AAAARecordContent
>(dr2Content
);
413 dr2
.d_ttl
= static_cast<uint32_t>(ttd
);
414 dr2
.d_place
= DNSResourceRecord::ANSWER
;
416 /* insert both entries */
417 records
.push_back(dr1
);
418 MRC
.replace(now
, power1
, QType(dr1
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
420 records
.push_back(dr2
);
421 MRC
.replace(now
, power2
, QType(dr2
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
423 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
425 /* the one for power2 having been inserted
426 more recently should be removed last */
427 /* we ask that only entry remains in the cache */
429 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
431 /* the remaining entry should be power2, but to get it
432 we need to go back in the past a bit */
433 BOOST_CHECK_EQUAL(MRC
.get(ttd
- 1, power2
, QType(dr2
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), 1);
434 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
435 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
436 /* check that power1 is gone */
437 BOOST_CHECK_EQUAL(MRC
.get(ttd
- 1, power1
, QType(dr1
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), -1);
439 /* clear everything up */
440 MRC
.doWipeCache(DNSName("."), true);
441 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
444 /* insert both entries back */
445 records
.push_back(dr1
);
446 MRC
.replace(now
, power1
, QType(dr1
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
448 records
.push_back(dr2
);
449 MRC
.replace(now
, power2
, QType(dr2
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
451 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
453 /* trigger a miss (expired) for power2 */
454 BOOST_CHECK_EQUAL(MRC
.get(now
, power2
, QType(dr2
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), -now
);
456 /* power2 should have been moved to the front of the expunge
457 queue, and should this time be removed first */
458 /* we ask that only entry remains in the cache */
460 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
462 /* the remaining entry should be power1, but to get it
463 we need to go back in the past a bit */
464 BOOST_CHECK_EQUAL(MRC
.get(ttd
- 1, power1
, QType(dr1
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), 1);
465 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
466 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
467 /* check that power2 is gone */
468 BOOST_CHECK_EQUAL(MRC
.get(ttd
- 1, power2
, QType(dr2
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), -1);
471 BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries
)
473 MemRecursorCache
MRC(1);
475 std::vector
<DNSRecord
> records
;
476 std::vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
477 std::vector
<std::shared_ptr
<DNSRecord
>> authRecs
;
478 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
479 time_t now
= time(nullptr);
480 DNSName
power1("powerdns.com.");
481 DNSName
power2("powerdns-1.com.");
482 time_t ttd
= now
+ 30;
483 std::vector
<DNSRecord
> retrieved
;
484 ComboAddress
who("192.0.2.1");
486 /* entry for power, which will expire in 30s */
488 ComboAddress
dr1Content("2001:DB8::1");
490 dr1
.d_type
= QType::AAAA
;
491 dr1
.d_class
= QClass::IN
;
492 dr1
.d_content
= std::make_shared
<AAAARecordContent
>(dr1Content
);
493 dr1
.d_ttl
= static_cast<uint32_t>(ttd
);
494 dr1
.d_place
= DNSResourceRecord::ANSWER
;
496 /* entry for power1, which will expire in 30s too */
498 ComboAddress
dr2Content("2001:DB8::2");
500 dr2
.d_type
= QType::AAAA
;
501 dr2
.d_class
= QClass::IN
;
502 dr2
.d_content
= std::make_shared
<AAAARecordContent
>(dr2Content
);
503 dr2
.d_ttl
= static_cast<uint32_t>(ttd
);
504 dr2
.d_place
= DNSResourceRecord::ANSWER
;
506 /* insert both entries */
507 records
.push_back(dr1
);
508 MRC
.replace(now
, power1
, QType(dr1
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
510 records
.push_back(dr2
);
511 MRC
.replace(now
, power2
, QType(dr2
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
513 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
515 /* the one for power2 having been inserted
516 more recently should be removed last */
517 /* we ask that only entry remains in the cache */
519 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
521 /* the remaining entry should be power2 */
522 BOOST_CHECK_EQUAL(MRC
.get(now
, power2
, QType(dr2
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), ttd
- now
);
523 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
524 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
525 /* check that power1 is gone */
526 BOOST_CHECK_EQUAL(MRC
.get(now
, power1
, QType(dr1
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), -1);
528 /* clear everything up */
529 MRC
.doWipeCache(DNSName("."), true);
530 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
533 /* insert both entries back */
534 records
.push_back(dr1
);
535 MRC
.replace(now
, power1
, QType(dr1
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
537 records
.push_back(dr2
);
538 MRC
.replace(now
, power2
, QType(dr2
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
540 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
542 /* replace the entry for power1 */
543 records
.push_back(dr1
);
544 MRC
.replace(now
, power1
, QType(dr1
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
546 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
548 /* the replaced entry for power1 should have been moved
549 to the back of the expunge queue, so power2 should be at the front
550 and should this time be removed first */
551 /* we ask that only entry remains in the cache */
553 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
555 /* the remaining entry should be power1 */
556 BOOST_CHECK_EQUAL(MRC
.get(now
, power1
, QType(dr1
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), ttd
- now
);
557 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
558 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
559 /* check that power2 is gone */
560 BOOST_CHECK_EQUAL(MRC
.get(now
, power2
, QType(dr2
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), -1);
562 /* clear everything up */
563 MRC
.doWipeCache(DNSName("."), true);
564 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
567 /* insert both entries back */
568 records
.push_back(dr1
);
569 MRC
.replace(now
, power1
, QType(dr1
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
571 records
.push_back(dr2
);
572 MRC
.replace(now
, power2
, QType(dr2
.d_type
), records
, signatures
, authRecs
, true, boost::none
);
574 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
576 /* get a hit for power1 */
577 BOOST_CHECK_EQUAL(MRC
.get(now
, power1
, QType(dr1
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), ttd
- now
);
578 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
579 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
581 /* the entry for power1 should have been moved to the back of the expunge queue
582 due to the hit, so power2 should be at the front and should this time be removed first */
583 /* we ask that only entry remains in the cache */
585 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
587 /* the remaining entry should be power1 */
588 BOOST_CHECK_EQUAL(MRC
.get(now
, power1
, QType(dr1
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), ttd
- now
);
589 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
590 BOOST_CHECK_EQUAL(getRR
<AAAARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
591 /* check that power2 is gone */
592 BOOST_CHECK_EQUAL(MRC
.get(now
, power2
, QType(dr2
.d_type
), false, &retrieved
, who
, boost::none
, nullptr), -1);
595 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
597 /* add a lot of netmask-specific entries */
598 for (size_t i
= 0; i
<= 255; i
++) {
602 ComboAddress
r1Content("192.0.2." + std::to_string(i
));
604 r1
.d_type
= QType::A
;
605 r1
.d_class
= QClass::IN
;
606 r1
.d_content
= std::make_shared
<ARecordContent
>(r1Content
);
607 r1
.d_ttl
= static_cast<uint32_t>(ttd
);
608 r1
.d_place
= DNSResourceRecord::ANSWER
;
609 records
.push_back(r1
);
611 MRC
.replace(now
, power1
, QType(QType::A
), records
, signatures
, authRecs
, true, Netmask(r1Content
, 32));
614 BOOST_CHECK_EQUAL(MRC
.size(), 256U);
615 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
617 /* remove a bit less than half of them */
620 BOOST_CHECK_EQUAL(MRC
.size(), keep
);
621 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
623 /* check that we can still retrieve the remaining ones */
625 for (size_t i
= 0; i
<= 255; i
++) {
626 ComboAddress
whoLoop("192.0.2." + std::to_string(i
));
628 auto ret
= MRC
.get(now
, power1
, QType(QType::A
), false, &retrieved
, whoLoop
);
630 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
631 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), whoLoop
.toString());
635 BOOST_REQUIRE_EQUAL(ret
, -1);
636 BOOST_REQUIRE_EQUAL(retrieved
.size(), 0U);
640 BOOST_CHECK_EQUAL(found
, keep
);
642 /* remove the rest */
644 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
645 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
648 BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex
)
650 MemRecursorCache
MRC(1);
652 const DNSName
power("powerdns.com.");
653 std::vector
<DNSRecord
> records
;
654 std::vector
<std::shared_ptr
<DNSRecord
>> authRecords
;
655 std::vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
656 time_t now
= time(nullptr);
657 std::vector
<DNSRecord
> retrieved
;
658 ComboAddress
who("192.0.2.1");
661 time_t ttd
= now
+ ttl
;
663 ComboAddress
dr1Content("192.0.2.255");
665 dr1
.d_type
= QType::A
;
666 dr1
.d_class
= QClass::IN
;
667 dr1
.d_content
= std::make_shared
<ARecordContent
>(dr1Content
);
668 dr1
.d_ttl
= static_cast<uint32_t>(ttd
);
669 dr1
.d_place
= DNSResourceRecord::ANSWER
;
672 ComboAddress
dr2Content("192.0.2.127");
674 dr2
.d_type
= QType::A
;
675 dr2
.d_class
= QClass::IN
;
676 dr2
.d_content
= std::make_shared
<ARecordContent
>(dr2Content
);
677 dr2
.d_ttl
= static_cast<uint32_t>(now
+ 5);
678 dr2
.d_place
= DNSResourceRecord::ANSWER
;
680 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
681 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
683 /* no entry in the ECS index, no non-specific entry either */
684 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, who
), -1);
686 /* insert a non-specific entry */
687 records
.push_back(dr1
);
688 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::none
);
690 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
691 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
693 /* retrieve the non-specific entry */
694 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, who
), ttd
- now
);
695 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
696 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
698 /* wipe everything */
700 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
701 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
703 /* insert a specific entry */
704 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/31"));
706 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
707 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
709 /* there is an ECS index for that entry but no match, and no non-specific entry */
710 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.4")), -1);
711 BOOST_REQUIRE_EQUAL(retrieved
.size(), 0U);
713 /* there is an ECS index for that entry and we get a match */
714 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.1")), ttd
- now
);
715 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
716 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
718 /* there is an ECS index for that entry and we get a match,
719 but it has expired. No other match, no non-specific entry */
720 BOOST_CHECK_EQUAL(MRC
.get(now
+ ttl
+ 1, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.1")), -1);
721 BOOST_REQUIRE_EQUAL(retrieved
.size(), 0U);
723 /* The ECS index should now be empty, but the cache entry has not been expunged yet */
724 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
725 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
727 /* add back the entry while it still exists in the cache but has been removed from the ECS index.
728 It should be added back to the ECS index, and we should be able to retrieve it */
729 MRC
.replace(now
+ ttl
+ 1, power
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/31"));
730 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
731 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
732 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.1")), ttd
- now
);
733 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
734 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
736 /* wipe everything */
738 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
739 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
741 /* insert a specific entry */
742 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/24"));
744 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
745 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
747 /* insert a slightly more specific one, but expiring sooner */
749 records
.push_back(dr2
);
750 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/26"));
752 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
753 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
755 /* check that we get the most specific one as long as it's still valid */
756 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.1")), 5);
757 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
758 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
760 /* there is an ECS index for that entry and we get a match,
762 The second ECS is a match too, and is valid. */
763 BOOST_CHECK_EQUAL(MRC
.get(now
+ 5 + 1, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.1")), (ttd
- (now
+ 5 + 1)));
764 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
765 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
767 /* The ECS index should not be empty */
768 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
769 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
771 /* wipe everything */
773 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
774 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
776 /* insert a non-specific entry */
778 records
.push_back(dr1
);
779 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, boost::none
);
781 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
782 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
784 /* insert a subnet-specific entry */
786 records
.push_back(dr2
);
787 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.42/32"));
789 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
790 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
792 /* there is an ECS index for that entry and it doesn't match. No other match, but we have a non-specific entry */
793 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.255")), ttd
- now
);
794 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
795 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
797 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
798 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
800 /* wipe everything */
802 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
803 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
806 BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe
)
808 MemRecursorCache MRC
;
810 const DNSName
power("powerdns.com.");
811 std::vector
<DNSRecord
> records
;
812 std::vector
<std::shared_ptr
<DNSRecord
>> authRecords
;
813 std::vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
814 time_t now
= time(nullptr);
815 std::vector
<DNSRecord
> retrieved
;
816 ComboAddress
who("192.0.2.1");
819 time_t ttd
= now
+ ttl
;
821 ComboAddress
dr1Content("192.0.2.255");
823 dr1
.d_type
= QType::A
;
824 dr1
.d_class
= QClass::IN
;
825 dr1
.d_content
= std::make_shared
<ARecordContent
>(dr1Content
);
826 dr1
.d_ttl
= static_cast<uint32_t>(ttd
);
827 dr1
.d_place
= DNSResourceRecord::ANSWER
;
829 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
830 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
832 /* no entry in the ECS index, no non-specific entry either */
833 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, who
), -1);
835 /* insert a specific entry */
836 records
.push_back(dr1
);
837 MRC
.replace(now
, power
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/31"));
839 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
840 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
842 /* insert two sub-domains entries */
843 DNSName
sub1("a.powerdns.com.");
846 records
.push_back(dr1
);
847 MRC
.replace(now
, sub1
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/31"));
849 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
850 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 2U);
852 DNSName
sub2("z.powerdns.com.");
855 records
.push_back(dr1
);
856 MRC
.replace(now
, sub2
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/31"));
858 BOOST_CHECK_EQUAL(MRC
.size(), 3U);
859 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 3U);
861 /* insert two entries for different domains */
862 DNSName
other1("b\bpowerdns.com.");
865 records
.push_back(dr1
);
866 MRC
.replace(now
, other1
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/31"));
868 BOOST_CHECK_EQUAL(MRC
.size(), 4U);
869 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 4U);
871 DNSName
other2("c\bpowerdns.com.");
874 records
.push_back(dr1
);
875 MRC
.replace(now
, other2
, QType(QType::A
), records
, signatures
, authRecords
, true, Netmask("192.0.2.0/31"));
877 BOOST_CHECK_EQUAL(MRC
.size(), 5U);
878 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 5U);
880 /* wipe everything under the powerdns.com domain */
881 BOOST_CHECK_EQUAL(MRC
.doWipeCache(power
, true), 3U);
882 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
883 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 2U);
885 /* now wipe the other domains too */
886 BOOST_CHECK_EQUAL(MRC
.doWipeCache(other1
, true), 1U);
887 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
888 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 1U);
890 BOOST_CHECK_EQUAL(MRC
.doWipeCache(other2
, true), 1U);
891 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
892 BOOST_CHECK_EQUAL(MRC
.ecsIndexSize(), 0U);
895 BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged
)
897 MemRecursorCache MRC
;
899 std::vector
<std::shared_ptr
<DNSRecord
>> authRecords
;
900 std::vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
901 time_t now
= time(nullptr);
902 time_t ttd
= now
+ 30;
904 DNSName
power("powerdns.com.");
906 ComboAddress
dr0Content("192.0.2.40");
908 dr0
.d_type
= QType::A
;
909 dr0
.d_class
= QClass::IN
;
910 dr0
.d_content
= std::make_shared
<ARecordContent
>(dr0Content
);
911 dr0
.d_ttl
= static_cast<uint32_t>(ttd
);
912 dr0
.d_place
= DNSResourceRecord::ANSWER
;
913 std::vector
<DNSRecord
> rset0
;
914 rset0
.push_back(dr0
);
917 ComboAddress
dr0taggedContent("192.0.2.100");
918 dr0tagged
.d_name
= power
;
919 dr0tagged
.d_type
= QType::A
;
920 dr0tagged
.d_class
= QClass::IN
;
921 dr0tagged
.d_content
= std::make_shared
<ARecordContent
>(dr0taggedContent
);
922 dr0tagged
.d_ttl
= static_cast<uint32_t>(ttd
);
923 dr0tagged
.d_place
= DNSResourceRecord::ANSWER
;
924 std::vector
<DNSRecord
> rset0tagged
;
925 rset0tagged
.push_back(dr0tagged
);
927 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
928 // An entry without edns subnet gets stored without tag as well
929 MRC
.replace(ttd
, DNSName("hello"), QType(QType::A
), rset0
, signatures
, authRecords
, true, boost::none
, boost::none
);
930 MRC
.replace(ttd
, DNSName("hello"), QType(QType::A
), rset0
, signatures
, authRecords
, true, boost::none
, string("mytag"));
931 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
932 BOOST_CHECK_EQUAL(MRC
.doWipeCache(DNSName("hello"), false, QType::A
), 1U);
933 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
934 BOOST_CHECK_EQUAL(MRC
.bytes(), 0U);
937 ComboAddress
who("192.0.2.1");
939 uint64_t counter
= 0;
941 for (counter
= 0; counter
< 100; ++counter
) {
942 DNSName a
= DNSName("hello ") + DNSName(std::to_string(counter
));
943 BOOST_CHECK_EQUAL(DNSName(a
.toString()), a
);
945 MRC
.replace(now
, a
, QType(QType::A
), rset0
, signatures
, authRecords
, true, boost::none
, string("mytagA"));
946 MRC
.replace(now
, a
, QType(QType::A
), rset0
, signatures
, authRecords
, true, boost::none
, string("mytagB"));
947 // After this, we have untagged entries, since no address was specified for both replace calls
950 BOOST_CHECK_EQUAL(MRC
.size(), counter
);
952 std::vector
<DNSRecord
> retrieved
;
954 int64_t expected
= counter
;
956 for (counter
= 0; counter
< 110; counter
++) {
957 if (MRC
.get(now
, DNSName("hello ") + DNSName(std::to_string(counter
)), QType(QType::A
), false, &retrieved
, nobody
, boost::none
) > 0) {
959 BOOST_CHECK_EQUAL(retrieved
.size(), rset0
.size());
960 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0Content
.toString());
963 BOOST_CHECK_EQUAL(matches
, expected
);
966 for (counter
= 0; counter
< 110; ++counter
) {
967 if (MRC
.get(now
, DNSName("hello ") + DNSName(std::to_string(counter
)), QType(QType::A
), false, &retrieved
, who
, string("mytagB")) > 0) {
969 BOOST_CHECK_EQUAL(retrieved
.size(), rset0
.size());
970 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0Content
.toString());
973 BOOST_CHECK_EQUAL(matches
, expected
);
976 for (counter
= 0; counter
< 110; counter
++) {
977 if (MRC
.get(now
, DNSName("hello ") + DNSName(std::to_string(counter
)), QType(QType::A
), false, &retrieved
, who
, string("mytagX")) > 0) {
979 BOOST_CHECK_EQUAL(retrieved
.size(), rset0
.size());
980 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0Content
.toString());
983 BOOST_CHECK_EQUAL(matches
, expected
);
985 // Now insert some tagged entries
986 for (counter
= 0; counter
< 50; ++counter
) {
987 DNSName a
= DNSName("hello ") + DNSName(std::to_string(counter
));
988 MRC
.replace(now
, a
, QType(QType::A
), rset0tagged
, signatures
, authRecords
, true, boost::optional
<Netmask
>("128.0.0.0/8"), string("mytagA"));
990 BOOST_CHECK_EQUAL(MRC
.size(), 150U);
993 for (counter
= 0; counter
< 110; counter
++) {
994 if (MRC
.get(now
, DNSName("hello ") + DNSName(std::to_string(counter
)), QType(QType::A
), false, &retrieved
, nobody
, boost::none
) > 0) {
996 BOOST_CHECK_EQUAL(retrieved
.size(), rset0
.size());
997 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0Content
.toString());
1000 BOOST_CHECK_EQUAL(matches
, 100U);
1003 for (counter
= 0; counter
< 110; ++counter
) {
1004 if (MRC
.get(now
, DNSName("hello ") + DNSName(std::to_string(counter
)), QType(QType::A
), false, &retrieved
, nobody
, string("mytagA")) > 0) {
1007 BOOST_CHECK_EQUAL(retrieved
.size(), rset0tagged
.size());
1008 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0taggedContent
.toString());
1011 BOOST_CHECK_EQUAL(retrieved
.size(), rset0
.size());
1012 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0Content
.toString());
1016 BOOST_CHECK_EQUAL(matches
, 100U);
1019 for (counter
= 0; counter
< 110; counter
++) {
1020 if (MRC
.get(now
, DNSName("hello ") + DNSName(std::to_string(counter
)), QType(QType::A
), false, &retrieved
, nobody
, string("mytagX")) > 0) {
1022 BOOST_CHECK_EQUAL(retrieved
.size(), rset0
.size());
1023 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr0Content
.toString());
1026 BOOST_CHECK_EQUAL(matches
, 100U);
1028 MRC
.doWipeCache(DNSName("."), true);
1029 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
1032 ComboAddress
dr1Content("192.0.2.41");
1034 dr1
.d_type
= QType::A
;
1035 dr1
.d_class
= QClass::IN
;
1036 dr1
.d_content
= std::make_shared
<ARecordContent
>(dr1Content
);
1037 dr1
.d_ttl
= static_cast<uint32_t>(ttd
);
1038 dr1
.d_place
= DNSResourceRecord::ANSWER
;
1039 std::vector
<DNSRecord
> rset1
;
1040 rset1
.push_back(dr1
);
1043 ComboAddress
dr2Content("192.0.2.42");
1045 dr2
.d_type
= QType::A
;
1046 dr2
.d_class
= QClass::IN
;
1047 dr2
.d_content
= std::make_shared
<ARecordContent
>(dr2Content
);
1048 dr2
.d_ttl
= static_cast<uint32_t>(ttd
);
1049 dr2
.d_place
= DNSResourceRecord::ANSWER
;
1050 std::vector
<DNSRecord
> rset2
;
1051 rset2
.push_back(dr2
);
1054 ComboAddress
dr3Content("192.0.2.43");
1056 dr3
.d_type
= QType::A
;
1057 dr3
.d_class
= QClass::IN
;
1058 dr3
.d_content
= std::make_shared
<ARecordContent
>(dr3Content
);
1059 dr3
.d_ttl
= static_cast<uint32_t>(ttd
);
1060 dr3
.d_place
= DNSResourceRecord::ANSWER
;
1061 std::vector
<DNSRecord
> rset3
;
1062 rset3
.push_back(dr3
);
1064 // insert a tagged entry
1065 MRC
.replace(now
, power
, QType(QType::A
), rset1
, signatures
, authRecords
, true, boost::optional
<Netmask
>("192.0.2.0/24"), string("mytag"));
1066 BOOST_CHECK_EQUAL(MRC
.size(), 1U);
1068 // tagged specific should be returned for a matching tag
1069 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.2"), string("mytag")), (ttd
- now
));
1070 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
1071 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
1073 // tag specific should not be returned for a different tag
1074 BOOST_CHECK_LT(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.2"), string("othertag")), 0);
1075 BOOST_CHECK_EQUAL(retrieved
.size(), 0U);
1077 // insert a new entry without tag
1078 MRC
.replace(now
, power
, QType(QType::A
), rset2
, signatures
, authRecords
, true, boost::optional
<Netmask
>("192.0.3.0/24"), boost::none
);
1079 BOOST_CHECK_EQUAL(MRC
.size(), 2U);
1081 // tagged specific should be returned for a matching tag
1082 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.2"), string("mytag")), (ttd
- now
));
1083 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
1084 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
1086 // if no tag given nothing should be retrieved if address doesn't match
1087 BOOST_CHECK_LT(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("127.0.0.1"), boost::none
), 0);
1088 BOOST_REQUIRE_EQUAL(retrieved
.size(), 0U);
1090 // if no tag given and no-non-tagged entries matches nothing shoudl be returned
1091 BOOST_CHECK_LT(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.2"), boost::none
), 0);
1092 BOOST_REQUIRE_EQUAL(retrieved
.size(), 0U);
1094 // Insert untagged entry with no netmask
1095 MRC
.replace(now
, power
, QType(QType::A
), rset3
, signatures
, authRecords
, true, boost::none
, boost::none
);
1096 BOOST_CHECK_EQUAL(MRC
.size(), 3U);
1098 // Retrieval with no address and no tag should get that one
1099 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress(), boost::none
), (ttd
- now
));
1100 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr3Content
.toString());
1102 // If no tag given match non-tagged entry
1103 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.2"), boost::none
), (ttd
- now
));
1104 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
1105 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr3Content
.toString());
1107 // If no tag given we should be able to retrieve the netmask specific record
1108 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.3.1"), boost::none
), (ttd
- now
));
1109 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
1110 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr2Content
.toString());
1112 // tagged specific should still be returned for a matching tag, address is not used
1113 BOOST_CHECK_EQUAL(MRC
.get(now
, power
, QType(QType::A
), false, &retrieved
, ComboAddress("192.0.2.2"), string("mytag")), (ttd
- now
));
1114 BOOST_REQUIRE_EQUAL(retrieved
.size(), 1U);
1115 BOOST_CHECK_EQUAL(getRR
<ARecordContent
>(retrieved
.at(0))->getCA().toString(), dr1Content
.toString());
1117 // remove everything
1118 MRC
.doWipeCache(DNSName("."), true);
1119 BOOST_CHECK_EQUAL(MRC
.size(), 0U);
1121 catch (const PDNSException
& e
) {
1122 cerr
<< "Had error: " << e
.reason
<< endl
;
1127 BOOST_AUTO_TEST_SUITE_END()