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