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