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