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