]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc2.cc
5728011378ece3ca40cfae571968d68c14299962
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc2.cc
1 #define BOOST_TEST_DYN_LINK
2 #include <boost/test/unit_test.hpp>
3
4 #include "test-syncres_cc.hh"
5
6 BOOST_AUTO_TEST_SUITE(syncres_cc2)
7
8 BOOST_AUTO_TEST_CASE(test_referral_depth)
9 {
10 std::unique_ptr<SyncRes> sr;
11 initSR(sr);
12
13 primeHints();
14
15 size_t queries = 0;
16 const DNSName target("www.powerdns.com.");
17
18 sr->setAsyncCallback([target, &queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
19 queries++;
20
21 if (isRootServer(ip)) {
22 setLWResult(res, 0, false, false, true);
23
24 if (domain == DNSName("www.powerdns.com.")) {
25 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
26 }
27 else if (domain == DNSName("ns.powerdns.com.")) {
28 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
29 }
30 else if (domain == DNSName("ns1.powerdns.org.")) {
31 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
32 }
33 else if (domain == DNSName("ns2.powerdns.org.")) {
34 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
35 }
36 else if (domain == DNSName("ns3.powerdns.org.")) {
37 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
38 }
39 else if (domain == DNSName("ns4.powerdns.org.")) {
40 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
41 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
42 }
43
44 return 1;
45 }
46 else if (ip == ComboAddress("192.0.2.1:53")) {
47
48 setLWResult(res, 0, true, false, false);
49 addRecordToLW(res, domain, QType::A, "192.0.2.2");
50 return 1;
51 }
52
53 return 0;
54 });
55
56 /* Set the maximum depth low */
57 SyncRes::s_maxdepth = 10;
58
59 try {
60 vector<DNSRecord> ret;
61 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
62 BOOST_CHECK(false);
63 }
64 catch (const ImmediateServFailException& e) {
65 }
66 }
67
68 BOOST_AUTO_TEST_CASE(test_cname_qperq)
69 {
70 std::unique_ptr<SyncRes> sr;
71 initSR(sr);
72
73 primeHints();
74
75 size_t queries = 0;
76 const DNSName target("cname.powerdns.com.");
77
78 sr->setAsyncCallback([target, &queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
79 queries++;
80
81 if (isRootServer(ip)) {
82
83 setLWResult(res, 0, false, false, true);
84 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
85 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
86 return 1;
87 }
88 else if (ip == ComboAddress("192.0.2.1:53")) {
89
90 setLWResult(res, 0, true, false, false);
91 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
92 return 1;
93 }
94
95 return 0;
96 });
97
98 /* Set the maximum number of questions very low */
99 SyncRes::s_maxqperq = 5;
100
101 try {
102 vector<DNSRecord> ret;
103 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
104 BOOST_CHECK(false);
105 }
106 catch (const ImmediateServFailException& e) {
107 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
108 }
109 }
110
111 BOOST_AUTO_TEST_CASE(test_throttled_server)
112 {
113 std::unique_ptr<SyncRes> sr;
114 initSR(sr);
115
116 primeHints();
117
118 const DNSName target("throttled.powerdns.com.");
119 const ComboAddress ns("192.0.2.1:53");
120 size_t queriesToNS = 0;
121
122 sr->setAsyncCallback([target, ns, &queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
123 if (isRootServer(ip)) {
124
125 setLWResult(res, 0, false, false, true);
126 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
127 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
128 return 1;
129 }
130 else if (ip == ns) {
131
132 queriesToNS++;
133
134 setLWResult(res, 0, true, false, false);
135 addRecordToLW(res, domain, QType::A, "192.0.2.2");
136
137 return 1;
138 }
139
140 return 0;
141 });
142
143 /* mark ns as down */
144 time_t now = sr->getNow().tv_sec;
145 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000);
146
147 vector<DNSRecord> ret;
148 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
149 BOOST_CHECK_EQUAL(res, RCode::ServFail);
150 BOOST_CHECK_EQUAL(ret.size(), 0U);
151 /* we should not have sent any queries to ns */
152 BOOST_CHECK_EQUAL(queriesToNS, 0U);
153 }
154
155 BOOST_AUTO_TEST_CASE(test_throttled_server_count)
156 {
157 std::unique_ptr<SyncRes> sr;
158 initSR(sr);
159
160 primeHints();
161
162 const ComboAddress ns("192.0.2.1:53");
163
164 const size_t blocks = 10;
165 /* mark ns as down for 'blocks' queries */
166 time_t now = sr->getNow().tv_sec;
167 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks);
168
169 for (size_t idx = 0; idx < blocks; idx++) {
170 BOOST_CHECK(SyncRes::isThrottled(now, ns));
171 }
172
173 /* we have been throttled 'blocks' times, we should not be throttled anymore */
174 BOOST_CHECK(!SyncRes::isThrottled(now, ns));
175 }
176
177 BOOST_AUTO_TEST_CASE(test_throttled_server_time)
178 {
179 std::unique_ptr<SyncRes> sr;
180 initSR(sr);
181
182 primeHints();
183
184 const ComboAddress ns("192.0.2.1:53");
185
186 const size_t seconds = 1;
187 /* mark ns as down for 'seconds' seconds */
188 time_t now = sr->getNow().tv_sec;
189 SyncRes::doThrottle(now, ns, seconds, 10000);
190
191 BOOST_CHECK(SyncRes::isThrottled(now, ns));
192
193 /* we should not be throttled anymore */
194 BOOST_CHECK(!SyncRes::isThrottled(now + 2, ns));
195 }
196
197 BOOST_AUTO_TEST_CASE(test_dont_query_server)
198 {
199 std::unique_ptr<SyncRes> sr;
200 initSR(sr);
201
202 primeHints();
203
204 const DNSName target("throttled.powerdns.com.");
205 const ComboAddress ns("192.0.2.1:53");
206 size_t queriesToNS = 0;
207
208 sr->setAsyncCallback([target, ns, &queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
209 if (isRootServer(ip)) {
210
211 setLWResult(res, 0, false, false, true);
212 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
213 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
214 return 1;
215 }
216 else if (ip == ns) {
217
218 queriesToNS++;
219
220 setLWResult(res, 0, true, false, false);
221 addRecordToLW(res, domain, QType::A, "192.0.2.2");
222
223 return 1;
224 }
225
226 return 0;
227 });
228
229 /* prevent querying this NS */
230 SyncRes::addDontQuery(Netmask(ns));
231
232 vector<DNSRecord> ret;
233 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
234 BOOST_CHECK_EQUAL(res, RCode::ServFail);
235 BOOST_CHECK_EQUAL(ret.size(), 0U);
236 /* we should not have sent any queries to ns */
237 BOOST_CHECK_EQUAL(queriesToNS, 0U);
238 }
239
240 BOOST_AUTO_TEST_CASE(test_root_nx_trust)
241 {
242 std::unique_ptr<SyncRes> sr;
243 initSR(sr);
244
245 primeHints();
246
247 const DNSName target1("powerdns.com.");
248 const DNSName target2("notpowerdns.com.");
249 const ComboAddress ns("192.0.2.1:53");
250 size_t queriesCount = 0;
251
252 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
253 queriesCount++;
254
255 if (isRootServer(ip)) {
256
257 if (domain == target1) {
258 setLWResult(res, RCode::NXDomain, true, false, true);
259 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
260 }
261 else {
262 setLWResult(res, 0, true, false, true);
263 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
264 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
265 }
266
267 return 1;
268 }
269 else if (ip == ns) {
270
271 setLWResult(res, 0, true, false, false);
272 addRecordToLW(res, domain, QType::A, "192.0.2.2");
273
274 return 1;
275 }
276
277 return 0;
278 });
279
280 SyncRes::s_maxnegttl = 3600;
281
282 vector<DNSRecord> ret;
283 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
284 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
285 BOOST_CHECK_EQUAL(ret.size(), 1U);
286 /* one for target1 and one for the entire TLD */
287 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
288
289 ret.clear();
290 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
291 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
292 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
293 BOOST_CHECK_LE(ret[0].d_ttl, SyncRes::s_maxnegttl);
294 /* one for target1 and one for the entire TLD */
295 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
296
297 /* we should have sent only one query */
298 BOOST_CHECK_EQUAL(queriesCount, 1U);
299 }
300
301 BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific)
302 {
303 std::unique_ptr<SyncRes> sr;
304 initSR();
305 initSR(sr, true, false);
306
307 primeHints();
308
309 const DNSName target1("powerdns.com.");
310 const DNSName target2("notpowerdns.com.");
311 const ComboAddress ns("192.0.2.1:53");
312 size_t queriesCount = 0;
313
314 /* This time the root denies target1 with a "com." SOA instead of a "." one.
315 We should add target1 to the negcache, but not "com.". */
316
317 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
318 queriesCount++;
319
320 if (isRootServer(ip)) {
321
322 if (domain == target1) {
323 setLWResult(res, RCode::NXDomain, true, false, true);
324 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
325 }
326 else {
327 setLWResult(res, 0, true, false, true);
328 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
329 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
330 }
331
332 return 1;
333 }
334 else if (ip == ns) {
335
336 setLWResult(res, 0, true, false, false);
337 addRecordToLW(res, domain, QType::A, "192.0.2.2");
338
339 return 1;
340 }
341
342 return 0;
343 });
344
345 vector<DNSRecord> ret;
346 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
347 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
348 BOOST_CHECK_EQUAL(ret.size(), 1U);
349
350 /* even with root-nx-trust on and a NX answer from the root,
351 we should not have cached the entire TLD this time. */
352 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
353
354 ret.clear();
355 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
356 BOOST_CHECK_EQUAL(res, RCode::NoError);
357 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
358 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
359 BOOST_REQUIRE(ret[0].d_type == QType::A);
360 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
361
362 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
363
364 BOOST_CHECK_EQUAL(queriesCount, 3U);
365 }
366
367 BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust)
368 {
369 std::unique_ptr<SyncRes> sr;
370 initSR(sr);
371
372 primeHints();
373
374 const DNSName target1("powerdns.com.");
375 const DNSName target2("notpowerdns.com.");
376 const ComboAddress ns("192.0.2.1:53");
377 size_t queriesCount = 0;
378
379 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
380 queriesCount++;
381
382 if (isRootServer(ip)) {
383
384 if (domain == target1) {
385 setLWResult(res, RCode::NXDomain, true, false, true);
386 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
387 }
388 else {
389 setLWResult(res, 0, true, false, true);
390 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
391 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
392 }
393
394 return 1;
395 }
396 else if (ip == ns) {
397
398 setLWResult(res, 0, true, false, false);
399 addRecordToLW(res, domain, QType::A, "192.0.2.2");
400
401 return 1;
402 }
403
404 return 0;
405 });
406
407 SyncRes::s_rootNXTrust = false;
408
409 vector<DNSRecord> ret;
410 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
411 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
412 BOOST_CHECK_EQUAL(ret.size(), 1U);
413 /* one for target1 */
414 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
415
416 ret.clear();
417 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
418 BOOST_CHECK_EQUAL(res, RCode::NoError);
419 BOOST_CHECK_EQUAL(ret.size(), 1U);
420 /* one for target1 */
421 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
422
423 /* we should have sent three queries */
424 BOOST_CHECK_EQUAL(queriesCount, 3U);
425 }
426
427 BOOST_AUTO_TEST_CASE(test_rfc8020_nothing_underneath)
428 {
429 std::unique_ptr<SyncRes> sr;
430 initSR(sr);
431 SyncRes::s_hardenNXD = SyncRes::HardenNXD::Yes;
432
433 primeHints();
434
435 const DNSName target1("www.powerdns.com."); // will be denied
436 const DNSName target2("foo.www.powerdns.com.");
437 const DNSName target3("bar.www.powerdns.com.");
438 const DNSName target4("quux.bar.www.powerdns.com.");
439 const ComboAddress ns("192.0.2.1:53");
440 size_t queriesCount = 0;
441
442 sr->setAsyncCallback([ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
443 queriesCount++;
444
445 if (isRootServer(ip)) {
446 setLWResult(res, 0, false, false, true);
447 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
448 addRecordToLW(res, "ns1.powerdns.com.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
449 return 1;
450 }
451 else if (ip == ns) {
452 setLWResult(res, RCode::NXDomain, true, false, false);
453 addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
454 return 1;
455 }
456 return 0;
457 });
458
459 vector<DNSRecord> ret;
460 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
461 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
462 BOOST_CHECK_EQUAL(ret.size(), 1U);
463 BOOST_CHECK_EQUAL(queriesCount, 2U);
464 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
465
466 ret.clear();
467 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
468 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
469 BOOST_CHECK_EQUAL(ret.size(), 1U);
470 BOOST_CHECK_EQUAL(queriesCount, 2U);
471 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
472
473 ret.clear();
474 res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
475 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
476 BOOST_CHECK_EQUAL(ret.size(), 1U);
477 BOOST_CHECK_EQUAL(queriesCount, 2U);
478 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
479
480 ret.clear();
481 res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
482 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
483 BOOST_CHECK_EQUAL(ret.size(), 1U);
484 BOOST_CHECK_EQUAL(queriesCount, 2U);
485 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
486
487 // Now test without RFC 8020 to see the cache and query count grow
488 SyncRes::s_hardenNXD = SyncRes::HardenNXD::No;
489
490 // Already cached
491 ret.clear();
492 res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
493 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
494 BOOST_CHECK_EQUAL(ret.size(), 1U);
495 BOOST_CHECK_EQUAL(queriesCount, 2U);
496 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
497
498 // New query
499 ret.clear();
500 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
501 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
502 BOOST_CHECK_EQUAL(ret.size(), 1U);
503 BOOST_CHECK_EQUAL(queriesCount, 3U);
504 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
505
506 ret.clear();
507 res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
508 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
509 BOOST_CHECK_EQUAL(ret.size(), 1U);
510 BOOST_CHECK_EQUAL(queriesCount, 4U);
511 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 3U);
512
513 ret.clear();
514 res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
515 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
516 BOOST_CHECK_EQUAL(ret.size(), 1U);
517 BOOST_CHECK_EQUAL(queriesCount, 5U);
518 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 4U);
519
520 // reset
521 SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC;
522 }
523
524 BOOST_AUTO_TEST_CASE(test_rfc8020_nothing_underneath_dnssec)
525 {
526 std::unique_ptr<SyncRes> sr;
527 initSR(sr, true);
528 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
529
530 primeHints();
531
532 const DNSName parent1("com.");
533 const DNSName parent2("powerdns.com.");
534 const DNSName target1("www.powerdns.com."); // will be denied
535 const DNSName target2("foo.www.powerdns.com.");
536 const DNSName target3("bar.www.powerdns.com.");
537 const DNSName target4("quux.bar.www.powerdns.com.");
538 const ComboAddress ns("192.0.2.1:53");
539
540 testkeysset_t keys;
541
542 auto luaconfsCopy = g_luaconfs.getCopy();
543 luaconfsCopy.dsAnchors.clear();
544 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
545 generateKeyMaterial(parent1, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
546 generateKeyMaterial(parent2, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
547 g_luaconfs.setState(luaconfsCopy);
548
549 size_t queriesCount = 0;
550
551 sr->setAsyncCallback([target1, target2, target3, target4, &queriesCount, keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
552 queriesCount++;
553
554 DNSName auth = domain;
555 if (domain == target1 || domain == target2 || domain == target3 || domain == target4) {
556 auth = DNSName("powerdns.com.");
557 }
558 if (type == QType::DS || type == QType::DNSKEY) {
559 if (type == QType::DS && (domain == target1 || domain == target2 || domain == target3 || domain == target4)) {
560 setLWResult(res, RCode::NXDomain, true, false, true);
561 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
562 addRRSIG(keys, res->d_records, auth, 300);
563 addNSECRecordToLW(DNSName("wwa.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records);
564 addRRSIG(keys, res->d_records, auth, 300);
565 return 1;
566 }
567 else {
568 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
569 }
570 }
571 else {
572 if (isRootServer(ip)) {
573 setLWResult(res, 0, false, false, true);
574 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
575 addDS(DNSName("com."), 300, res->d_records, keys);
576 addRRSIG(keys, res->d_records, DNSName("."), 300);
577 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
578 return 1;
579 }
580 else if (ip == ComboAddress("192.0.2.1:53")) {
581 if (domain == DNSName("com.")) {
582 setLWResult(res, 0, true, false, true);
583 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
584 addRRSIG(keys, res->d_records, domain, 300);
585 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
586 addRRSIG(keys, res->d_records, domain, 300);
587 }
588 else {
589 setLWResult(res, 0, false, false, true);
590 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
591 addDS(auth, 300, res->d_records, keys);
592 addRRSIG(keys, res->d_records, DNSName("com."), 300);
593 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
594 }
595 return 1;
596 }
597 else if (ip == ComboAddress("192.0.2.2:53")) {
598 if (type == QType::NS) {
599 setLWResult(res, 0, true, false, true);
600 if (domain == DNSName("powerdns.com.")) {
601 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
602 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
603 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
604 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
605 }
606 }
607 else {
608 setLWResult(res, RCode::NXDomain, true, false, true);
609 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
610 addRRSIG(keys, res->d_records, auth, 300);
611 addNSECRecordToLW(DNSName("wwa.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records);
612 addRRSIG(keys, res->d_records, auth, 300);
613 /* add wildcard denial */
614 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records);
615 addRRSIG(keys, res->d_records, auth, 300);
616 }
617 return 1;
618 }
619 }
620
621 return 0;
622 });
623
624 vector<DNSRecord> ret;
625 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
626 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
627 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
628 BOOST_CHECK_EQUAL(ret.size(), 6U);
629 BOOST_CHECK_EQUAL(queriesCount, 9U);
630 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
631
632 ret.clear();
633 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
634 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
635 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
636 BOOST_CHECK_EQUAL(ret.size(), 6U);
637 BOOST_CHECK_EQUAL(queriesCount, 9U);
638 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
639
640 ret.clear();
641 res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
642 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
643 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
644 BOOST_CHECK_EQUAL(ret.size(), 6U);
645 BOOST_CHECK_EQUAL(queriesCount, 9U);
646 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
647
648 ret.clear();
649 res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
650 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
651 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
652 BOOST_CHECK_EQUAL(ret.size(), 6U);
653 BOOST_CHECK_EQUAL(queriesCount, 9U);
654 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
655
656 // Now test without RFC 8020 to see the cache and query count grow
657 SyncRes::s_hardenNXD = SyncRes::HardenNXD::No;
658
659 // Already cached
660 ret.clear();
661 res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
662 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
663 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
664 BOOST_CHECK_EQUAL(ret.size(), 6U);
665 BOOST_CHECK_EQUAL(queriesCount, 9U);
666 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
667
668 // New query
669 ret.clear();
670 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
671 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
672 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
673 BOOST_CHECK_EQUAL(ret.size(), 6U);
674 BOOST_CHECK_EQUAL(queriesCount, 11U);
675 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
676
677 ret.clear();
678 res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
679 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
680 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
681 BOOST_CHECK_EQUAL(ret.size(), 6U);
682 BOOST_CHECK_EQUAL(queriesCount, 13U);
683 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 3U);
684
685 ret.clear();
686 res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
687 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
688 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
689 BOOST_CHECK_EQUAL(ret.size(), 6U);
690 BOOST_CHECK_EQUAL(queriesCount, 15U);
691 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 4U);
692
693 // reset
694 SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC;
695 }
696
697 BOOST_AUTO_TEST_CASE(test_rfc8020_nodata)
698 {
699 std::unique_ptr<SyncRes> sr;
700 initSR(sr);
701 SyncRes::s_hardenNXD = SyncRes::HardenNXD::Yes;
702
703 primeHints();
704
705 const DNSName target1("www.powerdns.com."); // TXT record will be denied
706 const DNSName target2("bar.www.powerdns.com."); // will be NXD, but the www. NODATA should not interfere with 8020 processing
707 const DNSName target3("quux.bar.www.powerdns.com."); // will be NXD, but will not yield a query
708 const ComboAddress ns("192.0.2.1:53");
709 size_t queriesCount = 0;
710
711 sr->setAsyncCallback([ns, target1, target2, target3, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
712 queriesCount++;
713
714 if (isRootServer(ip)) {
715 setLWResult(res, 0, false, false, true);
716 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
717 addRecordToLW(res, "ns1.powerdns.com.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
718 return 1;
719 }
720 else if (ip == ns) {
721 if (domain == target1) { // NODATA for TXT, NOERROR for A
722 if (type == QType::TXT) {
723 setLWResult(res, RCode::NoError, true);
724 addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
725 return 1;
726 }
727 if (type == QType::A) {
728 setLWResult(res, RCode::NoError, true);
729 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400);
730 return 1;
731 }
732 }
733 if (domain == target2 || domain == target3) {
734 setLWResult(res, RCode::NXDomain, true);
735 addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
736 return 1;
737 }
738 }
739 return 0;
740 });
741
742 vector<DNSRecord> ret;
743 int res = sr->beginResolve(target1, QType(QType::TXT), QClass::IN, ret);
744 BOOST_CHECK_EQUAL(res, RCode::NoError);
745 BOOST_CHECK_EQUAL(ret.size(), 1U);
746 BOOST_CHECK_EQUAL(queriesCount, 2U);
747 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
748
749 ret.clear();
750 res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
751 BOOST_CHECK_EQUAL(res, RCode::NoError);
752 BOOST_CHECK_EQUAL(ret.size(), 1U);
753 BOOST_CHECK_EQUAL(queriesCount, 3U);
754 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
755
756 ret.clear();
757 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
758 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
759 BOOST_CHECK_EQUAL(ret.size(), 1U);
760 BOOST_CHECK_EQUAL(queriesCount, 4U);
761 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
762
763 ret.clear();
764 res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
765 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
766 BOOST_CHECK_EQUAL(ret.size(), 1U);
767 BOOST_CHECK_EQUAL(queriesCount, 4U);
768 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
769 }
770
771 BOOST_AUTO_TEST_CASE(test_rfc8020_nodata_bis)
772 {
773 std::unique_ptr<SyncRes> sr;
774 initSR(sr);
775 SyncRes::s_hardenNXD = SyncRes::HardenNXD::Yes;
776
777 primeHints();
778
779 const DNSName target1("www.powerdns.com."); // TXT record will be denied
780 const DNSName target2("bar.www.powerdns.com."); // will be NXD, but the www. NODATA should not interfere with 8020 processing
781 const DNSName target3("quux.bar.www.powerdns.com."); // will be NXD, but will not yield a query
782 const ComboAddress ns("192.0.2.1:53");
783 size_t queriesCount = 0;
784
785 sr->setAsyncCallback([ns, target1, target2, target3, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
786 queriesCount++;
787
788 if (isRootServer(ip)) {
789 setLWResult(res, 0, false, false, true);
790 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
791 addRecordToLW(res, "ns1.powerdns.com.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
792 return 1;
793 }
794 else if (ip == ns) {
795 if (domain == target1) { // NODATA for TXT, NOERROR for A
796 if (type == QType::TXT) {
797 setLWResult(res, RCode::NoError, true);
798 addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
799 return 1;
800 }
801 if (type == QType::A) {
802 setLWResult(res, RCode::NoError, true);
803 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400);
804 return 1;
805 }
806 }
807 if (domain == target2 || domain == target3) {
808 setLWResult(res, RCode::NXDomain, true);
809 addRecordToLW(res, "powerdns.com.", QType::SOA, "ns1.powerdns.com. hostmaster.powerdns.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
810 return 1;
811 }
812 }
813 return 0;
814 });
815
816 vector<DNSRecord> ret;
817 int res = sr->beginResolve(target1, QType(QType::TXT), QClass::IN, ret);
818 BOOST_CHECK_EQUAL(res, RCode::NoError);
819 BOOST_CHECK_EQUAL(ret.size(), 1U);
820 BOOST_CHECK_EQUAL(queriesCount, 2U);
821 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
822
823 ret.clear();
824 res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
825 BOOST_CHECK_EQUAL(res, RCode::NoError);
826 BOOST_CHECK_EQUAL(ret.size(), 1U);
827 BOOST_CHECK_EQUAL(queriesCount, 3U);
828 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
829
830 ret.clear();
831 res = sr->beginResolve(target2, QType(QType::TXT), QClass::IN, ret);
832 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
833 BOOST_CHECK_EQUAL(ret.size(), 1U);
834 BOOST_CHECK_EQUAL(queriesCount, 4U);
835 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
836
837 ret.clear();
838 res = sr->beginResolve(target3, QType(QType::TXT), QClass::IN, ret);
839 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
840 BOOST_CHECK_EQUAL(ret.size(), 1U);
841 BOOST_CHECK_EQUAL(queriesCount, 4U);
842 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
843 }
844
845 BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response)
846 {
847 std::unique_ptr<SyncRes> sr;
848 initSR(sr);
849
850 primeHints();
851
852 const DNSName target("www.powerdns.com.");
853 const DNSName cnameTarget("cname.powerdns.com.");
854
855 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
856
857 EDNSSubnetOpts incomingECS;
858 incomingECS.source = Netmask("192.0.2.128/32");
859 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
860
861 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
862 BOOST_REQUIRE(srcmask);
863 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
864
865 if (isRootServer(ip)) {
866 setLWResult(res, 0, false, false, true);
867 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
868 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
869
870 srcmask = boost::none;
871
872 return 1;
873 }
874 else if (ip == ComboAddress("192.0.2.1:53")) {
875 if (domain == target) {
876 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
877 setLWResult(res, RCode::NXDomain, true, false, true);
878 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
879 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
880 }
881 else if (domain == cnameTarget) {
882 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
883 but we might if we still chase the CNAME. */
884 setLWResult(res, RCode::NXDomain, true, false, true);
885 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
886 }
887
888 return 1;
889 }
890
891 return 0;
892 });
893
894 vector<DNSRecord> ret;
895 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
896 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
897 BOOST_CHECK_EQUAL(ret.size(), 2U);
898 /* no negative cache entry because the response was variable */
899 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0U);
900 }
901
902 BOOST_AUTO_TEST_CASE(test_ecs_cache_limit_allowed)
903 {
904 std::unique_ptr<SyncRes> sr;
905 initSR(sr);
906
907 primeHints();
908
909 const DNSName target("www.powerdns.com.");
910
911 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
912
913 EDNSSubnetOpts incomingECS;
914 incomingECS.source = Netmask("192.0.2.128/32");
915 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
916 SyncRes::s_ecsipv4cachelimit = 24;
917
918 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
919 BOOST_REQUIRE(srcmask);
920 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
921
922 setLWResult(res, 0, true, false, true);
923 addRecordToLW(res, target, QType::A, "192.0.2.1");
924
925 return 1;
926 });
927
928 const time_t now = sr->getNow().tv_sec;
929 vector<DNSRecord> ret;
930 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
931 BOOST_CHECK_EQUAL(res, RCode::NoError);
932 BOOST_CHECK_EQUAL(ret.size(), 1U);
933
934 /* should have been cached */
935 const ComboAddress who("192.0.2.128");
936 vector<DNSRecord> cached;
937 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
938 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
939 }
940
941 BOOST_AUTO_TEST_CASE(test_ecs_cache_limit_no_ttl_limit_allowed)
942 {
943 std::unique_ptr<SyncRes> sr;
944 initSR(sr);
945
946 primeHints();
947
948 const DNSName target("www.powerdns.com.");
949
950 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
951
952 EDNSSubnetOpts incomingECS;
953 incomingECS.source = Netmask("192.0.2.128/32");
954 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
955 SyncRes::s_ecsipv4cachelimit = 16;
956
957 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
958 BOOST_REQUIRE(srcmask);
959 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
960
961 setLWResult(res, 0, true, false, true);
962 addRecordToLW(res, target, QType::A, "192.0.2.1");
963
964 return 1;
965 });
966
967 const time_t now = sr->getNow().tv_sec;
968 vector<DNSRecord> ret;
969 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
970 BOOST_CHECK_EQUAL(res, RCode::NoError);
971 BOOST_CHECK_EQUAL(ret.size(), 1U);
972
973 /* should have been cached because /24 is more specific than /16 but TTL limit is nof effective */
974 const ComboAddress who("192.0.2.128");
975 vector<DNSRecord> cached;
976 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
977 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
978 }
979
980 BOOST_AUTO_TEST_CASE(test_ecs_cache_ttllimit_allowed)
981 {
982 std::unique_ptr<SyncRes> sr;
983 initSR(sr);
984
985 primeHints();
986
987 const DNSName target("www.powerdns.com.");
988
989 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
990
991 EDNSSubnetOpts incomingECS;
992 incomingECS.source = Netmask("192.0.2.128/32");
993 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
994 SyncRes::s_ecscachelimitttl = 30;
995
996 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
997 BOOST_REQUIRE(srcmask);
998 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
999
1000 setLWResult(res, 0, true, false, true);
1001 addRecordToLW(res, target, QType::A, "192.0.2.1");
1002
1003 return 1;
1004 });
1005
1006 const time_t now = sr->getNow().tv_sec;
1007 vector<DNSRecord> ret;
1008 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1009 BOOST_CHECK_EQUAL(res, RCode::NoError);
1010 BOOST_CHECK_EQUAL(ret.size(), 1U);
1011
1012 /* should have been cached */
1013 const ComboAddress who("192.0.2.128");
1014 vector<DNSRecord> cached;
1015 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
1016 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1017 }
1018
1019 BOOST_AUTO_TEST_CASE(test_ecs_cache_ttllimit_and_scope_allowed)
1020 {
1021 std::unique_ptr<SyncRes> sr;
1022 initSR(sr);
1023
1024 primeHints();
1025
1026 const DNSName target("www.powerdns.com.");
1027
1028 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
1029
1030 EDNSSubnetOpts incomingECS;
1031 incomingECS.source = Netmask("192.0.2.128/32");
1032 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1033 SyncRes::s_ecscachelimitttl = 100;
1034 SyncRes::s_ecsipv4cachelimit = 24;
1035
1036 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1037 BOOST_REQUIRE(srcmask);
1038 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1039
1040 setLWResult(res, 0, true, false, true);
1041 addRecordToLW(res, target, QType::A, "192.0.2.1");
1042
1043 return 1;
1044 });
1045
1046 const time_t now = sr->getNow().tv_sec;
1047 vector<DNSRecord> ret;
1048 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1049 BOOST_CHECK_EQUAL(res, RCode::NoError);
1050 BOOST_CHECK_EQUAL(ret.size(), 1U);
1051
1052 /* should have been cached */
1053 const ComboAddress who("192.0.2.128");
1054 vector<DNSRecord> cached;
1055 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
1056 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1057 }
1058
1059 BOOST_AUTO_TEST_CASE(test_ecs_cache_ttllimit_notallowed)
1060 {
1061 std::unique_ptr<SyncRes> sr;
1062 initSR(sr);
1063
1064 primeHints();
1065
1066 const DNSName target("www.powerdns.com.");
1067
1068 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
1069
1070 EDNSSubnetOpts incomingECS;
1071 incomingECS.source = Netmask("192.0.2.128/32");
1072 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1073 SyncRes::s_ecscachelimitttl = 100;
1074 SyncRes::s_ecsipv4cachelimit = 16;
1075
1076 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1077 BOOST_REQUIRE(srcmask);
1078 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1079
1080 setLWResult(res, 0, true, false, true);
1081 addRecordToLW(res, target, QType::A, "192.0.2.1");
1082
1083 return 1;
1084 });
1085
1086 const time_t now = sr->getNow().tv_sec;
1087 vector<DNSRecord> ret;
1088 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1089 BOOST_CHECK_EQUAL(res, RCode::NoError);
1090 BOOST_CHECK_EQUAL(ret.size(), 1U);
1091
1092 /* should have NOT been cached because TTL of 60 is too small and /24 is more specific than /16 */
1093 const ComboAddress who("192.0.2.128");
1094 vector<DNSRecord> cached;
1095 BOOST_REQUIRE_LT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
1096 BOOST_REQUIRE_EQUAL(cached.size(), 0U);
1097 }
1098
1099 BOOST_AUTO_TEST_CASE(test_ns_speed)
1100 {
1101 std::unique_ptr<SyncRes> sr;
1102 initSR(sr);
1103
1104 primeHints();
1105
1106 const DNSName target("powerdns.com.");
1107
1108 std::map<ComboAddress, uint64_t> nsCounts;
1109
1110 sr->setAsyncCallback([target, &nsCounts](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1111 if (isRootServer(ip)) {
1112 setLWResult(res, 0, false, false, true);
1113 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1114 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1115 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1116
1117 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1118 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1119 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1120 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1121 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1122 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
1123
1124 return 1;
1125 }
1126 else {
1127 nsCounts[ip]++;
1128
1129 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1130 BOOST_CHECK_LT(nsCounts.size(), 3U);
1131
1132 /* let's time out on pdns-public-ns2.powerdns.com. */
1133 return 0;
1134 }
1135 else if (ip == ComboAddress("192.0.2.1:53")) {
1136 BOOST_CHECK_EQUAL(nsCounts.size(), 3U);
1137
1138 setLWResult(res, 0, true, false, true);
1139 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1140 return 1;
1141 }
1142
1143 return 0;
1144 }
1145
1146 return 0;
1147 });
1148
1149 struct timeval now = sr->getNow();
1150
1151 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1152 then pdns-public-ns1.powerdns.com. on IPv4 */
1153 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, now);
1154 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, now);
1155 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, now);
1156 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, now);
1157 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, now);
1158 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, now);
1159
1160 vector<DNSRecord> ret;
1161 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1162 BOOST_CHECK_EQUAL(res, RCode::NoError);
1163 BOOST_CHECK_EQUAL(ret.size(), 1U);
1164 BOOST_CHECK_EQUAL(nsCounts.size(), 3U);
1165 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1U);
1166 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1U);
1167 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1U);
1168 }
1169
1170 BOOST_AUTO_TEST_CASE(test_flawed_nsset)
1171 {
1172 std::unique_ptr<SyncRes> sr;
1173 initSR(sr);
1174
1175 primeHints();
1176
1177 const DNSName target("powerdns.com.");
1178
1179 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1180 if (isRootServer(ip)) {
1181 setLWResult(res, 0, false, false, true);
1182 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1183
1184 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1185
1186 return 1;
1187 }
1188 else if (ip == ComboAddress("192.0.2.1:53")) {
1189 setLWResult(res, 0, true, false, true);
1190 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1191 return 1;
1192 }
1193
1194 return 0;
1195 });
1196
1197 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
1198 time_t now = sr->getNow().tv_sec;
1199 std::vector<DNSRecord> records;
1200 std::vector<shared_ptr<RRSIGRecordContent>> sigs;
1201 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
1202
1203 s_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1204
1205 vector<DNSRecord> ret;
1206 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1207 BOOST_CHECK_EQUAL(res, RCode::NoError);
1208 BOOST_CHECK_EQUAL(ret.size(), 1U);
1209 }
1210
1211 BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset)
1212 {
1213 std::unique_ptr<SyncRes> sr;
1214 initSR(sr);
1215
1216 primeHints();
1217
1218 const DNSName target("powerdns.com.");
1219 size_t queriesCount = 0;
1220
1221 sr->setAsyncCallback([&queriesCount, target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1222 queriesCount++;
1223
1224 if (isRootServer(ip) && domain == target) {
1225 setLWResult(res, 0, false, false, true);
1226 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1227 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1228 return 1;
1229 }
1230 else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")) {
1231 setLWResult(res, 0, true, false, true);
1232 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1233 return 1;
1234 }
1235
1236 return 0;
1237 });
1238
1239 vector<DNSRecord> ret;
1240 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1241 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1242 BOOST_CHECK_EQUAL(ret.size(), 0U);
1243 /* one query to get NSs, then A and AAAA for each NS */
1244 BOOST_CHECK_EQUAL(queriesCount, 5U);
1245 }
1246
1247 BOOST_AUTO_TEST_CASE(test_cache_hit)
1248 {
1249 std::unique_ptr<SyncRes> sr;
1250 initSR(sr);
1251
1252 primeHints();
1253
1254 const DNSName target("powerdns.com.");
1255
1256 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1257 return 0;
1258 });
1259
1260 /* we populate the cache with eveything we need */
1261 time_t now = sr->getNow().tv_sec;
1262 std::vector<DNSRecord> records;
1263 std::vector<shared_ptr<RRSIGRecordContent>> sigs;
1264
1265 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
1266 s_RC->replace(now, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1267
1268 vector<DNSRecord> ret;
1269 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1270 BOOST_CHECK_EQUAL(res, RCode::NoError);
1271 BOOST_CHECK_EQUAL(ret.size(), 1U);
1272 }
1273
1274 BOOST_AUTO_TEST_CASE(test_no_rd)
1275 {
1276 std::unique_ptr<SyncRes> sr;
1277 initSR(sr);
1278
1279 primeHints();
1280
1281 const DNSName target("powerdns.com.");
1282 size_t queriesCount = 0;
1283
1284 sr->setCacheOnly();
1285
1286 sr->setAsyncCallback([target, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1287 queriesCount++;
1288 return 0;
1289 });
1290
1291 vector<DNSRecord> ret;
1292 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1293 BOOST_CHECK_EQUAL(res, RCode::NoError);
1294 BOOST_CHECK_EQUAL(ret.size(), 0U);
1295 BOOST_CHECK_EQUAL(queriesCount, 0U);
1296 }
1297
1298 BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl)
1299 {
1300 std::unique_ptr<SyncRes> sr;
1301 initSR(sr);
1302
1303 primeHints();
1304
1305 const DNSName target("cachettl.powerdns.com.");
1306 const ComboAddress ns("192.0.2.1:53");
1307
1308 sr->setAsyncCallback([target, ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1309 if (isRootServer(ip)) {
1310
1311 setLWResult(res, 0, false, false, true);
1312 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1313 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
1314 return 1;
1315 }
1316 else if (ip == ns) {
1317
1318 setLWResult(res, 0, true, false, false);
1319 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
1320
1321 return 1;
1322 }
1323
1324 return 0;
1325 });
1326
1327 const time_t now = sr->getNow().tv_sec;
1328 SyncRes::s_minimumTTL = 60;
1329 SyncRes::s_maxcachettl = 3600;
1330
1331 vector<DNSRecord> ret;
1332 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1333 BOOST_CHECK_EQUAL(res, RCode::NoError);
1334 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1335 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
1336
1337 const ComboAddress who;
1338 vector<DNSRecord> cached;
1339 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
1340 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1341 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
1342 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
1343
1344 cached.clear();
1345 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
1346 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1347 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
1348 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
1349 }
1350
1351 BOOST_AUTO_TEST_CASE(test_cache_min_max_ecs_ttl)
1352 {
1353 std::unique_ptr<SyncRes> sr;
1354 initSR(sr);
1355
1356 primeHints();
1357
1358 const DNSName target("cacheecsttl.powerdns.com.");
1359 const ComboAddress ns("192.0.2.1:53");
1360
1361 EDNSSubnetOpts incomingECS;
1362 incomingECS.source = Netmask("192.0.2.128/32");
1363 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1364 SyncRes::addEDNSDomain(target);
1365
1366 sr->setAsyncCallback([target, ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1367 BOOST_REQUIRE(srcmask);
1368 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1369
1370 if (isRootServer(ip)) {
1371
1372 setLWResult(res, 0, false, false, true);
1373 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1374 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 20);
1375 srcmask = boost::none;
1376
1377 return 1;
1378 }
1379 else if (ip == ns) {
1380
1381 setLWResult(res, 0, true, false, false);
1382 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
1383
1384 return 1;
1385 }
1386
1387 return 0;
1388 });
1389
1390 const time_t now = sr->getNow().tv_sec;
1391 SyncRes::s_minimumTTL = 60;
1392 SyncRes::s_minimumECSTTL = 120;
1393 SyncRes::s_maxcachettl = 3600;
1394
1395 vector<DNSRecord> ret;
1396 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1397 BOOST_CHECK_EQUAL(res, RCode::NoError);
1398 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1399 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumECSTTL);
1400
1401 const ComboAddress who("192.0.2.128");
1402 vector<DNSRecord> cached;
1403 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
1404 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1405 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
1406 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumECSTTL);
1407
1408 cached.clear();
1409 BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
1410 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1411 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
1412 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
1413
1414 cached.clear();
1415 BOOST_REQUIRE_GT(s_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0);
1416 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1417 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
1418 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
1419 }
1420
1421 BOOST_AUTO_TEST_CASE(test_cache_expired_ttl)
1422 {
1423 std::unique_ptr<SyncRes> sr;
1424 initSR(sr);
1425
1426 primeHints();
1427
1428 const DNSName target("powerdns.com.");
1429
1430 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
1431 if (isRootServer(ip)) {
1432 setLWResult(res, 0, false, false, true);
1433 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1434
1435 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1436
1437 return 1;
1438 }
1439 else if (ip == ComboAddress("192.0.2.1:53")) {
1440 setLWResult(res, 0, true, false, true);
1441 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1442 return 1;
1443 }
1444
1445 return 0;
1446 });
1447
1448 /* we populate the cache with entries that expired 60s ago*/
1449 const time_t now = sr->getNow().tv_sec;
1450
1451 std::vector<DNSRecord> records;
1452 std::vector<shared_ptr<RRSIGRecordContent>> sigs;
1453 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
1454
1455 s_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1456
1457 vector<DNSRecord> ret;
1458 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1459 BOOST_CHECK_EQUAL(res, RCode::NoError);
1460 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1461 BOOST_REQUIRE(ret[0].d_type == QType::A);
1462 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
1463 }
1464
1465 BOOST_AUTO_TEST_SUITE_END()