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