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