]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc1.cc
Merge pull request #12776 from jacobbunk/tsig-qtype
[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 */, const 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 */, const 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 */, const 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_cname_target_servfail)
1737 {
1738 std::unique_ptr<SyncRes> resolver;
1739 initSR(resolver);
1740
1741 primeHints();
1742
1743 const DNSName target("cname.powerdns.com.");
1744 const DNSName cnameTarget("cname-target.powerdns.com");
1745
1746 resolver->setAsyncCallback([target, cnameTarget](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const boost::optional<const ResolveContext&>& /* context */, LWResult* res, bool* /* chained */) {
1747 if (isRootServer(ipAddress)) {
1748 setLWResult(res, 0, false, false, true);
1749 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1750 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1751 return LWResult::Result::Success;
1752 }
1753 if (ipAddress == ComboAddress("192.0.2.1:53")) {
1754
1755 if (domain == target) {
1756 setLWResult(res, 0, true, false, false);
1757 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1758 return LWResult::Result::Success;
1759 }
1760 if (domain == cnameTarget) {
1761 return LWResult::Result::PermanentError;
1762 }
1763
1764 return LWResult::Result::Success;
1765 }
1766
1767 return LWResult::Result::Timeout;
1768 });
1769
1770 vector<DNSRecord> ret;
1771 int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
1772 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1773 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1774 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1775 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1776 }
1777
1778 BOOST_AUTO_TEST_CASE(test_cname_target_servfail_servestale)
1779 {
1780 std::unique_ptr<SyncRes> resolver;
1781 initSR(resolver);
1782 MemRecursorCache::s_maxServedStaleExtensions = 1440;
1783
1784 primeHints();
1785
1786 const DNSName target("cname.powerdns.com.");
1787 const DNSName cnameTarget("cname-target.powerdns.com");
1788
1789 resolver->setAsyncCallback([target, cnameTarget](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const boost::optional<const ResolveContext&>& /* context */, LWResult* res, bool* /* chained */) {
1790 if (isRootServer(ipAddress)) {
1791 setLWResult(res, 0, false, false, true);
1792 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1793 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1794 return LWResult::Result::Success;
1795 }
1796 if (ipAddress == ComboAddress("192.0.2.1:53")) {
1797
1798 if (domain == target) {
1799 setLWResult(res, 0, true, false, false);
1800 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1801 return LWResult::Result::Success;
1802 }
1803 if (domain == cnameTarget) {
1804 return LWResult::Result::PermanentError;
1805 }
1806
1807 return LWResult::Result::Success;
1808 }
1809
1810 return LWResult::Result::Timeout;
1811 });
1812
1813 vector<DNSRecord> ret;
1814 int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
1815 // different compared no non-servestale case (returns ServFail), handled by pdns_recursor
1816 BOOST_CHECK_EQUAL(res, -1);
1817 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1818 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1819 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1820 }
1821
1822 BOOST_AUTO_TEST_CASE(test_time_limit)
1823 {
1824 std::unique_ptr<SyncRes> sr;
1825 initSR(sr);
1826
1827 primeHints();
1828
1829 size_t queries = 0;
1830 const DNSName target("cname.powerdns.com.");
1831
1832 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 */) {
1833 queries++;
1834
1835 if (isRootServer(ip)) {
1836 setLWResult(res, 0, false, false, true);
1837 /* Pretend that this query took 2000 ms */
1838 res->d_usec = 2000;
1839
1840 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1841 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1842 return LWResult::Result::Success;
1843 }
1844 else if (ip == ComboAddress("192.0.2.1:53")) {
1845
1846 setLWResult(res, 0, true, false, false);
1847 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1848 return LWResult::Result::Success;
1849 }
1850
1851 return LWResult::Result::Timeout;
1852 });
1853
1854 /* Set the maximum time to 1 ms */
1855 SyncRes::s_maxtotusec = 1000;
1856
1857 try {
1858 vector<DNSRecord> ret;
1859 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1860 BOOST_CHECK(false);
1861 }
1862 catch (const ImmediateServFailException& e) {
1863 }
1864 BOOST_CHECK_EQUAL(queries, 1U);
1865 }
1866
1867 BOOST_AUTO_TEST_CASE(test_dname_processing)
1868 {
1869 std::unique_ptr<SyncRes> sr;
1870 initSR(sr);
1871
1872 primeHints();
1873
1874 const DNSName dnameOwner("powerdns.com");
1875 const DNSName dnameTarget("powerdns.net");
1876
1877 const DNSName target("dname.powerdns.com.");
1878 const DNSName cnameTarget("dname.powerdns.net");
1879
1880 const DNSName uncachedTarget("dname-uncached.powerdns.com.");
1881 const DNSName uncachedCNAMETarget("dname-uncached.powerdns.net.");
1882
1883 const DNSName synthCNAME("cname-uncached.powerdns.com.");
1884 const DNSName synthCNAMETarget("cname-uncached.powerdns.net.");
1885
1886 size_t queries = 0;
1887
1888 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 */) {
1889 queries++;
1890
1891 if (isRootServer(ip)) {
1892 if (domain.isPartOf(dnameOwner)) {
1893 setLWResult(res, 0, false, false, true);
1894 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1895 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1896 return LWResult::Result::Success;
1897 }
1898 if (domain.isPartOf(dnameTarget)) {
1899 setLWResult(res, 0, false, false, true);
1900 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1901 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1902 return LWResult::Result::Success;
1903 }
1904 }
1905 else if (ip == ComboAddress("192.0.2.1:53")) {
1906 if (domain == target) {
1907 setLWResult(res, 0, true, false, false);
1908 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
1909 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1910 return LWResult::Result::Success;
1911 }
1912 }
1913 else if (ip == ComboAddress("192.0.2.2:53")) {
1914 if (domain == cnameTarget) {
1915 setLWResult(res, 0, true, false, false);
1916 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1917 }
1918 if (domain == uncachedCNAMETarget) {
1919 setLWResult(res, 0, true, false, false);
1920 addRecordToLW(res, domain, QType::A, "192.0.2.3");
1921 }
1922 return LWResult::Result::Success;
1923 }
1924 return LWResult::Result::Timeout;
1925 });
1926
1927 vector<DNSRecord> ret;
1928 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1929
1930 BOOST_CHECK_EQUAL(res, RCode::NoError);
1931 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1932
1933 BOOST_CHECK_EQUAL(queries, 4u);
1934
1935 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1936 BOOST_CHECK(ret[0].d_name == dnameOwner);
1937 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1938
1939 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1940 BOOST_CHECK_EQUAL(ret[1].d_name, target);
1941
1942 BOOST_CHECK(ret[2].d_type == QType::A);
1943 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
1944
1945 // Now check the cache
1946 ret.clear();
1947 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1948
1949 BOOST_CHECK_EQUAL(res, RCode::NoError);
1950 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1951
1952 BOOST_CHECK_EQUAL(queries, 4U);
1953
1954 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1955 BOOST_CHECK(ret[0].d_name == dnameOwner);
1956 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1957
1958 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1959 BOOST_CHECK_EQUAL(ret[1].d_name, target);
1960
1961 BOOST_CHECK(ret[2].d_type == QType::A);
1962 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
1963
1964 // Check if we correctly return a synthesized CNAME, should send out just 1 more query
1965 ret.clear();
1966 res = sr->beginResolve(uncachedTarget, QType(QType::A), QClass::IN, ret);
1967
1968 BOOST_CHECK_EQUAL(res, RCode::NoError);
1969 BOOST_CHECK_EQUAL(queries, 5U);
1970
1971 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1972 BOOST_CHECK(ret[0].d_name == dnameOwner);
1973 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1974
1975 BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
1976 BOOST_CHECK_EQUAL(ret[1].d_name, uncachedTarget);
1977 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), uncachedCNAMETarget);
1978
1979 BOOST_CHECK(ret[2].d_type == QType::A);
1980 BOOST_CHECK_EQUAL(ret[2].d_name, uncachedCNAMETarget);
1981
1982 // Check if we correctly return the DNAME from cache when asked
1983 ret.clear();
1984 res = sr->beginResolve(dnameOwner, QType(QType::DNAME), QClass::IN, ret);
1985 BOOST_CHECK_EQUAL(res, RCode::NoError);
1986 BOOST_CHECK_EQUAL(queries, 5U);
1987
1988 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1989 BOOST_CHECK(ret[0].d_name == dnameOwner);
1990 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1991
1992 // Check if we correctly return the synthesized CNAME from cache when asked
1993 ret.clear();
1994 res = sr->beginResolve(synthCNAME, QType(QType::CNAME), QClass::IN, ret);
1995 BOOST_CHECK_EQUAL(res, RCode::NoError);
1996 BOOST_CHECK_EQUAL(queries, 5U);
1997
1998 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1999 BOOST_CHECK(ret[0].d_name == dnameOwner);
2000 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2001
2002 BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
2003 BOOST_CHECK(ret[1].d_name == synthCNAME);
2004 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), synthCNAMETarget);
2005 }
2006
2007 BOOST_AUTO_TEST_CASE(test_dname_dnssec_secure)
2008 {
2009 std::unique_ptr<SyncRes> sr;
2010 initSR(sr, true);
2011 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2012
2013 primeHints();
2014
2015 const DNSName dnameOwner("powerdns");
2016 const DNSName dnameTarget("example");
2017
2018 const DNSName target("dname.powerdns");
2019 const DNSName cnameTarget("dname.example");
2020
2021 testkeysset_t keys;
2022
2023 auto luaconfsCopy = g_luaconfs.getCopy();
2024 luaconfsCopy.dsAnchors.clear();
2025 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2026 generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2027 generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2028 g_luaconfs.setState(luaconfsCopy);
2029
2030 size_t queries = 0;
2031
2032 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 */) {
2033 queries++;
2034 /* 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
2035 * As such, we need to do some more work to make the answers correct.
2036 */
2037
2038 if (isRootServer(ip)) {
2039 if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
2040 setLWResult(res, 0, true, false, true);
2041 addDNSKEY(keys, domain, 300, res->d_records);
2042 addRRSIG(keys, res->d_records, DNSName("."), 300);
2043 return LWResult::Result::Success;
2044 }
2045 if (domain.countLabels() == 1 && type == QType::DS) { // powerdns|DS or example|DS
2046 setLWResult(res, 0, true, false, true);
2047 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2048 addRRSIG(keys, res->d_records, DNSName("."), 300);
2049 return LWResult::Result::Success;
2050 }
2051 // For the rest, delegate!
2052 if (domain.isPartOf(dnameOwner)) {
2053 setLWResult(res, 0, false, false, true);
2054 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2055 addDS(dnameOwner, 300, res->d_records, keys);
2056 addRRSIG(keys, res->d_records, DNSName("."), 300);
2057 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2058 return LWResult::Result::Success;
2059 }
2060 if (domain.isPartOf(dnameTarget)) {
2061 setLWResult(res, 0, false, false, true);
2062 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2063 addDS(dnameTarget, 300, res->d_records, keys);
2064 addRRSIG(keys, res->d_records, DNSName("."), 300);
2065 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2066 return LWResult::Result::Success;
2067 }
2068 }
2069 else if (ip == ComboAddress("192.0.2.1:53")) {
2070 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
2071 setLWResult(res, 0, true, false, true);
2072 addDNSKEY(keys, domain, 300, res->d_records);
2073 addRRSIG(keys, res->d_records, domain, 300);
2074 return LWResult::Result::Success;
2075 }
2076 if (domain == target && type == QType::DS) { // dname.powerdns|DS
2077 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
2078 }
2079 if (domain == target) {
2080 setLWResult(res, 0, true, false, false);
2081 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2082 addRRSIG(keys, res->d_records, dnameOwner, 300);
2083 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2084 return LWResult::Result::Success;
2085 }
2086 }
2087 else if (ip == ComboAddress("192.0.2.2:53")) {
2088 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // example|DNSKEY
2089 setLWResult(res, 0, true, false, true);
2090 addDNSKEY(keys, domain, 300, res->d_records);
2091 addRRSIG(keys, res->d_records, domain, 300);
2092 return LWResult::Result::Success;
2093 }
2094 if (domain == cnameTarget && type == QType::DS) { // dname.example|DS
2095 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
2096 }
2097 if (domain == cnameTarget) {
2098 setLWResult(res, 0, true, false, false);
2099 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2100 addRRSIG(keys, res->d_records, dnameTarget, 300);
2101 }
2102 return LWResult::Result::Success;
2103 }
2104 return LWResult::Result::Timeout;
2105 });
2106
2107 vector<DNSRecord> ret;
2108 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2109
2110 BOOST_CHECK_EQUAL(res, RCode::NoError);
2111 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2112 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2113
2114 BOOST_CHECK_EQUAL(queries, 7U);
2115
2116 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2117 BOOST_CHECK(ret[0].d_name == dnameOwner);
2118 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2119
2120 BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2121 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2122
2123 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2124 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2125
2126 BOOST_CHECK(ret[3].d_type == QType::A);
2127 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2128
2129 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2130 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2131
2132 // And the cache
2133 ret.clear();
2134 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2135
2136 BOOST_CHECK_EQUAL(res, RCode::NoError);
2137 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2138 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2139
2140 BOOST_CHECK_EQUAL(queries, 7U);
2141
2142 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2143 BOOST_CHECK(ret[0].d_name == dnameOwner);
2144 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2145
2146 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2147 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2148
2149 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2150 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2151
2152 BOOST_CHECK(ret[3].d_type == QType::A);
2153 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2154
2155 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2156 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2157 }
2158
2159 BOOST_AUTO_TEST_CASE(test_dname_plus_ns_dnssec_secure)
2160 {
2161 std::unique_ptr<SyncRes> sr;
2162 initSR(sr, true);
2163 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2164
2165 primeHints();
2166
2167 const DNSName dnameOwner("powerdns");
2168 const DNSName dnameTarget("example");
2169
2170 const DNSName target("dname.powerdns");
2171 const DNSName cnameTarget("dname.example");
2172
2173 testkeysset_t keys;
2174
2175 auto luaconfsCopy = g_luaconfs.getCopy();
2176 luaconfsCopy.dsAnchors.clear();
2177 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2178 generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2179 g_luaconfs.setState(luaconfsCopy);
2180
2181 size_t queries = 0;
2182
2183 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 */) {
2184 queries++;
2185
2186 if (type == QType::DS || type == QType::DNSKEY) {
2187 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
2188 }
2189
2190 if (domain.isPartOf(dnameOwner)) {
2191 setLWResult(res, 0, true, false, true);
2192 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2193 addRRSIG(keys, res->d_records, DNSName("."), 300);
2194 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2195
2196 addRecordToLW(res, dnameTarget, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2197 addDS(dnameTarget, 300, res->d_records, keys);
2198 addRRSIG(keys, res->d_records, DNSName("."), 300);
2199 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2200 return LWResult::Result::Success;
2201 }
2202 else if (domain == cnameTarget) {
2203 setLWResult(res, 0, true, false, true);
2204 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2205 addRRSIG(keys, res->d_records, dnameTarget, 300);
2206 return LWResult::Result::Success;
2207 }
2208 return LWResult::Result::Timeout;
2209 });
2210
2211 vector<DNSRecord> ret;
2212 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2213
2214 BOOST_CHECK_EQUAL(res, RCode::NoError);
2215 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2216 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2217
2218 BOOST_CHECK_EQUAL(queries, 4U);
2219
2220 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2221 BOOST_CHECK(ret[0].d_name == dnameOwner);
2222 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2223
2224 BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2225 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2226
2227 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2228 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2229
2230 BOOST_CHECK(ret[3].d_type == QType::A);
2231 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2232
2233 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2234 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2235
2236 // And the cache
2237 ret.clear();
2238 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2239
2240 BOOST_CHECK_EQUAL(res, RCode::NoError);
2241 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2242 BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2243
2244 BOOST_CHECK_EQUAL(queries, 4U);
2245
2246 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2247 BOOST_CHECK(ret[0].d_name == dnameOwner);
2248 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2249
2250 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2251 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2252
2253 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2254 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2255
2256 BOOST_CHECK(ret[3].d_type == QType::A);
2257 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2258
2259 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2260 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2261 }
2262
2263 BOOST_AUTO_TEST_CASE(test_dname_dnssec_insecure)
2264 {
2265 /*
2266 * The DNAME itself is signed, but the final A record is not
2267 */
2268 std::unique_ptr<SyncRes> sr;
2269 initSR(sr, true);
2270 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2271
2272 primeHints();
2273
2274 const DNSName dnameOwner("powerdns");
2275 const DNSName dnameTarget("example");
2276
2277 const DNSName target("dname.powerdns");
2278 const DNSName cnameTarget("dname.example");
2279
2280 testkeysset_t keys;
2281
2282 auto luaconfsCopy = g_luaconfs.getCopy();
2283 luaconfsCopy.dsAnchors.clear();
2284 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2285 generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2286 g_luaconfs.setState(luaconfsCopy);
2287
2288 size_t queries = 0;
2289
2290 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 */) {
2291 queries++;
2292
2293 if (isRootServer(ip)) {
2294 if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
2295 setLWResult(res, 0, true, false, true);
2296 addDNSKEY(keys, domain, 300, res->d_records);
2297 addRRSIG(keys, res->d_records, DNSName("."), 300);
2298 return LWResult::Result::Success;
2299 }
2300 if (domain == dnameOwner && type == QType::DS) { // powerdns|DS
2301 setLWResult(res, 0, true, false, true);
2302 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2303 addRRSIG(keys, res->d_records, DNSName("."), 300);
2304 return LWResult::Result::Success;
2305 }
2306 if (domain == dnameTarget && type == QType::DS) { // example|DS
2307 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
2308 }
2309 // For the rest, delegate!
2310 if (domain.isPartOf(dnameOwner)) {
2311 setLWResult(res, 0, false, false, true);
2312 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2313 addDS(dnameOwner, 300, res->d_records, keys);
2314 addRRSIG(keys, res->d_records, DNSName("."), 300);
2315 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2316 return LWResult::Result::Success;
2317 }
2318 if (domain.isPartOf(dnameTarget)) {
2319 setLWResult(res, 0, false, false, true);
2320 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2321 addDS(dnameTarget, 300, res->d_records, keys);
2322 addRRSIG(keys, res->d_records, DNSName("."), 300);
2323 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2324 return LWResult::Result::Success;
2325 }
2326 }
2327 else if (ip == ComboAddress("192.0.2.1:53")) {
2328 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
2329 setLWResult(res, 0, true, false, true);
2330 addDNSKEY(keys, domain, 300, res->d_records);
2331 addRRSIG(keys, res->d_records, domain, 300);
2332 return LWResult::Result::Success;
2333 }
2334 if (domain == target && type == QType::DS) { // dname.powerdns|DS
2335 return genericDSAndDNSKEYHandler(res, domain, dnameOwner, type, keys, false);
2336 }
2337 if (domain == target) {
2338 setLWResult(res, 0, true, false, false);
2339 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2340 addRRSIG(keys, res->d_records, dnameOwner, 300);
2341 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2342 return LWResult::Result::Success;
2343 }
2344 }
2345 else if (ip == ComboAddress("192.0.2.2:53")) {
2346 if (domain == target && type == QType::DS) { // dname.example|DS
2347 return genericDSAndDNSKEYHandler(res, domain, dnameTarget, type, keys, false);
2348 }
2349 if (domain == cnameTarget) {
2350 setLWResult(res, 0, true, false, false);
2351 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2352 }
2353 return LWResult::Result::Success;
2354 }
2355 return LWResult::Result::Timeout;
2356 });
2357
2358 vector<DNSRecord> ret;
2359 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2360
2361 BOOST_CHECK_EQUAL(res, RCode::NoError);
2362 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2363 BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2364
2365 BOOST_CHECK_EQUAL(queries, 7U);
2366
2367 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2368 BOOST_CHECK(ret[0].d_name == dnameOwner);
2369 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2370
2371 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2372 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2373
2374 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2375 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2376
2377 BOOST_CHECK(ret[3].d_type == QType::A);
2378 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2379
2380 // And the cache
2381 ret.clear();
2382 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2383
2384 BOOST_CHECK_EQUAL(res, RCode::NoError);
2385 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2386 BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2387
2388 BOOST_CHECK_EQUAL(queries, 7U);
2389
2390 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2391 BOOST_CHECK(ret[0].d_name == dnameOwner);
2392 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2393
2394 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2395 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2396
2397 BOOST_CHECK(ret[2].d_type == QType::CNAME);
2398 BOOST_CHECK_EQUAL(ret[2].d_name, target);
2399
2400 BOOST_CHECK(ret[3].d_type == QType::A);
2401 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2402 }
2403
2404 BOOST_AUTO_TEST_CASE(test_dname_processing_no_CNAME)
2405 {
2406 std::unique_ptr<SyncRes> sr;
2407 initSR(sr);
2408
2409 primeHints();
2410
2411 const DNSName dnameOwner("powerdns.com");
2412 const DNSName dnameTarget("powerdns.net");
2413
2414 const DNSName target("dname.powerdns.com.");
2415 const DNSName cnameTarget("dname.powerdns.net");
2416
2417 size_t queries = 0;
2418
2419 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 */) {
2420 queries++;
2421
2422 if (isRootServer(ip)) {
2423 if (domain.isPartOf(dnameOwner)) {
2424 setLWResult(res, 0, false, false, true);
2425 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2426 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2427 return LWResult::Result::Success;
2428 }
2429 if (domain.isPartOf(dnameTarget)) {
2430 setLWResult(res, 0, false, false, true);
2431 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2432 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2433 return LWResult::Result::Success;
2434 }
2435 }
2436 else if (ip == ComboAddress("192.0.2.1:53")) {
2437 if (domain == target) {
2438 setLWResult(res, 0, true, false, false);
2439 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2440 // No CNAME, recursor should synth
2441 return LWResult::Result::Success;
2442 }
2443 }
2444 else if (ip == ComboAddress("192.0.2.2:53")) {
2445 if (domain == cnameTarget) {
2446 setLWResult(res, 0, true, false, false);
2447 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2448 }
2449 return LWResult::Result::Success;
2450 }
2451 return LWResult::Result::Timeout;
2452 });
2453
2454 vector<DNSRecord> ret;
2455 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2456
2457 BOOST_CHECK_EQUAL(res, RCode::NoError);
2458 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2459
2460 BOOST_CHECK_EQUAL(queries, 4U);
2461
2462 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2463 BOOST_CHECK(ret[0].d_name == dnameOwner);
2464 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2465
2466 BOOST_CHECK(ret[1].d_type == QType::CNAME);
2467 BOOST_CHECK_EQUAL(ret[1].d_name, target);
2468
2469 BOOST_CHECK(ret[2].d_type == QType::A);
2470 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2471
2472 // Now check the cache
2473 ret.clear();
2474 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2475
2476 BOOST_CHECK_EQUAL(res, RCode::NoError);
2477 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2478
2479 BOOST_CHECK_EQUAL(queries, 4U);
2480
2481 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2482 BOOST_CHECK(ret[0].d_name == dnameOwner);
2483 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2484
2485 BOOST_CHECK(ret[1].d_type == QType::CNAME);
2486 BOOST_CHECK_EQUAL(ret[1].d_name, target);
2487
2488 BOOST_CHECK(ret[2].d_type == QType::A);
2489 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2490 }
2491
2492 /*
2493 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2494
2495 - check out of band support
2496
2497 - check preoutquery
2498
2499 */
2500
2501 BOOST_AUTO_TEST_CASE(test_glued_referral_child_ns_set_wrong)
2502 {
2503 std::unique_ptr<SyncRes> sr;
2504 initSR(sr);
2505
2506 primeHints();
2507
2508 const DNSName target("powerdns.com.");
2509
2510 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 */) {
2511 /* this will cause issue with qname minimization if we ever implement it */
2512 if (domain != target) {
2513 return LWResult::Result::Timeout;
2514 }
2515
2516 if (isRootServer(ip)) {
2517 setLWResult(res, 0, false, false, true);
2518 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2519 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2520 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2521 return LWResult::Result::Success;
2522 }
2523 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
2524 setLWResult(res, 0, false, false, true);
2525 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2526 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2527 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2528 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2529 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2530 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2531 return LWResult::Result::Success;
2532 }
2533 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")) {
2534
2535 if (type == QType::A) {
2536 setLWResult(res, 0, true, false, true);
2537 addRecordToLW(res, target, QType::A, "192.0.2.4");
2538 return LWResult::Result::Success;
2539 }
2540 else if (type == QType::NS) {
2541 setLWResult(res, 0, true, false, true);
2542 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX1.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2543 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX2.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2544 addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::A, "192.0.2.11", DNSResourceRecord::ADDITIONAL, 172800);
2545 addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::AAAA, "2001:DB8::11", DNSResourceRecord::ADDITIONAL, 172800);
2546 addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::A, "192.0.2.12", DNSResourceRecord::ADDITIONAL, 172800);
2547 addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::AAAA, "2001:DB8::12", DNSResourceRecord::ADDITIONAL, 172800);
2548 return LWResult::Result::Success;
2549 }
2550 else {
2551 return LWResult::Result::Timeout;
2552 }
2553 }
2554 else {
2555 return LWResult::Result::Timeout;
2556 }
2557 });
2558
2559 vector<DNSRecord> ret;
2560 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2561 BOOST_CHECK_EQUAL(res, RCode::NoError);
2562 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2563 BOOST_CHECK(ret[0].d_type == QType::A);
2564 BOOST_CHECK_EQUAL(ret[0].d_name, target);
2565
2566 // Now resolve NS to get auth NS set in cache and save the parent NS set
2567 ret.clear();
2568 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
2569 BOOST_CHECK_EQUAL(res, RCode::NoError);
2570 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2571 BOOST_CHECK(ret[0].d_type == QType::NS);
2572 BOOST_CHECK_EQUAL(ret[0].d_name, target);
2573 BOOST_CHECK_EQUAL(SyncRes::getSaveParentsNSSetsSize(), 1U);
2574
2575 g_recCache->doWipeCache(target, false, QType::A);
2576 SyncRes::s_save_parent_ns_set = false;
2577
2578 // Try to resolve now via the broken child NS set... should not work
2579 ret.clear();
2580 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2581 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2582 BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2583
2584 SyncRes::s_save_parent_ns_set = true;
2585
2586 // Try to resolve now via the broken child... should work now via fallback to parent NS set
2587 ret.clear();
2588 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2589 BOOST_CHECK_EQUAL(res, RCode::NoError);
2590 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2591 BOOST_CHECK(ret[0].d_type == QType::A);
2592 BOOST_CHECK_EQUAL(ret[0].d_name, target);
2593 }
2594
2595 BOOST_AUTO_TEST_SUITE_END()