]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc1.cc
Merge pull request #14267 from ZaphodB/master
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc1.cc
1 #ifndef BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_DYN_LINK
3 #endif
4
5 #include <boost/test/unit_test.hpp>
6
7 #include "test-syncres_cc.hh"
8 #include "taskqueue.hh"
9 #include "rec-taskqueue.hh"
10
11 BOOST_AUTO_TEST_SUITE(syncres_cc1)
12
13 BOOST_AUTO_TEST_CASE(test_root_primed)
14 {
15 std::unique_ptr<SyncRes> sr;
16 initSR(sr);
17
18 primeHints();
19
20 const DNSName target("a.root-servers.net.");
21 try {
22 /* we are primed, but only with non-auth data so we cannot resolve A a.root-servers.net. without any query */
23 vector<DNSRecord> ret;
24 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
25 BOOST_CHECK_EQUAL(res, RCode::ServFail);
26 BOOST_REQUIRE_EQUAL(ret.size(), 0U);
27
28 ret.clear();
29 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
30 BOOST_CHECK_EQUAL(res, RCode::ServFail);
31 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
32 BOOST_REQUIRE_EQUAL(ret.size(), 0U);
33 BOOST_CHECK(false);
34 }
35 catch (const ImmediateServFailException) {
36 // Expected
37 }
38 }
39
40 BOOST_AUTO_TEST_CASE(test_root_primed_ns)
41 {
42 std::unique_ptr<SyncRes> sr;
43 initSR(sr);
44
45 primeHints();
46 const DNSName target(".");
47
48 /* we are primed, but we should not be able to NS . without any query
49 because the . NS entry is not stored as authoritative */
50
51 size_t queriesCount = 0;
52
53 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 */) {
54 queriesCount++;
55
56 if (domain == target && type == QType::NS) {
57
58 setLWResult(res, 0, true, false, true);
59 char addr[] = "a.root-servers.net.";
60 for (char idx = 'a'; idx <= 'm'; idx++) {
61 addr[0] = idx;
62 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
63 }
64
65 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
66 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
67
68 return LWResult::Result::Success;
69 }
70
71 return LWResult::Result::Timeout;
72 });
73
74 vector<DNSRecord> ret;
75 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
76 BOOST_CHECK_EQUAL(res, RCode::NoError);
77 BOOST_REQUIRE_EQUAL(ret.size(), 13U);
78 BOOST_CHECK_EQUAL(queriesCount, 1U);
79 }
80
81 BOOST_AUTO_TEST_CASE(test_root_not_primed)
82 {
83 std::unique_ptr<SyncRes> sr;
84 initSR(sr);
85
86 size_t queriesCount = 0;
87
88 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 */) {
89 queriesCount++;
90
91 if (domain == g_rootdnsname && type == QType::NS) {
92 setLWResult(res, 0, true, false, true);
93 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
94 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
95 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
96
97 return LWResult::Result::Success;
98 }
99
100 return LWResult::Result::Timeout;
101 });
102
103 /* we are not primed yet, so SyncRes will have to call primeHints()
104 then call getRootNS(), for which at least one of the root servers needs to answer */
105 vector<DNSRecord> ret;
106 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
107 BOOST_CHECK_EQUAL(res, RCode::NoError);
108 BOOST_CHECK_EQUAL(ret.size(), 1U);
109 BOOST_CHECK_EQUAL(queriesCount, 2U);
110 }
111
112 BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response)
113 {
114 std::unique_ptr<SyncRes> sr;
115 initSR(sr);
116 // We expect an error, do not log it
117 g_log.toConsole(Logger::Critical);
118 std::set<ComboAddress> downServers;
119
120 /* we are not primed yet, so SyncRes will have to call primeHints()
121 then call getRootNS(), for which at least one of the root servers needs to answer.
122 None will, so it should ServFail.
123 */
124 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 */) {
125 downServers.insert(address);
126 return LWResult::Result::Timeout;
127 });
128
129 vector<DNSRecord> ret;
130 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
131 BOOST_CHECK_EQUAL(res, RCode::ServFail);
132 BOOST_CHECK_EQUAL(ret.size(), 0U);
133 BOOST_CHECK(downServers.size() > 0);
134 /* we explicitly refuse to mark the root servers down */
135 for (const auto& server : downServers) {
136 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0U);
137 }
138 }
139
140 BOOST_AUTO_TEST_CASE(test_root_ns_poison_resistance)
141 {
142 std::unique_ptr<SyncRes> sr;
143 initSR(sr);
144
145 primeHints();
146 const DNSName target("www.example.com.");
147
148 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 */) {
149 if (domain == g_rootdnsname && type == QType::NS) {
150
151 setLWResult(res, 0, true, false, true);
152 char addr[] = "a.root-servers.net.";
153 for (char idx = 'a'; idx <= 'm'; idx++) {
154 addr[0] = idx;
155 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
156 }
157
158 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
159 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
160
161 return LWResult::Result::Success;
162 }
163
164 if (domain == target && type == QType::A) {
165
166 setLWResult(res, 0, true, false, true);
167 addRecordToLW(res, target, QType::A, "1.2.3.4", DNSResourceRecord::ANSWER, 3600);
168
169 addRecordToLW(res, ".", QType::NS, "poison.name.", DNSResourceRecord::AUTHORITY, 3600);
170 addRecordToLW(res, "poison.name", QType::A, "4.5.6.7", DNSResourceRecord::ADDITIONAL, 3600);
171
172 return LWResult::Result::Success;
173 }
174
175 return LWResult::Result::Timeout;
176 });
177
178 vector<DNSRecord> ret;
179 // Check we have 13 root servers
180 int res = sr->beginResolve(g_rootdnsname, QType(QType::NS), QClass::IN, ret);
181 BOOST_CHECK_EQUAL(res, RCode::NoError);
182 BOOST_REQUIRE_EQUAL(ret.size(), 13U);
183
184 // Try to poison
185 ret.clear();
186 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
187 BOOST_CHECK_EQUAL(res, RCode::NoError);
188 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
189
190 // Still should have 13
191 ret.clear();
192 res = sr->beginResolve(g_rootdnsname, QType(QType::NS), QClass::IN, ret);
193 BOOST_CHECK_EQUAL(res, RCode::NoError);
194 BOOST_REQUIRE_EQUAL(ret.size(), 13U);
195 }
196
197 BOOST_AUTO_TEST_CASE(test_root_primed_ns_update)
198 {
199 std::unique_ptr<SyncRes> sr;
200 initSR(sr);
201
202 primeHints();
203 const DNSName target(".");
204 const DNSName aroot("a.root-servers.net.");
205 const string newA = "1.2.3.4";
206 const string newAAAA = "1::2";
207
208 /* we are primed, but we should not be able to NS . without any query
209 because the . NS entry is not stored as authoritative */
210
211 size_t queriesCount = 0;
212
213 auto asynccb = [&](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 */) {
214 queriesCount++;
215
216 if (domain == target && type == QType::NS) {
217
218 setLWResult(res, 0, true, false, true);
219 char addr[] = "a.root-servers.net.";
220 for (char idx = 'a'; idx <= 'm'; idx++) {
221 addr[0] = idx;
222 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
223 }
224
225 addRecordToLW(res, aroot.toString(), QType::A, newA, DNSResourceRecord::ADDITIONAL, 3600);
226 addRecordToLW(res, aroot.toString(), QType::AAAA, newAAAA, DNSResourceRecord::ADDITIONAL, 3600);
227
228 return LWResult::Result::Success;
229 }
230 return LWResult::Result::Timeout;
231 };
232
233 sr->setAsyncCallback(asynccb);
234
235 struct timeval now;
236 Utility::gettimeofday(&now, nullptr);
237
238 vector<DNSRecord> ret;
239 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
240 BOOST_CHECK_EQUAL(res, RCode::NoError);
241 BOOST_REQUIRE_EQUAL(ret.size(), 13U);
242 BOOST_CHECK_EQUAL(queriesCount, 1U);
243
244 ret.clear();
245 time_t cached = g_recCache->get(now.tv_sec, aroot, QType::A, MemRecursorCache::None, &ret, ComboAddress());
246 BOOST_CHECK(cached > 0);
247 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
248 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress(newA));
249
250 ret.clear();
251 cached = g_recCache->get(now.tv_sec, aroot, QType::AAAA, MemRecursorCache::None, &ret, ComboAddress());
252 BOOST_CHECK(cached > 0);
253 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
254 BOOST_CHECK(getRR<AAAARecordContent>(ret[0])->getCA() == ComboAddress(newAAAA));
255 }
256
257 static void test_edns_formerr_fallback_f(bool sample)
258 {
259 std::unique_ptr<SyncRes> sr;
260 initSR(sr);
261 if (sample) {
262 sr->setQNameMinimization();
263 }
264 ComboAddress noEDNSServer;
265 size_t queriesWithEDNS = 0;
266 size_t queriesWithoutEDNS = 0;
267
268 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 */) {
269 if (EDNS0Level != 0) {
270 queriesWithEDNS++;
271 noEDNSServer = address;
272
273 setLWResult(res, RCode::FormErr);
274 return LWResult::Result::Success;
275 }
276
277 queriesWithoutEDNS++;
278
279 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
280 setLWResult(res, 0, true, false, false);
281 addRecordToLW(res, domain, QType::A, "192.0.2.1");
282 return LWResult::Result::Success;
283 }
284
285 return sample ? basicRecordsForQnameMinimization(res, domain, type) : LWResult::Result::Timeout;
286 });
287
288 primeHints();
289
290 /* fake that the root NS doesn't handle EDNS, check that we fallback */
291 vector<DNSRecord> ret;
292 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
293 BOOST_CHECK_EQUAL(res, RCode::NoError);
294 BOOST_CHECK_EQUAL(ret.size(), 1U);
295 BOOST_CHECK_EQUAL(queriesWithEDNS, sample ? 3U : 1U);
296 BOOST_CHECK_EQUAL(queriesWithoutEDNS, sample ? 4U : 1U);
297 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), sample ? 3U : 1U);
298 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
299 }
300
301 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback)
302 {
303 test_edns_formerr_fallback_f(false);
304 }
305
306 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback_qmin)
307 {
308 // DISABLED UNTIL QNAME MINIMIZATION IS THERE
309 return;
310 test_edns_formerr_fallback_f(true);
311 }
312
313 BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled)
314 {
315 std::unique_ptr<SyncRes> sr;
316 initSR(sr);
317
318 /* in this test, the auth answers with FormErr to an EDNS-enabled
319 query, but the response does contain EDNS so we should not mark
320 it as EDNS ignorant or intolerant.
321 */
322 size_t queriesWithEDNS = 0;
323 size_t queriesWithoutEDNS = 0;
324 std::set<ComboAddress> usedServers;
325
326 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 */) {
327 if (EDNS0Level > 0) {
328 queriesWithEDNS++;
329 }
330 else {
331 queriesWithoutEDNS++;
332 }
333 usedServers.insert(address);
334
335 if (type == QType::DNAME) {
336 setLWResult(res, RCode::FormErr);
337 if (EDNS0Level > 0) {
338 res->d_haveEDNS = true;
339 }
340 return LWResult::Result::Success;
341 }
342
343 return LWResult::Result::Timeout;
344 });
345
346 primeHints();
347
348 vector<DNSRecord> ret;
349 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::DNAME), QClass::IN, ret);
350 BOOST_CHECK_EQUAL(res, RCode::ServFail);
351 BOOST_CHECK_EQUAL(ret.size(), 0U);
352 BOOST_CHECK_EQUAL(queriesWithEDNS, 26U);
353 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 0U);
354 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0U);
355 BOOST_CHECK_EQUAL(usedServers.size(), 26U);
356 for (const auto& server : usedServers) {
357 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
358 }
359 }
360
361 BOOST_AUTO_TEST_CASE(test_meta_types)
362 {
363 std::unique_ptr<SyncRes> sr;
364 initSR(sr);
365
366 static const std::set<uint16_t> invalidTypes = {128, QType::AXFR, QType::IXFR, QType::RRSIG, QType::NSEC3, QType::OPT, QType::TSIG, QType::TKEY, QType::MAILA, QType::MAILB, 65535};
367
368 for (const auto qtype : invalidTypes) {
369 size_t queriesCount = 0;
370
371 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 */) {
372 queriesCount++;
373 return LWResult::Result::Timeout;
374 });
375
376 primeHints();
377
378 vector<DNSRecord> ret;
379 int res = sr->beginResolve(DNSName("powerdns.com."), QType(qtype), QClass::IN, ret);
380 BOOST_CHECK_EQUAL(res, -1);
381 BOOST_CHECK_EQUAL(ret.size(), 0U);
382 BOOST_CHECK_EQUAL(queriesCount, 0U);
383 }
384 }
385
386 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp)
387 {
388 std::unique_ptr<SyncRes> sr;
389 initSR(sr);
390
391 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 */) {
392 if (!doTCP) {
393 setLWResult(res, 0, false, true, false);
394 return LWResult::Result::Success;
395 }
396 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
397 setLWResult(res, 0, true, false, false);
398 addRecordToLW(res, domain, QType::A, "192.0.2.1");
399 return LWResult::Result::Success;
400 }
401
402 return LWResult::Result::Timeout;
403 });
404
405 primeHints();
406
407 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
408 vector<DNSRecord> ret;
409 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
410 BOOST_CHECK_EQUAL(res, RCode::NoError);
411 }
412
413 BOOST_AUTO_TEST_CASE(test_tc_over_tcp)
414 {
415 std::unique_ptr<SyncRes> sr;
416 initSR(sr);
417
418 size_t tcpQueriesCount = 0;
419
420 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 */) {
421 if (!doTCP) {
422 setLWResult(res, 0, true, true, false);
423 return LWResult::Result::Success;
424 }
425
426 /* first TCP query is answered with a TC response */
427 tcpQueriesCount++;
428 if (tcpQueriesCount == 1) {
429 setLWResult(res, 0, true, true, false);
430 }
431 else {
432 setLWResult(res, 0, true, false, false);
433 }
434
435 addRecordToLW(res, domain, QType::A, "192.0.2.1");
436 return LWResult::Result::Success;
437 });
438
439 primeHints();
440
441 vector<DNSRecord> ret;
442 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
443 BOOST_CHECK_EQUAL(res, RCode::NoError);
444 BOOST_CHECK_EQUAL(tcpQueriesCount, 2U);
445 }
446
447 BOOST_AUTO_TEST_CASE(test_all_nss_down)
448 {
449 std::unique_ptr<SyncRes> sr;
450 initSR(sr);
451 std::set<ComboAddress> downServers;
452
453 primeHints();
454
455 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 */) {
456 if (isRootServer(address)) {
457 setLWResult(res, 0, false, false, true);
458 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
459 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
460 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
461 return LWResult::Result::Success;
462 }
463 if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
464 setLWResult(res, 0, false, false, true);
465 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
466 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
467 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
468 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
469 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
470 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
471 return LWResult::Result::Success;
472 }
473 downServers.insert(address);
474 res->d_usec = g_networkTimeoutMsec * 1000;
475 return LWResult::Result::Timeout;
476 });
477
478 DNSName target("powerdns.com.");
479
480 vector<DNSRecord> ret;
481 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
482 BOOST_CHECK_EQUAL(res, RCode::ServFail);
483 BOOST_CHECK_EQUAL(ret.size(), 0U);
484 BOOST_CHECK_EQUAL(downServers.size(), 4U);
485
486 time_t now = sr->getNow().tv_sec;
487 for (const auto& server : downServers) {
488 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1U);
489 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
490 }
491 }
492
493 BOOST_AUTO_TEST_CASE(test_all_nss_network_error)
494 {
495 std::unique_ptr<SyncRes> sr;
496 initSR(sr);
497 std::set<ComboAddress> downServers;
498
499 primeHints();
500
501 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 */) {
502 if (isRootServer(address)) {
503 setLWResult(res, 0, false, false, true);
504 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
505 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
506 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
507 return LWResult::Result::Success;
508 }
509 if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
510 setLWResult(res, 0, false, false, true);
511 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
512 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
513 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
514 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
515 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
516 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
517 return LWResult::Result::Success;
518 }
519 downServers.insert(address);
520 res->d_usec = g_networkTimeoutMsec * 1000;
521 return LWResult::Result::Timeout;
522 });
523
524 /* exact same test than the previous one, except instead of a time out we fake a network error */
525 DNSName target("powerdns.com.");
526
527 vector<DNSRecord> ret;
528 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
529 BOOST_CHECK_EQUAL(res, RCode::ServFail);
530 BOOST_CHECK_EQUAL(ret.size(), 0U);
531 BOOST_CHECK_EQUAL(downServers.size(), 4U);
532
533 time_t now = sr->getNow().tv_sec;
534 for (const auto& server : downServers) {
535 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1U);
536 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
537 }
538 }
539
540 BOOST_AUTO_TEST_CASE(test_all_nss_send_tc_then_garbage_over_tcp)
541 {
542 std::unique_ptr<SyncRes> sr;
543 initSR(sr);
544
545 primeHints();
546
547 std::set<ComboAddress> downServers;
548
549 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 */) {
550 if (isRootServer(address)) {
551 setLWResult(res, 0, false, false, true);
552 addRecordToLW(res, "lock-up.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
553 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
554 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
555 return LWResult::Result::Success;
556 }
557
558 if (!doTCP) {
559 setLWResult(res, 0, false, true, false);
560 return LWResult::Result::Success;
561 }
562 downServers.insert(address);
563
564 setLWResult(res, RCode::FormErr, false, false, false);
565 res->d_validpacket = false;
566 return LWResult::Result::Success;
567 });
568
569 DNSName target("www.lock-up.");
570
571 vector<DNSRecord> ret;
572 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
573 BOOST_CHECK_EQUAL(res, RCode::ServFail);
574 BOOST_CHECK_EQUAL(ret.size(), 0U);
575 BOOST_CHECK_EQUAL(downServers.size(), 2U);
576
577 for (const auto& server : downServers) {
578 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
579 BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 1000000U);
580 }
581 }
582
583 BOOST_AUTO_TEST_CASE(test_all_nss_send_garbage_over_udp)
584 {
585 std::unique_ptr<SyncRes> sr;
586 initSR(sr);
587
588 primeHints();
589
590 std::set<ComboAddress> downServers;
591 size_t queriesCount = 0;
592
593 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 */) {
594 if (isRootServer(address)) {
595 setLWResult(res, 0, false, false, true);
596 addRecordToLW(res, "lock-up.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
597 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
598 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
599 return LWResult::Result::Success;
600 }
601
602 ++queriesCount;
603 downServers.insert(address);
604
605 setLWResult(res, RCode::FormErr, false, false, false);
606 res->d_validpacket = false;
607 return LWResult::Result::Success;
608 });
609
610 DNSName target("www.lock-up.");
611
612 vector<DNSRecord> ret;
613 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
614 BOOST_CHECK_EQUAL(res, RCode::ServFail);
615 BOOST_CHECK_EQUAL(ret.size(), 0U);
616 BOOST_CHECK_EQUAL(downServers.size(), 2U);
617 /* two queries with EDNS, that's it */
618 BOOST_CHECK_EQUAL(queriesCount, 2U);
619
620 for (const auto& server : downServers) {
621 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
622 BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 1000000U);
623 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSIGNORANT);
624 }
625 }
626
627 BOOST_AUTO_TEST_CASE(test_regular_ns_send_refused)
628 {
629 std::unique_ptr<SyncRes> sr;
630 initSR(sr);
631
632 primeHints();
633
634 std::set<ComboAddress> downServers;
635 size_t queriesCount = 0;
636
637 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 */) {
638 if (isRootServer(address)) {
639 setLWResult(res, 0, false, false, true);
640 addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
641 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
642 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
643 return LWResult::Result::Success;
644 }
645
646 ++queriesCount;
647 downServers.insert(address);
648
649 setLWResult(res, RCode::Refused, false, false, true);
650
651 return LWResult::Result::Success;
652 });
653
654 DNSName target("www.refused.");
655
656 vector<DNSRecord> ret;
657 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
658 BOOST_CHECK_EQUAL(res, RCode::ServFail);
659 BOOST_CHECK_EQUAL(ret.size(), 0U);
660 BOOST_CHECK_EQUAL(downServers.size(), 2U);
661 BOOST_CHECK_EQUAL(queriesCount, 2U);
662
663 for (const auto& server : downServers) {
664 /* same as any other server */
665 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
666 BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 0U);
667 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
668 }
669 }
670
671 BOOST_AUTO_TEST_CASE(test_forward_ns_send_refused)
672 {
673 std::unique_ptr<SyncRes> sr;
674 initSR(sr);
675
676 primeHints();
677
678 std::set<ComboAddress> downServers;
679 size_t queriesCount = 0;
680
681 const DNSName target("www.refused.");
682
683 SyncRes::AuthDomain ad;
684 const std::vector<ComboAddress> forwardedNSs{ComboAddress("192.0.2.42:53"), ComboAddress("192.0.2.43:53")};
685 ad.d_rdForward = false;
686 ad.d_servers = forwardedNSs;
687 (*SyncRes::t_sstorage.domainmap)[target] = ad;
688
689 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 */) {
690 if (isRootServer(address)) {
691 setLWResult(res, 0, false, false, true);
692 addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
693 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
694 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
695 return LWResult::Result::Success;
696 }
697
698 ++queriesCount;
699 downServers.insert(address);
700
701 setLWResult(res, RCode::Refused, false, false, true);
702
703 return LWResult::Result::Success;
704 });
705
706 vector<DNSRecord> ret;
707 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
708 BOOST_CHECK_EQUAL(res, RCode::ServFail);
709 BOOST_CHECK_EQUAL(ret.size(), 0U);
710 BOOST_CHECK_EQUAL(downServers.size(), 2U);
711 BOOST_CHECK_EQUAL(queriesCount, 2U);
712
713 for (const auto& server : forwardedNSs) {
714 BOOST_CHECK_EQUAL(downServers.count(server), 1U);
715 /* same as any other server */
716 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
717 BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 0U);
718 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
719 }
720 }
721
722 BOOST_AUTO_TEST_CASE(test_forward_ns_send_servfail)
723 {
724 std::unique_ptr<SyncRes> sr;
725 initSR(sr);
726
727 primeHints();
728
729 std::set<ComboAddress> downServers;
730 size_t queriesCount = 0;
731
732 const DNSName target("www.refused.");
733
734 SyncRes::AuthDomain ad;
735 const std::vector<ComboAddress> forwardedNSs{ComboAddress("192.0.2.42:53"), ComboAddress("192.0.2.43:53")};
736 ad.d_rdForward = false;
737 ad.d_servers = forwardedNSs;
738 (*SyncRes::t_sstorage.domainmap)[DNSName("refused.")] = ad;
739
740 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 */) {
741 if (isRootServer(address)) {
742 setLWResult(res, 0, false, false, true);
743 addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
744 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
745 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
746 return LWResult::Result::Success;
747 }
748
749 ++queriesCount;
750 downServers.insert(address);
751
752 setLWResult(res, RCode::ServFail, false, false, true);
753
754 return LWResult::Result::Success;
755 });
756
757 vector<DNSRecord> ret;
758 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
759 BOOST_CHECK_EQUAL(res, RCode::ServFail);
760 BOOST_CHECK_EQUAL(ret.size(), 0U);
761 BOOST_CHECK_EQUAL(downServers.size(), 2U);
762 BOOST_CHECK_EQUAL(queriesCount, 2U);
763
764 for (const auto& server : forwardedNSs) {
765 BOOST_CHECK_EQUAL(downServers.count(server), 1U);
766 /* on servfail from a server we forward to we only increase the NS speed so
767 that a different server might be tried instead, but we don't throttle */
768 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
769 BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName(server.toStringWithPort()), server), 1000000U);
770 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
771 }
772 }
773
774 BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue)
775 {
776 std::unique_ptr<SyncRes> sr;
777 initSR(sr);
778
779 primeHints();
780
781 DNSName target("www.powerdns.com.");
782
783 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 */) {
784 if (isRootServer(address)) {
785 setLWResult(res, 0, false, false, true);
786 if (domain == target) {
787 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
788 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
789 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
790 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
791 }
792 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
793 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
794 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
795 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
796 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
797 }
798 return LWResult::Result::Success;
799 }
800 if (address == ComboAddress("192.0.2.3:53")) {
801 setLWResult(res, 0, true, false, true);
802 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
803 if (type == QType::A) {
804 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
805 }
806 else if (type == QType::AAAA) {
807 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
808 }
809 }
810 else if (domain == target) {
811 if (type == QType::A) {
812 addRecordToLW(res, domain, QType::A, "192.0.2.1");
813 }
814 else if (type == QType::AAAA) {
815 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
816 }
817 }
818 return LWResult::Result::Success;
819 }
820 return LWResult::Result::Timeout;
821 });
822
823 vector<DNSRecord> ret;
824 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
825 BOOST_CHECK_EQUAL(res, RCode::NoError);
826 BOOST_CHECK_EQUAL(ret.size(), 1U);
827 }
828
829 BOOST_AUTO_TEST_CASE(test_os_limit_errors)
830 {
831 std::unique_ptr<SyncRes> sr;
832 initSR(sr);
833 std::set<ComboAddress> downServers;
834
835 primeHints();
836
837 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 */) {
838 if (isRootServer(address)) {
839 setLWResult(res, 0, false, false, true);
840 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
841 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
842 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
843 return LWResult::Result::Success;
844 }
845 if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
846 setLWResult(res, 0, false, false, true);
847 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
848 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
849 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
850 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
851 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
852 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
853 return LWResult::Result::Success;
854 }
855 {
856 if (downServers.size() < 3) {
857 /* only the last one will answer */
858 downServers.insert(address);
859 res->d_usec = g_networkTimeoutMsec * 1000;
860 return LWResult::Result::OSLimitError;
861 }
862 setLWResult(res, 0, true, false, true);
863 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
864 return LWResult::Result::Success;
865 }
866 });
867
868 DNSName target("powerdns.com.");
869
870 vector<DNSRecord> ret;
871 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
872 BOOST_CHECK_EQUAL(res, RCode::NoError);
873 BOOST_CHECK_EQUAL(ret.size(), 1U);
874 BOOST_CHECK_EQUAL(downServers.size(), 3U);
875
876 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
877 time_t now = sr->getNow().tv_sec;
878 for (const auto& server : downServers) {
879 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0U);
880 BOOST_CHECK(!SyncRes::isThrottled(now, server, target, QType::A));
881 }
882 }
883
884 BOOST_AUTO_TEST_CASE(test_glued_referral)
885 {
886 std::unique_ptr<SyncRes> sr;
887 initSR(sr);
888
889 primeHints();
890
891 const DNSName target("powerdns.com.");
892
893 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 */) {
894 /* this will cause issue with qname minimization if we ever implement it */
895 if (domain != target) {
896 return LWResult::Result::Timeout;
897 }
898
899 if (isRootServer(address)) {
900 setLWResult(res, 0, false, false, true);
901 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
902 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
903 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
904 return LWResult::Result::Success;
905 }
906 if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
907 setLWResult(res, 0, false, false, true);
908 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
909 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
910 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
911 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
912 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
913 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
914 return LWResult::Result::Success;
915 }
916 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")) {
917 setLWResult(res, 0, true, false, true);
918 addRecordToLW(res, target, QType::A, "192.0.2.4");
919 return LWResult::Result::Success;
920 }
921 return LWResult::Result::Timeout;
922 });
923
924 vector<DNSRecord> ret;
925 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
926 BOOST_CHECK_EQUAL(res, RCode::NoError);
927 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
928 BOOST_CHECK(ret[0].d_type == QType::A);
929 BOOST_CHECK_EQUAL(ret[0].d_name, target);
930 }
931
932 BOOST_AUTO_TEST_CASE(test_glueless_referral)
933 {
934 std::unique_ptr<SyncRes> sr;
935 initSR(sr);
936
937 primeHints();
938
939 const DNSName target("powerdns.com.");
940
941 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 */) {
942 if (isRootServer(address)) {
943 setLWResult(res, 0, false, false, true);
944
945 if (domain.isPartOf(DNSName("com."))) {
946 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
947 }
948 else if (domain.isPartOf(DNSName("org."))) {
949 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
950 }
951 else {
952 setLWResult(res, RCode::NXDomain, false, false, true);
953 return LWResult::Result::Success;
954 }
955
956 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
957 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
958 return LWResult::Result::Success;
959 }
960 if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
961 if (domain == target) {
962 setLWResult(res, 0, false, false, true);
963 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
964 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
965 return LWResult::Result::Success;
966 }
967 if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
968 setLWResult(res, 0, true, false, true);
969 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
970 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
971 return LWResult::Result::Success;
972 }
973 if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
974 setLWResult(res, 0, true, false, true);
975 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
976 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
977 return LWResult::Result::Success;
978 }
979
980 setLWResult(res, RCode::NXDomain, false, false, true);
981 return LWResult::Result::Success;
982 }
983 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")) {
984 setLWResult(res, 0, true, false, true);
985 addRecordToLW(res, target, QType::A, "192.0.2.4");
986 return LWResult::Result::Success;
987 }
988 return LWResult::Result::Timeout;
989 });
990
991 vector<DNSRecord> ret;
992 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
993 BOOST_CHECK_EQUAL(res, RCode::NoError);
994 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
995 BOOST_CHECK(ret[0].d_type == QType::A);
996 BOOST_CHECK_EQUAL(ret[0].d_name, target);
997 }
998
999 BOOST_AUTO_TEST_CASE(test_endless_glueless_referral)
1000 {
1001 std::unique_ptr<SyncRes> sr;
1002 initSR(sr);
1003
1004 primeHints();
1005
1006 const DNSName target("powerdns.com.");
1007
1008 size_t count = 0;
1009 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 */) {
1010 if (isRootServer(address)) {
1011 setLWResult(res, 0, false, false, true);
1012
1013 if (domain.isPartOf(DNSName("com."))) {
1014 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1015 }
1016 else if (domain.isPartOf(DNSName("org."))) {
1017 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1018 }
1019 else {
1020 setLWResult(res, RCode::NXDomain, false, false, true);
1021 return LWResult::Result::Success;
1022 }
1023
1024 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1025 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1026 return LWResult::Result::Success;
1027 }
1028 if (domain == target) {
1029 setLWResult(res, 0, false, false, true);
1030 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1031 addRecordToLW(res, "powerdns.com.", QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1032 return LWResult::Result::Success;
1033 }
1034 setLWResult(res, 0, false, false, true);
1035 addRecordToLW(res, domain, QType::NS, std::to_string(count) + ".ns1.powerdns.org", DNSResourceRecord::AUTHORITY, 172800);
1036 addRecordToLW(res, domain, QType::NS, std::to_string(count) + ".ns2.powerdns.org", DNSResourceRecord::AUTHORITY, 172800);
1037 count++;
1038 return LWResult::Result::Success;
1039 });
1040
1041 vector<DNSRecord> ret;
1042 BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
1043 ImmediateServFailException,
1044 [&](const ImmediateServFailException& isfe) {
1045 return isfe.reason.substr(0, 9) == "More than";
1046 });
1047 }
1048
1049 BOOST_AUTO_TEST_CASE(test_glueless_referral_aaaa_task)
1050 {
1051 std::unique_ptr<SyncRes> sr;
1052 initSR(sr);
1053
1054 primeHints();
1055
1056 const DNSName target("powerdns.com.");
1057
1058 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 */) {
1059 if (isRootServer(address)) {
1060 setLWResult(res, 0, false, false, true);
1061
1062 if (domain.isPartOf(DNSName("com."))) {
1063 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1064 }
1065 else if (domain.isPartOf(DNSName("org."))) {
1066 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1067 }
1068 else {
1069 setLWResult(res, RCode::NXDomain, false, false, true);
1070 return LWResult::Result::Success;
1071 }
1072
1073 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1074 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1075 return LWResult::Result::Success;
1076 }
1077 if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
1078 if (domain == target) {
1079 setLWResult(res, 0, false, false, true);
1080 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1081 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1082 return LWResult::Result::Success;
1083 }
1084 if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
1085 setLWResult(res, 0, true, false, true);
1086 if (type == QType::A) {
1087 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
1088 }
1089 else {
1090 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
1091 }
1092 return LWResult::Result::Success;
1093 }
1094 if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1095 setLWResult(res, 0, true, false, true);
1096 if (type == QType::A) {
1097 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1098 }
1099 else {
1100 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1101 }
1102 return LWResult::Result::Success;
1103 }
1104
1105 setLWResult(res, RCode::NXDomain, false, false, true);
1106 return LWResult::Result::Success;
1107 }
1108 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")) {
1109 setLWResult(res, 0, true, false, true);
1110 addRecordToLW(res, target, QType::A, "192.0.2.4");
1111 return LWResult::Result::Success;
1112 }
1113 return LWResult::Result::Timeout;
1114 });
1115
1116 vector<DNSRecord> ret;
1117 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1118 BOOST_CHECK_EQUAL(res, RCode::NoError);
1119 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1120 BOOST_CHECK(ret[0].d_type == QType::A);
1121 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1122
1123 // One task should be submitted
1124 BOOST_REQUIRE_EQUAL(getTaskSize(), 1U);
1125 auto task = taskQueuePop();
1126 BOOST_CHECK(task.d_qname == DNSName("pdns-public-ns1.powerdns.org") || task.d_qname == DNSName("pdns-public-ns2.powerdns.org"));
1127 BOOST_CHECK_EQUAL(task.d_qtype, QType::AAAA);
1128 }
1129
1130 BOOST_AUTO_TEST_CASE(test_edns_subnet_by_domain)
1131 {
1132 std::unique_ptr<SyncRes> sr;
1133 initSR(sr);
1134
1135 primeHints();
1136
1137 const DNSName target("powerdns.com.");
1138 SyncRes::addEDNSDomain(target);
1139
1140 EDNSSubnetOpts incomingECS;
1141 incomingECS.source = Netmask("192.0.2.128/32");
1142 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1143
1144 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 */) {
1145 BOOST_REQUIRE(srcmask);
1146 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1147
1148 if (isRootServer(address)) {
1149 setLWResult(res, 0, false, false, true);
1150 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1151 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1152
1153 /* this one did not use the ECS info */
1154 srcmask = boost::none;
1155
1156 return LWResult::Result::Success;
1157 }
1158 if (address == ComboAddress("192.0.2.1:53")) {
1159
1160 setLWResult(res, 0, true, false, false);
1161 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1162
1163 /* this one did, but only up to a precision of /16, not the full /24 */
1164 srcmask = Netmask("192.0.0.0/16");
1165
1166 return LWResult::Result::Success;
1167 }
1168
1169 return LWResult::Result::Timeout;
1170 });
1171
1172 SyncRes::s_ecsqueries = 0;
1173 SyncRes::s_ecsresponses = 0;
1174 vector<DNSRecord> ret;
1175 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1176 BOOST_CHECK_EQUAL(res, RCode::NoError);
1177 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1178 BOOST_CHECK(ret[0].d_type == QType::A);
1179 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1180 BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 2U);
1181 BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1U);
1182 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
1183 BOOST_CHECK_EQUAL(entry.second, entry.first == 15 ? 1U : 0U);
1184 }
1185 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
1186 BOOST_CHECK_EQUAL(entry.second, 0U);
1187 }
1188 }
1189
1190 BOOST_AUTO_TEST_CASE(test_edns_subnet_by_addr)
1191 {
1192 std::unique_ptr<SyncRes> sr;
1193 initSR(sr);
1194
1195 primeHints();
1196
1197 const DNSName target("powerdns.com.");
1198 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1199
1200 EDNSSubnetOpts incomingECS;
1201 incomingECS.source = Netmask("2001:DB8::FF/128");
1202 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1203
1204 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 */) {
1205 if (isRootServer(address)) {
1206 BOOST_REQUIRE(!srcmask);
1207
1208 setLWResult(res, 0, false, false, true);
1209 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1210 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1211 return LWResult::Result::Success;
1212 }
1213 if (address == ComboAddress("192.0.2.1:53")) {
1214
1215 BOOST_REQUIRE(srcmask);
1216 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1217
1218 setLWResult(res, 0, true, false, false);
1219 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1220 return LWResult::Result::Success;
1221 }
1222
1223 return LWResult::Result::Timeout;
1224 });
1225
1226 SyncRes::s_ecsqueries = 0;
1227 SyncRes::s_ecsresponses = 0;
1228 vector<DNSRecord> ret;
1229 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1230 BOOST_CHECK_EQUAL(res, RCode::NoError);
1231 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1232 BOOST_CHECK(ret[0].d_type == QType::A);
1233 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1234 BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 1U);
1235 BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1U);
1236 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
1237 BOOST_CHECK_EQUAL(entry.second, 0u);
1238 }
1239 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
1240 BOOST_CHECK_EQUAL(entry.second, entry.first == 55 ? 1U : 0U);
1241 }
1242 }
1243
1244 BOOST_AUTO_TEST_CASE(test_ecs_use_requestor)
1245 {
1246 std::unique_ptr<SyncRes> sr;
1247 initSR(sr);
1248
1249 primeHints();
1250
1251 const DNSName target("powerdns.com.");
1252 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1253 // No incoming ECS data
1254 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1255
1256 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 */) {
1257 if (isRootServer(address)) {
1258 BOOST_REQUIRE(!srcmask);
1259
1260 setLWResult(res, 0, false, false, true);
1261 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1262 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1263 return LWResult::Result::Success;
1264 }
1265 if (address == ComboAddress("192.0.2.1:53")) {
1266
1267 BOOST_REQUIRE(srcmask);
1268 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1269
1270 setLWResult(res, 0, true, false, false);
1271 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1272 return LWResult::Result::Success;
1273 }
1274
1275 return LWResult::Result::Timeout;
1276 });
1277
1278 vector<DNSRecord> ret;
1279 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1280 BOOST_CHECK_EQUAL(res, RCode::NoError);
1281 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1282 BOOST_CHECK(ret[0].d_type == QType::A);
1283 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1284 }
1285
1286 BOOST_AUTO_TEST_CASE(test_ecs_use_scope_zero)
1287 {
1288 std::unique_ptr<SyncRes> sr;
1289 initSR(sr);
1290
1291 primeHints();
1292
1293 const DNSName target("powerdns.com.");
1294 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1295 SyncRes::clearEDNSLocalSubnets();
1296 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1297 // No incoming ECS data, Requestor IP not in ecs-add-for
1298 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1299
1300 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 */) {
1301 if (isRootServer(address)) {
1302 BOOST_REQUIRE(!srcmask);
1303
1304 setLWResult(res, 0, false, false, true);
1305 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1306 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1307 return LWResult::Result::Success;
1308 }
1309 if (address == ComboAddress("192.0.2.1:53")) {
1310
1311 BOOST_REQUIRE(srcmask);
1312 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
1313
1314 setLWResult(res, 0, true, false, false);
1315 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1316 return LWResult::Result::Success;
1317 }
1318
1319 return LWResult::Result::Timeout;
1320 });
1321
1322 vector<DNSRecord> ret;
1323 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1324 BOOST_CHECK_EQUAL(res, RCode::NoError);
1325 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1326 BOOST_CHECK(ret[0].d_type == QType::A);
1327 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1328 }
1329
1330 BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask)
1331 {
1332 std::unique_ptr<SyncRes> sr;
1333 initSR(sr);
1334
1335 primeHints();
1336
1337 const DNSName target("powerdns.com.");
1338 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1339 SyncRes::clearEDNSLocalSubnets();
1340 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1341 EDNSSubnetOpts incomingECS;
1342 incomingECS.source = Netmask("192.0.0.0/16");
1343 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1344
1345 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 */) {
1346 if (isRootServer(address)) {
1347 BOOST_REQUIRE(!srcmask);
1348
1349 setLWResult(res, 0, false, false, true);
1350 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1351 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1352 return LWResult::Result::Success;
1353 }
1354 if (address == ComboAddress("192.0.2.1:53")) {
1355
1356 BOOST_REQUIRE(srcmask);
1357 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.0.0/16");
1358
1359 setLWResult(res, 0, true, false, false);
1360 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1361 return LWResult::Result::Success;
1362 }
1363
1364 return LWResult::Result::Timeout;
1365 });
1366
1367 vector<DNSRecord> ret;
1368 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1369 BOOST_CHECK_EQUAL(res, RCode::NoError);
1370 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1371 BOOST_CHECK(ret[0].d_type == QType::A);
1372 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1373 }
1374
1375 BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask_zero)
1376 {
1377 std::unique_ptr<SyncRes> sr;
1378 initSR(sr);
1379
1380 primeHints();
1381
1382 const DNSName target("powerdns.com.");
1383 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1384 SyncRes::clearEDNSLocalSubnets();
1385 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1386 EDNSSubnetOpts incomingECS;
1387 incomingECS.source = Netmask("0.0.0.0/0");
1388 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1389
1390 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 */) {
1391 if (isRootServer(address)) {
1392 BOOST_REQUIRE(!srcmask);
1393
1394 setLWResult(res, 0, false, false, true);
1395 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1396 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1397 return LWResult::Result::Success;
1398 }
1399 if (address == ComboAddress("192.0.2.1:53")) {
1400
1401 BOOST_REQUIRE(srcmask);
1402 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
1403
1404 setLWResult(res, 0, true, false, false);
1405 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1406 return LWResult::Result::Success;
1407 }
1408
1409 return LWResult::Result::Timeout;
1410 });
1411
1412 vector<DNSRecord> ret;
1413 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1414 BOOST_CHECK_EQUAL(res, RCode::NoError);
1415 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1416 BOOST_CHECK(ret[0].d_type == QType::A);
1417 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1418 }
1419
1420 BOOST_AUTO_TEST_CASE(test_following_cname)
1421 {
1422 std::unique_ptr<SyncRes> sr;
1423 initSR(sr);
1424
1425 primeHints();
1426
1427 const DNSName target("cname.powerdns.com.");
1428 const DNSName cnameTarget("cname-target.powerdns.com");
1429
1430 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 */) {
1431 if (isRootServer(address)) {
1432 setLWResult(res, 0, false, false, true);
1433 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1434 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1435 return LWResult::Result::Success;
1436 }
1437 if (address == ComboAddress("192.0.2.1:53")) {
1438
1439 if (domain == target) {
1440 setLWResult(res, 0, true, false, false);
1441 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1442 return LWResult::Result::Success;
1443 }
1444 if (domain == cnameTarget) {
1445 setLWResult(res, 0, true, false, false);
1446 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1447 }
1448
1449 return LWResult::Result::Success;
1450 }
1451
1452 return LWResult::Result::Timeout;
1453 });
1454
1455 vector<DNSRecord> ret;
1456 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1457 BOOST_CHECK_EQUAL(res, RCode::NoError);
1458 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1459 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1460 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1461 BOOST_CHECK(ret[1].d_type == QType::A);
1462 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1463 }
1464
1465 BOOST_AUTO_TEST_CASE(test_cname_nxdomain)
1466 {
1467 std::unique_ptr<SyncRes> sr;
1468 initSR(sr);
1469
1470 primeHints();
1471
1472 const DNSName target("cname.powerdns.com.");
1473 const DNSName cnameTarget("cname-target.powerdns.com");
1474
1475 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 */) {
1476 if (isRootServer(address)) {
1477 setLWResult(res, 0, false, false, true);
1478 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1479 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1480 return LWResult::Result::Success;
1481 }
1482 if (address == ComboAddress("192.0.2.1:53")) {
1483
1484 if (domain == target) {
1485 setLWResult(res, RCode::NXDomain, true, false, false);
1486 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1487 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1488 }
1489 else if (domain == cnameTarget) {
1490 setLWResult(res, RCode::NXDomain, true, false, false);
1491 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1492 return LWResult::Result::Success;
1493 }
1494
1495 return LWResult::Result::Success;
1496 }
1497
1498 return LWResult::Result::Timeout;
1499 });
1500
1501 vector<DNSRecord> ret;
1502 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1503 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1504 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1505 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1506 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1507 BOOST_CHECK(ret[1].d_type == QType::SOA);
1508
1509 /* a second time, to check the cache */
1510 ret.clear();
1511 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1512 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1513 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1514 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1515 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1516 BOOST_CHECK(ret[1].d_type == QType::SOA);
1517 }
1518
1519 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname)
1520 {
1521 std::unique_ptr<SyncRes> sr;
1522 initSR(sr);
1523
1524 primeHints();
1525
1526 /* In this test we directly get the NS server for cname.powerdns.com.,
1527 and we don't know whether it's also authoritative for
1528 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1529 the additional A record for cname-target.powerdns.com. */
1530 const DNSName target("cname.powerdns.com.");
1531 const DNSName cnameTarget("cname-target.powerdns.com");
1532
1533 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 */) {
1534 if (isRootServer(address)) {
1535
1536 setLWResult(res, 0, false, false, true);
1537
1538 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1539 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1540 return LWResult::Result::Success;
1541 }
1542 if (address == ComboAddress("192.0.2.1:53")) {
1543
1544 if (domain == target) {
1545 setLWResult(res, 0, true, false, false);
1546 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1547 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1548 return LWResult::Result::Success;
1549 }
1550 if (domain == cnameTarget) {
1551 setLWResult(res, 0, true, false, false);
1552 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1553 return LWResult::Result::Success;
1554 }
1555
1556 return LWResult::Result::Success;
1557 }
1558
1559 return LWResult::Result::Timeout;
1560 });
1561
1562 vector<DNSRecord> ret;
1563 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1564 BOOST_CHECK_EQUAL(res, RCode::NoError);
1565 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1566 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1567 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1568 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1569 BOOST_REQUIRE(ret[1].d_type == QType::A);
1570 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1571 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1572 }
1573
1574 BOOST_AUTO_TEST_CASE(test_cname_loop)
1575 {
1576 std::unique_ptr<SyncRes> sr;
1577 initSR(sr);
1578
1579 primeHints();
1580
1581 size_t count = 0;
1582 const DNSName target("cname.powerdns.com.");
1583
1584 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 */) {
1585 count++;
1586
1587 if (isRootServer(address)) {
1588
1589 setLWResult(res, 0, false, false, true);
1590 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1591 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1592 return LWResult::Result::Success;
1593 }
1594 if (address == ComboAddress("192.0.2.1:53")) {
1595
1596 if (domain == target) {
1597 setLWResult(res, 0, true, false, false);
1598 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1599 return LWResult::Result::Success;
1600 }
1601
1602 return LWResult::Result::Success;
1603 }
1604
1605 return LWResult::Result::Timeout;
1606 });
1607
1608 vector<DNSRecord> ret;
1609 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1610 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1611 BOOST_CHECK_EQUAL(ret.size(), 0U);
1612 BOOST_CHECK_EQUAL(count, 2U);
1613
1614 // Again to check cache
1615 try {
1616 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1617 BOOST_CHECK(false);
1618 }
1619 catch (const ImmediateServFailException& ex) {
1620 BOOST_CHECK(true);
1621 }
1622 }
1623
1624 BOOST_AUTO_TEST_CASE(test_cname_loop_forwarder)
1625 {
1626 std::unique_ptr<SyncRes> resolver;
1627 initSR(resolver);
1628
1629 primeHints();
1630
1631 size_t count = 0;
1632 const DNSName target("cname.powerdns.com.");
1633 const DNSName cname1("cname1.cname.powerdns.com.");
1634 const DNSName cname2("cname2.cname.powerdns.com.");
1635
1636 SyncRes::AuthDomain ad;
1637 const std::vector<ComboAddress> forwardedNSs{ComboAddress("192.0.2.42:53")};
1638 ad.d_rdForward = true;
1639 ad.d_servers = forwardedNSs;
1640 (*SyncRes::t_sstorage.domainmap)[target] = ad;
1641
1642 resolver->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 */) {
1643 count++;
1644
1645 if (isRootServer(address)) {
1646
1647 setLWResult(res, 0, false, false, true);
1648 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1649 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1650 return LWResult::Result::Success;
1651 }
1652 if (address == ComboAddress("192.0.2.42:53")) {
1653
1654 if (domain == target) {
1655 setLWResult(res, 0, true, false, false);
1656 addRecordToLW(res, domain, QType::CNAME, cname1.toString());
1657 addRecordToLW(res, cname1, QType::CNAME, cname2.toString());
1658 addRecordToLW(res, cname2, QType::CNAME, domain.toString());
1659 return LWResult::Result::Success;
1660 }
1661
1662 return LWResult::Result::Success;
1663 }
1664
1665 return LWResult::Result::Timeout;
1666 });
1667
1668 vector<DNSRecord> ret;
1669 BOOST_REQUIRE_THROW(resolver->beginResolve(target, QType(QType::A), QClass::IN, ret), ImmediateServFailException);
1670 }
1671
1672 BOOST_AUTO_TEST_CASE(test_cname_long_loop)
1673 {
1674 std::unique_ptr<SyncRes> sr;
1675 initSR(sr);
1676
1677 primeHints();
1678
1679 size_t count = 0;
1680 const DNSName target1("cname1.powerdns.com.");
1681 const DNSName target2("cname2.powerdns.com.");
1682 const DNSName target3("cname3.powerdns.com.");
1683 const DNSName target4("cname4.powerdns.com.");
1684
1685 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 */) {
1686 count++;
1687
1688 if (isRootServer(address)) {
1689
1690 setLWResult(res, 0, false, false, true);
1691 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1692 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1693 return LWResult::Result::Success;
1694 }
1695 if (address == ComboAddress("192.0.2.1:53")) {
1696
1697 if (domain == target1) {
1698 setLWResult(res, 0, true, false, false);
1699 addRecordToLW(res, domain, QType::CNAME, target2.toString());
1700 return LWResult::Result::Success;
1701 }
1702 if (domain == target2) {
1703 setLWResult(res, 0, true, false, false);
1704 addRecordToLW(res, domain, QType::CNAME, target3.toString());
1705 return LWResult::Result::Success;
1706 }
1707 if (domain == target3) {
1708 setLWResult(res, 0, true, false, false);
1709 addRecordToLW(res, domain, QType::CNAME, target4.toString());
1710 return LWResult::Result::Success;
1711 }
1712 if (domain == target4) {
1713 setLWResult(res, 0, true, false, false);
1714 addRecordToLW(res, domain, QType::CNAME, target1.toString());
1715 return LWResult::Result::Success;
1716 }
1717
1718 return LWResult::Result::Success;
1719 }
1720
1721 return LWResult::Result::Timeout;
1722 });
1723
1724 vector<DNSRecord> ret;
1725 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1726 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1727 BOOST_CHECK_EQUAL(ret.size(), 0U);
1728 BOOST_CHECK_EQUAL(count, 8U);
1729
1730 // And again to check cache
1731 try {
1732 sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1733 BOOST_CHECK(false);
1734 }
1735 catch (const ImmediateServFailException& ex) {
1736 BOOST_CHECK(true);
1737 }
1738 }
1739
1740 BOOST_AUTO_TEST_CASE(test_cname_length)
1741 {
1742 std::unique_ptr<SyncRes> sr;
1743 initSR(sr);
1744
1745 primeHints();
1746
1747 size_t length = 0;
1748 const DNSName target("cname.powerdns.com.");
1749
1750 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 */) {
1751 if (isRootServer(address)) {
1752
1753 setLWResult(res, 0, false, false, true);
1754 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1755 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1756 return LWResult::Result::Success;
1757 }
1758 if (address == ComboAddress("192.0.2.1:53")) {
1759
1760 setLWResult(res, 0, true, false, false);
1761 addRecordToLW(res, domain, QType::CNAME, std::to_string(length) + "-cname.powerdns.com");
1762 length++;
1763 return LWResult::Result::Success;
1764 }
1765
1766 return LWResult::Result::Timeout;
1767 });
1768
1769 vector<DNSRecord> ret;
1770 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1771 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1772 BOOST_CHECK_EQUAL(ret.size(), length);
1773 BOOST_CHECK_EQUAL(length, SyncRes::s_max_CNAMES_followed + 1);
1774 }
1775
1776 BOOST_AUTO_TEST_CASE(test_cname_target_servfail)
1777 {
1778 std::unique_ptr<SyncRes> resolver;
1779 initSR(resolver);
1780
1781 primeHints();
1782
1783 const DNSName target("cname.powerdns.com.");
1784 const DNSName cnameTarget("cname-target.powerdns.com");
1785
1786 resolver->setAsyncCallback([&](const ComboAddress& ipAddress, 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 */) {
1787 if (isRootServer(ipAddress)) {
1788 setLWResult(res, 0, false, false, true);
1789 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1790 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1791 return LWResult::Result::Success;
1792 }
1793 if (ipAddress == ComboAddress("192.0.2.1:53")) {
1794
1795 if (domain == target) {
1796 setLWResult(res, 0, true, false, false);
1797 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1798 return LWResult::Result::Success;
1799 }
1800 if (domain == cnameTarget) {
1801 return LWResult::Result::PermanentError;
1802 }
1803
1804 return LWResult::Result::Success;
1805 }
1806
1807 return LWResult::Result::Timeout;
1808 });
1809
1810 vector<DNSRecord> ret;
1811 int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
1812 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1813 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1814 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1815 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1816 }
1817
1818 BOOST_AUTO_TEST_CASE(test_cname_target_servfail_servestale)
1819 {
1820 std::unique_ptr<SyncRes> resolver;
1821 initSR(resolver);
1822 MemRecursorCache::s_maxServedStaleExtensions = 1440;
1823
1824 primeHints();
1825
1826 const DNSName target("cname.powerdns.com.");
1827 const DNSName cnameTarget("cname-target.powerdns.com");
1828
1829 resolver->setAsyncCallback([&](const ComboAddress& ipAddress, 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 */) {
1830 if (isRootServer(ipAddress)) {
1831 setLWResult(res, 0, false, false, true);
1832 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1833 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1834 return LWResult::Result::Success;
1835 }
1836 if (ipAddress == ComboAddress("192.0.2.1:53")) {
1837
1838 if (domain == target) {
1839 setLWResult(res, 0, true, false, false);
1840 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1841 return LWResult::Result::Success;
1842 }
1843 if (domain == cnameTarget) {
1844 return LWResult::Result::PermanentError;
1845 }
1846
1847 return LWResult::Result::Success;
1848 }
1849
1850 return LWResult::Result::Timeout;
1851 });
1852
1853 vector<DNSRecord> ret;
1854 int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
1855 // different compared no non-servestale case (returns ServFail), handled by pdns_recursor
1856 BOOST_CHECK_EQUAL(res, -1);
1857 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1858 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1859 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1860 }
1861
1862 BOOST_AUTO_TEST_CASE(test_time_limit)
1863 {
1864 std::unique_ptr<SyncRes> sr;
1865 initSR(sr);
1866
1867 primeHints();
1868
1869 size_t queries = 0;
1870 const DNSName target("cname.powerdns.com.");
1871
1872 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 */) {
1873 queries++;
1874
1875 if (isRootServer(address)) {
1876 setLWResult(res, 0, false, false, true);
1877 /* Pretend that this query took 2000 ms */
1878 res->d_usec = 2000;
1879
1880 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1881 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1882 return LWResult::Result::Success;
1883 }
1884 if (address == ComboAddress("192.0.2.1:53")) {
1885
1886 setLWResult(res, 0, true, false, false);
1887 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1888 return LWResult::Result::Success;
1889 }
1890
1891 return LWResult::Result::Timeout;
1892 });
1893
1894 /* Set the maximum time to 1 ms */
1895 SyncRes::s_maxtotusec = 1000;
1896
1897 try {
1898 vector<DNSRecord> ret;
1899 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1900 BOOST_CHECK(false);
1901 }
1902 catch (const ImmediateServFailException& e) {
1903 }
1904 BOOST_CHECK_EQUAL(queries, 1U);
1905 }
1906
1907 BOOST_AUTO_TEST_CASE(test_dname_processing)
1908 {
1909 std::unique_ptr<SyncRes> sr;
1910 initSR(sr);
1911
1912 primeHints();
1913
1914 const DNSName dnameOwner("powerdns.com");
1915 const DNSName dnameTarget("powerdns.net");
1916
1917 const DNSName target("dname.powerdns.com.");
1918 const DNSName cnameTarget("dname.powerdns.net");
1919
1920 const DNSName uncachedTarget("dname-uncached.powerdns.com.");
1921 const DNSName uncachedCNAMETarget("dname-uncached.powerdns.net.");
1922
1923 const DNSName synthCNAME("cname-uncached.powerdns.com.");
1924 const DNSName synthCNAMETarget("cname-uncached.powerdns.net.");
1925
1926 size_t queries = 0;
1927
1928 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 */) {
1929 queries++;
1930
1931 if (isRootServer(address)) {
1932 if (domain.isPartOf(dnameOwner)) {
1933 setLWResult(res, 0, false, false, true);
1934 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1935 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1936 return LWResult::Result::Success;
1937 }
1938 if (domain.isPartOf(dnameTarget)) {
1939 setLWResult(res, 0, false, false, true);
1940 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1941 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1942 return LWResult::Result::Success;
1943 }
1944 }
1945 else if (address == ComboAddress("192.0.2.1:53")) {
1946 if (domain == target) {
1947 setLWResult(res, 0, true, false, false);
1948 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
1949 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1950 return LWResult::Result::Success;
1951 }
1952 }
1953 else if (address == ComboAddress("192.0.2.2:53")) {
1954 if (domain == cnameTarget) {
1955 setLWResult(res, 0, true, false, false);
1956 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1957 }
1958 if (domain == uncachedCNAMETarget) {
1959 setLWResult(res, 0, true, false, false);
1960 addRecordToLW(res, domain, QType::A, "192.0.2.3");
1961 }
1962 return LWResult::Result::Success;
1963 }
1964 return LWResult::Result::Timeout;
1965 });
1966
1967 vector<DNSRecord> ret;
1968 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1969
1970 BOOST_CHECK_EQUAL(res, RCode::NoError);
1971 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1972
1973 BOOST_CHECK_EQUAL(queries, 4u);
1974
1975 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1976 BOOST_CHECK(ret[0].d_name == dnameOwner);
1977 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1978
1979 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1980 BOOST_CHECK_EQUAL(ret[1].d_name, target);
1981
1982 BOOST_CHECK(ret[2].d_type == QType::A);
1983 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
1984
1985 // Now check the cache
1986 ret.clear();
1987 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1988
1989 BOOST_CHECK_EQUAL(res, RCode::NoError);
1990 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1991
1992 BOOST_CHECK_EQUAL(queries, 4U);
1993
1994 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1995 BOOST_CHECK(ret[0].d_name == dnameOwner);
1996 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1997
1998 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1999 BOOST_CHECK_EQUAL(ret[1].d_name, target);
2000
2001 BOOST_CHECK(ret[2].d_type == QType::A);
2002 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2003
2004 // Check if we correctly return a synthesized CNAME, should send out just 1 more query
2005 ret.clear();
2006 res = sr->beginResolve(uncachedTarget, QType(QType::A), QClass::IN, ret);
2007
2008 BOOST_CHECK_EQUAL(res, RCode::NoError);
2009 BOOST_CHECK_EQUAL(queries, 5U);
2010
2011 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2012 BOOST_CHECK(ret[0].d_name == dnameOwner);
2013 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2014
2015 BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
2016 BOOST_CHECK_EQUAL(ret[1].d_name, uncachedTarget);
2017 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), uncachedCNAMETarget);
2018
2019 BOOST_CHECK(ret[2].d_type == QType::A);
2020 BOOST_CHECK_EQUAL(ret[2].d_name, uncachedCNAMETarget);
2021
2022 // Check if we correctly return the DNAME from cache when asked
2023 ret.clear();
2024 res = sr->beginResolve(dnameOwner, QType(QType::DNAME), QClass::IN, ret);
2025 BOOST_CHECK_EQUAL(res, RCode::NoError);
2026 BOOST_CHECK_EQUAL(queries, 5U);
2027
2028 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2029 BOOST_CHECK(ret[0].d_name == dnameOwner);
2030 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2031
2032 // Check if we correctly return the synthesized CNAME from cache when asked
2033 ret.clear();
2034 res = sr->beginResolve(synthCNAME, QType(QType::CNAME), QClass::IN, ret);
2035 BOOST_CHECK_EQUAL(res, RCode::NoError);
2036 BOOST_CHECK_EQUAL(queries, 5U);
2037
2038 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2039 BOOST_CHECK(ret[0].d_name == dnameOwner);
2040 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2041
2042 BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
2043 BOOST_CHECK(ret[1].d_name == synthCNAME);
2044 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), synthCNAMETarget);
2045 }
2046
2047 BOOST_AUTO_TEST_CASE(test_dname_dnssec_secure)
2048 {
2049 std::unique_ptr<SyncRes> sr;
2050 initSR(sr, true);
2051 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2052
2053 primeHints();
2054
2055 const DNSName dnameOwner("powerdns");
2056 const DNSName dnameTarget("example");
2057
2058 const DNSName target("dname.powerdns");
2059 const DNSName cnameTarget("dname.example");
2060
2061 testkeysset_t keys;
2062
2063 auto luaconfsCopy = g_luaconfs.getCopy();
2064 luaconfsCopy.dsAnchors.clear();
2065 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2066 generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2067 generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2068 g_luaconfs.setState(luaconfsCopy);
2069
2070 size_t queries = 0;
2071
2072 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 */) {
2073 queries++;
2074 /* We don't use the genericDSAndDNSKEYHandler here, as it would deny names existing at the wrong level of the tree, due to the way computeZoneCuts works
2075 * As such, we need to do some more work to make the answers correct.
2076 */
2077
2078 if (isRootServer(address)) {
2079 if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
2080 setLWResult(res, 0, true, false, true);
2081 addDNSKEY(keys, domain, 300, res->d_records);
2082 addRRSIG(keys, res->d_records, DNSName("."), 300);
2083 return LWResult::Result::Success;
2084 }
2085 if (domain.countLabels() == 1 && type == QType::DS) { // powerdns|DS or example|DS
2086 setLWResult(res, 0, true, false, true);
2087 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2088 addRRSIG(keys, res->d_records, DNSName("."), 300);
2089 return LWResult::Result::Success;
2090 }
2091 // For the rest, delegate!
2092 if (domain.isPartOf(dnameOwner)) {
2093 setLWResult(res, 0, false, false, true);
2094 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2095 addDS(dnameOwner, 300, res->d_records, keys);
2096 addRRSIG(keys, res->d_records, DNSName("."), 300);
2097 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2098 return LWResult::Result::Success;
2099 }
2100 if (domain.isPartOf(dnameTarget)) {
2101 setLWResult(res, 0, false, false, true);
2102 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2103 addDS(dnameTarget, 300, res->d_records, keys);
2104 addRRSIG(keys, res->d_records, DNSName("."), 300);
2105 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2106 return LWResult::Result::Success;
2107 }
2108 }
2109 else if (address == ComboAddress("192.0.2.1:53")) {
2110 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
2111 setLWResult(res, 0, true, false, true);
2112 addDNSKEY(keys, domain, 300, res->d_records);
2113 addRRSIG(keys, res->d_records, domain, 300);
2114 return LWResult::Result::Success;
2115 }
2116 if (domain == target && type == QType::DS) { // dname.powerdns|DS
2117 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
2118 }
2119 if (domain == target) {
2120 setLWResult(res, 0, true, false, false);
2121 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2122 addRRSIG(keys, res->d_records, dnameOwner, 300);
2123 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2124 return LWResult::Result::Success;
2125 }
2126 }
2127 else if (address == ComboAddress("192.0.2.2:53")) {
2128 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // example|DNSKEY
2129 setLWResult(res, 0, true, false, true);
2130 addDNSKEY(keys, domain, 300, res->d_records);
2131 addRRSIG(keys, res->d_records, domain, 300);
2132 return LWResult::Result::Success;
2133 }
2134 if (domain == cnameTarget && type == QType::DS) { // dname.example|DS
2135 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
2136 }
2137 if (domain == cnameTarget) {
2138 setLWResult(res, 0, true, false, false);
2139 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2140 addRRSIG(keys, res->d_records, dnameTarget, 300);
2141 }
2142 return LWResult::Result::Success;
2143 }
2144 return LWResult::Result::Timeout;
2145 });
2146
2147 vector<DNSRecord> ret;
2148 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2149
2150 BOOST_CHECK_EQUAL(res, RCode::NoError);
2151 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2152 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2153
2154 BOOST_CHECK_EQUAL(queries, 7U);
2155
2156 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2157 BOOST_CHECK(ret[0].d_name == dnameOwner);
2158 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2159
2160 BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2161 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2162
2163 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2164 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2165
2166 BOOST_CHECK(ret[3].d_type == QType::A);
2167 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2168
2169 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2170 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2171
2172 // And the cache
2173 ret.clear();
2174 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2175
2176 BOOST_CHECK_EQUAL(res, RCode::NoError);
2177 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2178 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2179
2180 BOOST_CHECK_EQUAL(queries, 7U);
2181
2182 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2183 BOOST_CHECK(ret[0].d_name == dnameOwner);
2184 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2185
2186 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2187 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2188
2189 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2190 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2191
2192 BOOST_CHECK(ret[3].d_type == QType::A);
2193 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2194
2195 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2196 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2197 }
2198
2199 BOOST_AUTO_TEST_CASE(test_dname_plus_ns_dnssec_secure)
2200 {
2201 std::unique_ptr<SyncRes> sr;
2202 initSR(sr, true);
2203 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2204
2205 primeHints();
2206
2207 const DNSName dnameOwner("powerdns");
2208 const DNSName dnameTarget("example");
2209
2210 const DNSName target("dname.powerdns");
2211 const DNSName cnameTarget("dname.example");
2212
2213 testkeysset_t keys;
2214
2215 auto luaconfsCopy = g_luaconfs.getCopy();
2216 luaconfsCopy.dsAnchors.clear();
2217 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2218 generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2219 g_luaconfs.setState(luaconfsCopy);
2220
2221 size_t queries = 0;
2222
2223 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 */) {
2224 queries++;
2225
2226 if (type == QType::DS || type == QType::DNSKEY) {
2227 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
2228 }
2229
2230 if (domain.isPartOf(dnameOwner)) {
2231 setLWResult(res, 0, true, false, true);
2232 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2233 addRRSIG(keys, res->d_records, DNSName("."), 300);
2234 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2235
2236 addRecordToLW(res, dnameTarget, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2237 addDS(dnameTarget, 300, res->d_records, keys);
2238 addRRSIG(keys, res->d_records, DNSName("."), 300);
2239 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2240 return LWResult::Result::Success;
2241 }
2242 if (domain == cnameTarget) {
2243 setLWResult(res, 0, true, false, true);
2244 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2245 addRRSIG(keys, res->d_records, dnameTarget, 300);
2246 return LWResult::Result::Success;
2247 }
2248 return LWResult::Result::Timeout;
2249 });
2250
2251 vector<DNSRecord> ret;
2252 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2253
2254 BOOST_CHECK_EQUAL(res, RCode::NoError);
2255 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2256 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2257
2258 BOOST_CHECK_EQUAL(queries, 4U);
2259
2260 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2261 BOOST_CHECK(ret[0].d_name == dnameOwner);
2262 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2263
2264 BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2265 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2266
2267 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2268 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2269
2270 BOOST_CHECK(ret[3].d_type == QType::A);
2271 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2272
2273 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2274 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2275
2276 // And the cache
2277 ret.clear();
2278 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2279
2280 BOOST_CHECK_EQUAL(res, RCode::NoError);
2281 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2282 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2283
2284 BOOST_CHECK_EQUAL(queries, 4U);
2285
2286 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2287 BOOST_CHECK(ret[0].d_name == dnameOwner);
2288 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2289
2290 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2291 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2292
2293 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2294 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2295
2296 BOOST_CHECK(ret[3].d_type == QType::A);
2297 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2298
2299 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2300 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2301 }
2302
2303 BOOST_AUTO_TEST_CASE(test_dname_dnssec_insecure)
2304 {
2305 /*
2306 * The DNAME itself is signed, but the final A record is not
2307 */
2308 std::unique_ptr<SyncRes> sr;
2309 initSR(sr, true);
2310 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2311
2312 primeHints();
2313
2314 const DNSName dnameOwner("powerdns");
2315 const DNSName dnameTarget("example");
2316
2317 const DNSName target("dname.powerdns");
2318 const DNSName cnameTarget("dname.example");
2319
2320 testkeysset_t keys;
2321
2322 auto luaconfsCopy = g_luaconfs.getCopy();
2323 luaconfsCopy.dsAnchors.clear();
2324 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2325 generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2326 g_luaconfs.setState(luaconfsCopy);
2327
2328 size_t queries = 0;
2329
2330 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 */) {
2331 queries++;
2332
2333 if (isRootServer(address)) {
2334 if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
2335 setLWResult(res, 0, true, false, true);
2336 addDNSKEY(keys, domain, 300, res->d_records);
2337 addRRSIG(keys, res->d_records, DNSName("."), 300);
2338 return LWResult::Result::Success;
2339 }
2340 if (domain == dnameOwner && type == QType::DS) { // powerdns|DS
2341 setLWResult(res, 0, true, false, true);
2342 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2343 addRRSIG(keys, res->d_records, DNSName("."), 300);
2344 return LWResult::Result::Success;
2345 }
2346 if (domain == dnameTarget && type == QType::DS) { // example|DS
2347 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
2348 }
2349 // For the rest, delegate!
2350 if (domain.isPartOf(dnameOwner)) {
2351 setLWResult(res, 0, false, false, true);
2352 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2353 addDS(dnameOwner, 300, res->d_records, keys);
2354 addRRSIG(keys, res->d_records, DNSName("."), 300);
2355 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2356 return LWResult::Result::Success;
2357 }
2358 if (domain.isPartOf(dnameTarget)) {
2359 setLWResult(res, 0, false, false, true);
2360 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2361 addDS(dnameTarget, 300, res->d_records, keys);
2362 addRRSIG(keys, res->d_records, DNSName("."), 300);
2363 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2364 return LWResult::Result::Success;
2365 }
2366 }
2367 else if (address == ComboAddress("192.0.2.1:53")) {
2368 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
2369 setLWResult(res, 0, true, false, true);
2370 addDNSKEY(keys, domain, 300, res->d_records);
2371 addRRSIG(keys, res->d_records, domain, 300);
2372 return LWResult::Result::Success;
2373 }
2374 if (domain == target && type == QType::DS) { // dname.powerdns|DS
2375 return genericDSAndDNSKEYHandler(res, domain, dnameOwner, type, keys, false);
2376 }
2377 if (domain == target) {
2378 setLWResult(res, 0, true, false, false);
2379 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2380 addRRSIG(keys, res->d_records, dnameOwner, 300);
2381 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2382 return LWResult::Result::Success;
2383 }
2384 }
2385 else if (address == ComboAddress("192.0.2.2:53")) {
2386 if (domain == target && type == QType::DS) { // dname.example|DS
2387 return genericDSAndDNSKEYHandler(res, domain, dnameTarget, type, keys, false);
2388 }
2389 if (domain == cnameTarget) {
2390 setLWResult(res, 0, true, false, false);
2391 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2392 }
2393 return LWResult::Result::Success;
2394 }
2395 return LWResult::Result::Timeout;
2396 });
2397
2398 vector<DNSRecord> ret;
2399 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2400
2401 BOOST_CHECK_EQUAL(res, RCode::NoError);
2402 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2403 BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2404
2405 BOOST_CHECK_EQUAL(queries, 7U);
2406
2407 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2408 BOOST_CHECK(ret[0].d_name == dnameOwner);
2409 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2410
2411 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2412 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2413
2414 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2415 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2416
2417 BOOST_CHECK(ret[3].d_type == QType::A);
2418 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2419
2420 // And the cache
2421 ret.clear();
2422 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2423
2424 BOOST_CHECK_EQUAL(res, RCode::NoError);
2425 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2426 BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2427
2428 BOOST_CHECK_EQUAL(queries, 7U);
2429
2430 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2431 BOOST_CHECK(ret[0].d_name == dnameOwner);
2432 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2433
2434 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2435 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2436
2437 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2438 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2439
2440 BOOST_CHECK(ret[3].d_type == QType::A);
2441 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2442 }
2443
2444 BOOST_AUTO_TEST_CASE(test_dname_processing_no_CNAME)
2445 {
2446 std::unique_ptr<SyncRes> sr;
2447 initSR(sr);
2448
2449 primeHints();
2450
2451 const DNSName dnameOwner("powerdns.com");
2452 const DNSName dnameTarget("powerdns.net");
2453
2454 const DNSName target("dname.powerdns.com.");
2455 const DNSName cnameTarget("dname.powerdns.net");
2456
2457 size_t queries = 0;
2458
2459 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 */) {
2460 queries++;
2461
2462 if (isRootServer(address)) {
2463 if (domain.isPartOf(dnameOwner)) {
2464 setLWResult(res, 0, false, false, true);
2465 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2466 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2467 return LWResult::Result::Success;
2468 }
2469 if (domain.isPartOf(dnameTarget)) {
2470 setLWResult(res, 0, false, false, true);
2471 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2472 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2473 return LWResult::Result::Success;
2474 }
2475 }
2476 else if (address == ComboAddress("192.0.2.1:53")) {
2477 if (domain == target) {
2478 setLWResult(res, 0, true, false, false);
2479 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2480 // No CNAME, recursor should synth
2481 return LWResult::Result::Success;
2482 }
2483 }
2484 else if (address == ComboAddress("192.0.2.2:53")) {
2485 if (domain == cnameTarget) {
2486 setLWResult(res, 0, true, false, false);
2487 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2488 }
2489 return LWResult::Result::Success;
2490 }
2491 return LWResult::Result::Timeout;
2492 });
2493
2494 vector<DNSRecord> ret;
2495 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2496
2497 BOOST_CHECK_EQUAL(res, RCode::NoError);
2498 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2499
2500 BOOST_CHECK_EQUAL(queries, 4U);
2501
2502 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2503 BOOST_CHECK(ret[0].d_name == dnameOwner);
2504 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2505
2506 BOOST_CHECK(ret[1].d_type == QType::CNAME);
2507 BOOST_CHECK_EQUAL(ret[1].d_name, target);
2508
2509 BOOST_CHECK(ret[2].d_type == QType::A);
2510 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2511
2512 // Now check the cache
2513 ret.clear();
2514 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2515
2516 BOOST_CHECK_EQUAL(res, RCode::NoError);
2517 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2518
2519 BOOST_CHECK_EQUAL(queries, 4U);
2520
2521 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2522 BOOST_CHECK(ret[0].d_name == dnameOwner);
2523 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2524
2525 BOOST_CHECK(ret[1].d_type == QType::CNAME);
2526 BOOST_CHECK_EQUAL(ret[1].d_name, target);
2527
2528 BOOST_CHECK(ret[2].d_type == QType::A);
2529 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2530 }
2531
2532 /*
2533 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2534
2535 - check out of band support
2536
2537 - check preoutquery
2538
2539 */
2540
2541 BOOST_AUTO_TEST_CASE(test_glued_referral_child_ns_set_wrong)
2542 {
2543 std::unique_ptr<SyncRes> sr;
2544 initSR(sr);
2545
2546 primeHints();
2547
2548 const DNSName target("powerdns.com.");
2549
2550 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 */) {
2551 /* this will cause issue with qname minimization if we ever implement it */
2552 if (domain != target) {
2553 return LWResult::Result::Timeout;
2554 }
2555
2556 if (isRootServer(address)) {
2557 setLWResult(res, 0, false, false, true);
2558 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2559 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2560 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2561 return LWResult::Result::Success;
2562 }
2563 if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
2564 setLWResult(res, 0, false, false, true);
2565 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2566 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2567 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2568 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2569 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2570 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2571 return LWResult::Result::Success;
2572 }
2573 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")) {
2574
2575 if (type == QType::A) {
2576 setLWResult(res, 0, true, false, true);
2577 addRecordToLW(res, target, QType::A, "192.0.2.4");
2578 return LWResult::Result::Success;
2579 }
2580 if (type == QType::NS) {
2581 setLWResult(res, 0, true, false, true);
2582 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX1.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2583 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX2.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2584 addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::A, "192.0.2.11", DNSResourceRecord::ADDITIONAL, 172800);
2585 addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::AAAA, "2001:DB8::11", DNSResourceRecord::ADDITIONAL, 172800);
2586 addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::A, "192.0.2.12", DNSResourceRecord::ADDITIONAL, 172800);
2587 addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::AAAA, "2001:DB8::12", DNSResourceRecord::ADDITIONAL, 172800);
2588 return LWResult::Result::Success;
2589 }
2590 return LWResult::Result::Timeout;
2591 }
2592 return LWResult::Result::Timeout;
2593 });
2594
2595 vector<DNSRecord> ret;
2596 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2597 BOOST_CHECK_EQUAL(res, RCode::NoError);
2598 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2599 BOOST_CHECK(ret[0].d_type == QType::A);
2600 BOOST_CHECK_EQUAL(ret[0].d_name, target);
2601
2602 // Now resolve NS to get auth NS set in cache and save the parent NS set
2603 ret.clear();
2604 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
2605 BOOST_CHECK_EQUAL(res, RCode::NoError);
2606 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2607 BOOST_CHECK(ret[0].d_type == QType::NS);
2608 BOOST_CHECK_EQUAL(ret[0].d_name, target);
2609 BOOST_CHECK_EQUAL(SyncRes::getSaveParentsNSSetsSize(), 1U);
2610
2611 g_recCache->doWipeCache(target, false, QType::A);
2612 SyncRes::s_save_parent_ns_set = false;
2613
2614 // Try to resolve now via the broken child NS set... should not work
2615 ret.clear();
2616 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2617 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2618 BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2619
2620 SyncRes::s_save_parent_ns_set = true;
2621
2622 // Try to resolve now via the broken child... should work now via fallback to parent NS set
2623 ret.clear();
2624 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2625 BOOST_CHECK_EQUAL(res, RCode::NoError);
2626 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2627 BOOST_CHECK(ret[0].d_type == QType::A);
2628 BOOST_CHECK_EQUAL(ret[0].d_name, target);
2629 }
2630
2631 BOOST_AUTO_TEST_SUITE_END()