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