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