]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc1.cc
Resolve merge errors.
[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
6 BOOST_AUTO_TEST_SUITE(syncres_cc1)
7
8 BOOST_AUTO_TEST_CASE(test_root_primed) {
9 std::unique_ptr<SyncRes> sr;
10 initSR(sr);
11
12 primeHints();
13
14 const DNSName target("a.root-servers.net.");
15
16 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
17 vector<DNSRecord> ret;
18 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
19 BOOST_CHECK_EQUAL(res, RCode::NoError);
20 BOOST_REQUIRE_EQUAL(ret.size(), 1);
21 BOOST_CHECK(ret[0].d_type == QType::A);
22 BOOST_CHECK_EQUAL(ret[0].d_name, target);
23
24 ret.clear();
25 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
26 BOOST_CHECK_EQUAL(res, RCode::NoError);
27 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
28 BOOST_REQUIRE_EQUAL(ret.size(), 1);
29 BOOST_CHECK(ret[0].d_type == QType::AAAA);
30 BOOST_CHECK_EQUAL(ret[0].d_name, target);
31 }
32
33 BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
34 std::unique_ptr<SyncRes> sr;
35 initSR(sr);
36
37 primeHints();
38 const DNSName target(".");
39
40 /* we are primed, but we should not be able to NS . without any query
41 because the . NS entry is not stored as authoritative */
42
43 size_t queriesCount = 0;
44
45 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) {
46 queriesCount++;
47
48 if (domain == target && type == QType::NS) {
49
50 setLWResult(res, 0, true, false, true);
51 char addr[] = "a.root-servers.net.";
52 for (char idx = 'a'; idx <= 'm'; idx++) {
53 addr[0] = idx;
54 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
55 }
56
57 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
58 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
59
60 return 1;
61 }
62
63 return 0;
64 });
65
66 vector<DNSRecord> ret;
67 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
68 BOOST_CHECK_EQUAL(res, RCode::NoError);
69 BOOST_REQUIRE_EQUAL(ret.size(), 13);
70 BOOST_CHECK_EQUAL(queriesCount, 1);
71 }
72
73 BOOST_AUTO_TEST_CASE(test_root_not_primed) {
74 std::unique_ptr<SyncRes> sr;
75 initSR(sr);
76
77 size_t queriesCount = 0;
78
79 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) {
80 queriesCount++;
81
82 if (domain == g_rootdnsname && type == QType::NS) {
83 setLWResult(res, 0, true, false, true);
84 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
85 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
86 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
87
88 return 1;
89 }
90
91 return 0;
92 });
93
94 /* we are not primed yet, so SyncRes will have to call primeHints()
95 then call getRootNS(), for which at least one of the root servers needs to answer */
96 vector<DNSRecord> ret;
97 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
98 BOOST_CHECK_EQUAL(res, RCode::NoError);
99 BOOST_CHECK_EQUAL(ret.size(), 1);
100 BOOST_CHECK_EQUAL(queriesCount, 2);
101 }
102
103 BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
104 std::unique_ptr<SyncRes> sr;
105 initSR(sr);
106 std::set<ComboAddress> downServers;
107
108 /* we are not primed yet, so SyncRes will have to call primeHints()
109 then call getRootNS(), for which at least one of the root servers needs to answer.
110 None will, so it should ServFail.
111 */
112 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) {
113
114 downServers.insert(ip);
115 return 0;
116 });
117
118 vector<DNSRecord> ret;
119 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
120 BOOST_CHECK_EQUAL(res, RCode::ServFail);
121 BOOST_CHECK_EQUAL(ret.size(), 0);
122 BOOST_CHECK(downServers.size() > 0);
123 /* we explicitly refuse to mark the root servers down */
124 for (const auto& server : downServers) {
125 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
126 }
127 }
128
129 static void test_edns_formerr_fallback_f(bool sample) {
130 std::unique_ptr<SyncRes> sr;
131 initSR(sr);
132 if (sample) {
133 sr->setQNameMinimization();
134 }
135 ComboAddress noEDNSServer;
136 size_t queriesWithEDNS = 0;
137 size_t queriesWithoutEDNS = 0;
138
139 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) {
140 if (EDNS0Level != 0) {
141 queriesWithEDNS++;
142 noEDNSServer = ip;
143
144 setLWResult(res, RCode::FormErr);
145 return 1;
146 }
147
148 queriesWithoutEDNS++;
149
150 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
151 setLWResult(res, 0, true, false, false);
152 addRecordToLW(res, domain, QType::A, "192.0.2.1");
153 return 1;
154 }
155
156 return sample ? basicRecordsForQnameMinimization(res, domain, type) : 0;
157 });
158
159 primeHints();
160
161 /* fake that the root NS doesn't handle EDNS, check that we fallback */
162 vector<DNSRecord> ret;
163 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
164 BOOST_CHECK_EQUAL(res, RCode::NoError);
165 BOOST_CHECK_EQUAL(ret.size(), 1);
166 BOOST_CHECK_EQUAL(queriesWithEDNS, sample ? 3 : 1);
167 BOOST_CHECK_EQUAL(queriesWithoutEDNS, sample ? 4 : 1);
168 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), sample ? 3 : 1);
169 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
170 }
171
172 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
173 test_edns_formerr_fallback_f(false);
174 }
175
176 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback_qmin) {
177 // DISABLED UNTIL QNAME MINIMIZATON IS THERE
178 return;
179 test_edns_formerr_fallback_f(true);
180 }
181
182 BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled) {
183 std::unique_ptr<SyncRes> sr;
184 initSR(sr);
185
186 /* in this test, the auth answers with FormErr to an EDNS-enabled
187 query, but the response does contain EDNS so we should not mark
188 it as EDNS ignorant or intolerant.
189 */
190 size_t queriesWithEDNS = 0;
191 size_t queriesWithoutEDNS = 0;
192 std::set<ComboAddress> usedServers;
193
194 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) {
195
196 if (EDNS0Level > 0) {
197 queriesWithEDNS++;
198 }
199 else {
200 queriesWithoutEDNS++;
201 }
202 usedServers.insert(ip);
203
204 if (type == QType::DNAME) {
205 setLWResult(res, RCode::FormErr);
206 if (EDNS0Level > 0) {
207 res->d_haveEDNS = true;
208 }
209 return 1;
210 }
211
212 return 0;
213 });
214
215 primeHints();
216
217 vector<DNSRecord> ret;
218 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::DNAME), QClass::IN, ret);
219 BOOST_CHECK_EQUAL(res, RCode::ServFail);
220 BOOST_CHECK_EQUAL(ret.size(), 0);
221 BOOST_CHECK_EQUAL(queriesWithEDNS, 26);
222 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 0);
223 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 26);
224 BOOST_CHECK_EQUAL(usedServers.size(), 26);
225 for (const auto& server : usedServers) {
226 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
227 }
228 }
229
230 BOOST_AUTO_TEST_CASE(test_meta_types) {
231 std::unique_ptr<SyncRes> sr;
232 initSR(sr);
233
234 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 };
235
236 for (const auto qtype : invalidTypes) {
237 size_t queriesCount = 0;
238
239 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) {
240
241 queriesCount++;
242 return 0;
243 });
244
245 primeHints();
246
247 vector<DNSRecord> ret;
248 int res = sr->beginResolve(DNSName("powerdns.com."), QType(qtype), QClass::IN, ret);
249 BOOST_CHECK_EQUAL(res, -1);
250 BOOST_CHECK_EQUAL(ret.size(), 0);
251 BOOST_CHECK_EQUAL(queriesCount, 0);
252 }
253 }
254
255 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
256 std::unique_ptr<SyncRes> sr;
257 initSR(sr);
258
259 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) {
260 if (!doTCP) {
261 setLWResult(res, 0, false, true, false);
262 return 1;
263 }
264 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
265 setLWResult(res, 0, true, false, false);
266 addRecordToLW(res, domain, QType::A, "192.0.2.1");
267 return 1;
268 }
269
270 return 0;
271 });
272
273 primeHints();
274
275 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
276 vector<DNSRecord> ret;
277 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
278 BOOST_CHECK_EQUAL(res, RCode::NoError);
279 }
280
281 BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
282 std::unique_ptr<SyncRes> sr;
283 initSR(sr);
284
285 size_t tcpQueriesCount = 0;
286
287 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) {
288 if (!doTCP) {
289 setLWResult(res, 0, true, true, false);
290 return 1;
291 }
292
293 /* first TCP query is answered with a TC response */
294 tcpQueriesCount++;
295 if (tcpQueriesCount == 1) {
296 setLWResult(res, 0, true, true, false);
297 }
298 else {
299 setLWResult(res, 0, true, false, false);
300 }
301
302 addRecordToLW(res, domain, QType::A, "192.0.2.1");
303 return 1;
304 });
305
306 primeHints();
307
308 vector<DNSRecord> ret;
309 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
310 BOOST_CHECK_EQUAL(res, RCode::NoError);
311 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
312 }
313
314 BOOST_AUTO_TEST_CASE(test_all_nss_down) {
315 std::unique_ptr<SyncRes> sr;
316 initSR(sr);
317 std::set<ComboAddress> downServers;
318
319 primeHints();
320
321 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) {
322
323 if (isRootServer(ip)) {
324 setLWResult(res, 0, false, false, true);
325 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
326 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
327 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
328 return 1;
329 }
330 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
331 setLWResult(res, 0, false, false, true);
332 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
333 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
334 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
335 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
336 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
337 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
338 return 1;
339 }
340 else {
341 downServers.insert(ip);
342 return 0;
343 }
344 });
345
346 DNSName target("powerdns.com.");
347
348 vector<DNSRecord> ret;
349 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
350 BOOST_CHECK_EQUAL(res, RCode::ServFail);
351 BOOST_CHECK_EQUAL(ret.size(), 0);
352 BOOST_CHECK_EQUAL(downServers.size(), 4);
353
354 time_t now = sr->getNow().tv_sec;
355 for (const auto& server : downServers) {
356 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
357 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
358 }
359 }
360
361 BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
362 std::unique_ptr<SyncRes> sr;
363 initSR(sr);
364 std::set<ComboAddress> downServers;
365
366 primeHints();
367
368 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) {
369
370 if (isRootServer(ip)) {
371 setLWResult(res, 0, false, false, true);
372 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
373 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
374 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
375 return 1;
376 }
377 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
378 setLWResult(res, 0, false, false, true);
379 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
380 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
381 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
382 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
383 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
384 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
385 return 1;
386 }
387 else {
388 downServers.insert(ip);
389 return 0;
390 }
391 });
392
393 /* exact same test than the previous one, except instead of a time out we fake a network error */
394 DNSName target("powerdns.com.");
395
396 vector<DNSRecord> ret;
397 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
398 BOOST_CHECK_EQUAL(res, RCode::ServFail);
399 BOOST_CHECK_EQUAL(ret.size(), 0);
400 BOOST_CHECK_EQUAL(downServers.size(), 4);
401
402 time_t now = sr->getNow().tv_sec;
403 for (const auto& server : downServers) {
404 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
405 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
406 }
407 }
408
409 BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
410 std::unique_ptr<SyncRes> sr;
411 initSR(sr);
412
413 primeHints();
414
415 DNSName target("www.powerdns.com.");
416
417 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) {
418
419 if (isRootServer(ip)) {
420 setLWResult(res, 0, false, false, true);
421 if (domain == target) {
422 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
423 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
424 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
425 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
426 }
427 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
428 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
429 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
430 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
431 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
432 }
433 return 1;
434 }
435 else if (ip == ComboAddress("192.0.2.3:53")) {
436 setLWResult(res, 0, true, false, true);
437 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
438 if (type == QType::A) {
439 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
440 }
441 else if (type == QType::AAAA) {
442 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
443 }
444 }
445 else if (domain == target) {
446 if (type == QType::A) {
447 addRecordToLW(res, domain, QType::A, "192.0.2.1");
448 }
449 else if (type == QType::AAAA) {
450 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
451 }
452 }
453 return 1;
454 }
455 return 0;
456 });
457
458 vector<DNSRecord> ret;
459 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
460 BOOST_CHECK_EQUAL(res, RCode::NoError);
461 BOOST_CHECK_EQUAL(ret.size(), 1);
462 }
463
464 BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
465 std::unique_ptr<SyncRes> sr;
466 initSR(sr);
467 std::set<ComboAddress> downServers;
468
469 primeHints();
470
471 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) {
472
473 if (isRootServer(ip)) {
474 setLWResult(res, 0, false, false, true);
475 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
476 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
477 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
478 return 1;
479 }
480 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
481 setLWResult(res, 0, false, false, true);
482 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
483 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
484 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
485 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
486 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
487 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
488 return 1;
489 }
490 else {
491 if (downServers.size() < 3) {
492 /* only the last one will answer */
493 downServers.insert(ip);
494 return -2;
495 }
496 else {
497 setLWResult(res, 0, true, false, true);
498 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
499 return 1;
500 }
501 }
502 });
503
504 DNSName target("powerdns.com.");
505
506 vector<DNSRecord> ret;
507 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
508 BOOST_CHECK_EQUAL(res, RCode::NoError);
509 BOOST_CHECK_EQUAL(ret.size(), 1);
510 BOOST_CHECK_EQUAL(downServers.size(), 3);
511
512 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
513 time_t now = sr->getNow().tv_sec;
514 for (const auto& server : downServers) {
515 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
516 BOOST_CHECK(!SyncRes::isThrottled(now, server, target, QType::A));
517 }
518 }
519
520 BOOST_AUTO_TEST_CASE(test_glued_referral) {
521 std::unique_ptr<SyncRes> sr;
522 initSR(sr);
523
524 primeHints();
525
526 const DNSName target("powerdns.com.");
527
528 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) {
529 /* this will cause issue with qname minimization if we ever implement it */
530 if (domain != target) {
531 return 0;
532 }
533
534 if (isRootServer(ip)) {
535 setLWResult(res, 0, false, false, true);
536 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
537 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
538 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
539 return 1;
540 }
541 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
542 setLWResult(res, 0, false, false, true);
543 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
544 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
545 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
546 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
547 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
548 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
549 return 1;
550 }
551 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")) {
552 setLWResult(res, 0, true, false, true);
553 addRecordToLW(res, target, QType::A, "192.0.2.4");
554 return 1;
555 }
556 else {
557 return 0;
558 }
559 });
560
561 vector<DNSRecord> ret;
562 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
563 BOOST_CHECK_EQUAL(res, RCode::NoError);
564 BOOST_REQUIRE_EQUAL(ret.size(), 1);
565 BOOST_CHECK(ret[0].d_type == QType::A);
566 BOOST_CHECK_EQUAL(ret[0].d_name, target);
567 }
568
569 BOOST_AUTO_TEST_CASE(test_glueless_referral) {
570 std::unique_ptr<SyncRes> sr;
571 initSR(sr);
572
573 primeHints();
574
575 const DNSName target("powerdns.com.");
576
577 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) {
578
579 if (isRootServer(ip)) {
580 setLWResult(res, 0, false, false, true);
581
582 if (domain.isPartOf(DNSName("com."))) {
583 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
584 } else if (domain.isPartOf(DNSName("org."))) {
585 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
586 }
587 else {
588 setLWResult(res, RCode::NXDomain, false, false, true);
589 return 1;
590 }
591
592 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
593 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
594 return 1;
595 }
596 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
597 if (domain == target) {
598 setLWResult(res, 0, false, false, true);
599 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
600 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
601 return 1;
602 }
603 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
604 setLWResult(res, 0, true, false, true);
605 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
606 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
607 return 1;
608 }
609 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
610 setLWResult(res, 0, true, false, true);
611 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
612 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
613 return 1;
614 }
615
616 setLWResult(res, RCode::NXDomain, false, false, true);
617 return 1;
618 }
619 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")) {
620 setLWResult(res, 0, true, false, true);
621 addRecordToLW(res, target, QType::A, "192.0.2.4");
622 return 1;
623 }
624 else {
625 return 0;
626 }
627 });
628
629 vector<DNSRecord> ret;
630 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
631 BOOST_CHECK_EQUAL(res, RCode::NoError);
632 BOOST_REQUIRE_EQUAL(ret.size(), 1);
633 BOOST_CHECK(ret[0].d_type == QType::A);
634 BOOST_CHECK_EQUAL(ret[0].d_name, target);
635 }
636
637 BOOST_AUTO_TEST_CASE(test_edns_subnet_by_domain) {
638 std::unique_ptr<SyncRes> sr;
639 initSR(sr);
640
641 primeHints();
642
643 const DNSName target("powerdns.com.");
644 SyncRes::addEDNSDomain(target);
645
646 EDNSSubnetOpts incomingECS;
647 incomingECS.source = Netmask("192.0.2.128/32");
648 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
649
650 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) {
651
652 BOOST_REQUIRE(srcmask);
653 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
654
655 if (isRootServer(ip)) {
656 setLWResult(res, 0, false, false, true);
657 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
658 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
659
660 /* this one did not use the ECS info */
661 srcmask = boost::none;
662
663 return 1;
664 } else if (ip == ComboAddress("192.0.2.1:53")) {
665
666 setLWResult(res, 0, true, false, false);
667 addRecordToLW(res, domain, QType::A, "192.0.2.2");
668
669 /* this one did, but only up to a precision of /16, not the full /24 */
670 srcmask = Netmask("192.0.0.0/16");
671
672 return 1;
673 }
674
675 return 0;
676 });
677
678 SyncRes::s_ecsqueries = 0;
679 SyncRes::s_ecsresponses = 0;
680 vector<DNSRecord> ret;
681 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
682 BOOST_CHECK_EQUAL(res, RCode::NoError);
683 BOOST_REQUIRE_EQUAL(ret.size(), 1);
684 BOOST_CHECK(ret[0].d_type == QType::A);
685 BOOST_CHECK_EQUAL(ret[0].d_name, target);
686 BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 2);
687 BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1);
688 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
689 BOOST_CHECK_EQUAL(entry.second, entry.first == 15 ? 1 : 0);
690 }
691 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
692 BOOST_CHECK_EQUAL(entry.second, 0);
693 }
694 }
695
696 BOOST_AUTO_TEST_CASE(test_edns_subnet_by_addr) {
697 std::unique_ptr<SyncRes> sr;
698 initSR(sr);
699
700 primeHints();
701
702 const DNSName target("powerdns.com.");
703 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
704
705 EDNSSubnetOpts incomingECS;
706 incomingECS.source = Netmask("2001:DB8::FF/128");
707 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
708
709 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) {
710
711 if (isRootServer(ip)) {
712 BOOST_REQUIRE(!srcmask);
713
714 setLWResult(res, 0, false, false, true);
715 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
716 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
717 return 1;
718 } else if (ip == ComboAddress("192.0.2.1:53")) {
719
720 BOOST_REQUIRE(srcmask);
721 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
722
723 setLWResult(res, 0, true, false, false);
724 addRecordToLW(res, domain, QType::A, "192.0.2.2");
725 return 1;
726 }
727
728 return 0;
729 });
730
731 SyncRes::s_ecsqueries = 0;
732 SyncRes::s_ecsresponses = 0;
733 vector<DNSRecord> ret;
734 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
735 BOOST_CHECK_EQUAL(res, RCode::NoError);
736 BOOST_REQUIRE_EQUAL(ret.size(), 1);
737 BOOST_CHECK(ret[0].d_type == QType::A);
738 BOOST_CHECK_EQUAL(ret[0].d_name, target);
739 BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 1);
740 BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1);
741 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
742 BOOST_CHECK_EQUAL(entry.second, 0);
743 }
744 for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
745 BOOST_CHECK_EQUAL(entry.second, entry.first == 55 ? 1 : 0);
746 }
747 }
748
749 BOOST_AUTO_TEST_CASE(test_ecs_use_requestor) {
750 std::unique_ptr<SyncRes> sr;
751 initSR(sr);
752
753 primeHints();
754
755 const DNSName target("powerdns.com.");
756 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
757 // No incoming ECS data
758 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
759
760 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) {
761
762 if (isRootServer(ip)) {
763 BOOST_REQUIRE(!srcmask);
764
765 setLWResult(res, 0, false, false, true);
766 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
767 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
768 return 1;
769 } else if (ip == ComboAddress("192.0.2.1:53")) {
770
771 BOOST_REQUIRE(srcmask);
772 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
773
774 setLWResult(res, 0, true, false, false);
775 addRecordToLW(res, domain, QType::A, "192.0.2.2");
776 return 1;
777 }
778
779 return 0;
780 });
781
782 vector<DNSRecord> ret;
783 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
784 BOOST_CHECK_EQUAL(res, RCode::NoError);
785 BOOST_REQUIRE_EQUAL(ret.size(), 1);
786 BOOST_CHECK(ret[0].d_type == QType::A);
787 BOOST_CHECK_EQUAL(ret[0].d_name, target);
788 }
789
790 BOOST_AUTO_TEST_CASE(test_ecs_use_scope_zero) {
791 std::unique_ptr<SyncRes> sr;
792 initSR(sr);
793
794 primeHints();
795
796 const DNSName target("powerdns.com.");
797 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
798 SyncRes::clearEDNSLocalSubnets();
799 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
800 // No incoming ECS data, Requestor IP not in ecs-add-for
801 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
802
803 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) {
804
805 if (isRootServer(ip)) {
806 BOOST_REQUIRE(!srcmask);
807
808 setLWResult(res, 0, false, false, true);
809 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
810 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
811 return 1;
812 } else if (ip == ComboAddress("192.0.2.1:53")) {
813
814 BOOST_REQUIRE(srcmask);
815 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
816
817 setLWResult(res, 0, true, false, false);
818 addRecordToLW(res, domain, QType::A, "192.0.2.2");
819 return 1;
820 }
821
822 return 0;
823 });
824
825 vector<DNSRecord> ret;
826 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
827 BOOST_CHECK_EQUAL(res, RCode::NoError);
828 BOOST_REQUIRE_EQUAL(ret.size(), 1);
829 BOOST_CHECK(ret[0].d_type == QType::A);
830 BOOST_CHECK_EQUAL(ret[0].d_name, target);
831 }
832
833 BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask) {
834 std::unique_ptr<SyncRes> sr;
835 initSR(sr);
836
837 primeHints();
838
839 const DNSName target("powerdns.com.");
840 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
841 SyncRes::clearEDNSLocalSubnets();
842 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
843 EDNSSubnetOpts incomingECS;
844 incomingECS.source = Netmask("192.0.0.0/16");
845 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
846
847 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) {
848
849 if (isRootServer(ip)) {
850 BOOST_REQUIRE(!srcmask);
851
852 setLWResult(res, 0, false, false, true);
853 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
854 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
855 return 1;
856 } else if (ip == ComboAddress("192.0.2.1:53")) {
857
858 BOOST_REQUIRE(srcmask);
859 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.0.0/16");
860
861 setLWResult(res, 0, true, false, false);
862 addRecordToLW(res, domain, QType::A, "192.0.2.2");
863 return 1;
864 }
865
866 return 0;
867 });
868
869 vector<DNSRecord> ret;
870 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
871 BOOST_CHECK_EQUAL(res, RCode::NoError);
872 BOOST_REQUIRE_EQUAL(ret.size(), 1);
873 BOOST_CHECK(ret[0].d_type == QType::A);
874 BOOST_CHECK_EQUAL(ret[0].d_name, target);
875 }
876
877 BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask_zero) {
878 std::unique_ptr<SyncRes> sr;
879 initSR(sr);
880
881 primeHints();
882
883 const DNSName target("powerdns.com.");
884 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
885 SyncRes::clearEDNSLocalSubnets();
886 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
887 EDNSSubnetOpts incomingECS;
888 incomingECS.source = Netmask("0.0.0.0/0");
889 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
890
891 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) {
892
893 if (isRootServer(ip)) {
894 BOOST_REQUIRE(!srcmask);
895
896 setLWResult(res, 0, false, false, true);
897 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
898 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
899 return 1;
900 } else if (ip == ComboAddress("192.0.2.1:53")) {
901
902 BOOST_REQUIRE(srcmask);
903 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
904
905 setLWResult(res, 0, true, false, false);
906 addRecordToLW(res, domain, QType::A, "192.0.2.2");
907 return 1;
908 }
909
910 return 0;
911 });
912
913 vector<DNSRecord> ret;
914 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
915 BOOST_CHECK_EQUAL(res, RCode::NoError);
916 BOOST_REQUIRE_EQUAL(ret.size(), 1);
917 BOOST_CHECK(ret[0].d_type == QType::A);
918 BOOST_CHECK_EQUAL(ret[0].d_name, target);
919 }
920
921 BOOST_AUTO_TEST_CASE(test_following_cname) {
922 std::unique_ptr<SyncRes> sr;
923 initSR(sr);
924
925 primeHints();
926
927 const DNSName target("cname.powerdns.com.");
928 const DNSName cnameTarget("cname-target.powerdns.com");
929
930 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) {
931
932 if (isRootServer(ip)) {
933 setLWResult(res, 0, false, false, true);
934 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
935 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
936 return 1;
937 } else if (ip == ComboAddress("192.0.2.1:53")) {
938
939 if (domain == target) {
940 setLWResult(res, 0, true, false, false);
941 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
942 return 1;
943 }
944 else if (domain == cnameTarget) {
945 setLWResult(res, 0, true, false, false);
946 addRecordToLW(res, domain, QType::A, "192.0.2.2");
947 }
948
949 return 1;
950 }
951
952 return 0;
953 });
954
955 vector<DNSRecord> ret;
956 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
957 BOOST_CHECK_EQUAL(res, RCode::NoError);
958 BOOST_REQUIRE_EQUAL(ret.size(), 2);
959 BOOST_CHECK(ret[0].d_type == QType::CNAME);
960 BOOST_CHECK_EQUAL(ret[0].d_name, target);
961 BOOST_CHECK(ret[1].d_type == QType::A);
962 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
963 }
964
965 BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
966 std::unique_ptr<SyncRes> sr;
967 initSR(sr);
968
969 primeHints();
970
971 const DNSName target("cname.powerdns.com.");
972 const DNSName cnameTarget("cname-target.powerdns.com");
973
974 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) {
975
976 if (isRootServer(ip)) {
977 setLWResult(res, 0, false, false, true);
978 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
979 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
980 return 1;
981 } else if (ip == ComboAddress("192.0.2.1:53")) {
982
983 if (domain == target) {
984 setLWResult(res, RCode::NXDomain, true, false, false);
985 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
986 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
987 } else if (domain == cnameTarget) {
988 setLWResult(res, RCode::NXDomain, true, false, false);
989 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
990 return 1;
991 }
992
993 return 1;
994 }
995
996 return 0;
997 });
998
999 vector<DNSRecord> ret;
1000 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1001 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1002 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1003 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1004 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1005 BOOST_CHECK(ret[1].d_type == QType::SOA);
1006
1007 /* a second time, to check the cache */
1008 ret.clear();
1009 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1010 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1011 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1012 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1013 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1014 BOOST_CHECK(ret[1].d_type == QType::SOA);
1015 }
1016
1017 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1018 std::unique_ptr<SyncRes> sr;
1019 initSR(sr);
1020
1021 primeHints();
1022
1023 /* In this test we directly get the NS server for cname.powerdns.com.,
1024 and we don't know whether it's also authoritative for
1025 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1026 the additional A record for cname-target.powerdns.com. */
1027 const DNSName target("cname.powerdns.com.");
1028 const DNSName cnameTarget("cname-target.powerdns.com");
1029
1030 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) {
1031
1032 if (isRootServer(ip)) {
1033
1034 setLWResult(res, 0, false, false, true);
1035
1036 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1037 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1038 return 1;
1039 } else if (ip == ComboAddress("192.0.2.1:53")) {
1040
1041 if (domain == target) {
1042 setLWResult(res, 0, true, false, false);
1043 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1044 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1045 return 1;
1046 } else if (domain == cnameTarget) {
1047 setLWResult(res, 0, true, false, false);
1048 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1049 return 1;
1050 }
1051
1052 return 1;
1053 }
1054
1055 return 0;
1056 });
1057
1058 vector<DNSRecord> ret;
1059 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1060 BOOST_CHECK_EQUAL(res, RCode::NoError);
1061 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1062 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1063 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1064 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1065 BOOST_REQUIRE(ret[1].d_type == QType::A);
1066 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1067 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1068 }
1069
1070 BOOST_AUTO_TEST_CASE(test_cname_loop) {
1071 std::unique_ptr<SyncRes> sr;
1072 initSR(sr);
1073
1074 primeHints();
1075
1076 size_t count = 0;
1077 const DNSName target("cname.powerdns.com.");
1078
1079 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) {
1080
1081 count++;
1082
1083 if (isRootServer(ip)) {
1084
1085 setLWResult(res, 0, false, false, true);
1086 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1087 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1088 return 1;
1089 } else if (ip == ComboAddress("192.0.2.1:53")) {
1090
1091 if (domain == target) {
1092 setLWResult(res, 0, true, false, false);
1093 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1094 return 1;
1095 }
1096
1097 return 1;
1098 }
1099
1100 return 0;
1101 });
1102
1103 vector<DNSRecord> ret;
1104 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1105 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1106 BOOST_CHECK_GT(ret.size(), 0);
1107 BOOST_CHECK_EQUAL(count, 2);
1108 }
1109
1110 BOOST_AUTO_TEST_CASE(test_cname_depth) {
1111 std::unique_ptr<SyncRes> sr;
1112 initSR(sr);
1113
1114 primeHints();
1115
1116 size_t depth = 0;
1117 const DNSName target("cname.powerdns.com.");
1118
1119 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) {
1120
1121 if (isRootServer(ip)) {
1122
1123 setLWResult(res, 0, false, false, true);
1124 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1125 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1126 return 1;
1127 } else if (ip == ComboAddress("192.0.2.1:53")) {
1128
1129 setLWResult(res, 0, true, false, false);
1130 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1131 depth++;
1132 return 1;
1133 }
1134
1135 return 0;
1136 });
1137
1138 vector<DNSRecord> ret;
1139 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1140 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1141 BOOST_CHECK_EQUAL(ret.size(), depth);
1142 /* we have an arbitrary limit at 10 when following a CNAME chain */
1143 BOOST_CHECK_EQUAL(depth, 10 + 2);
1144 }
1145
1146 BOOST_AUTO_TEST_CASE(test_time_limit) {
1147 std::unique_ptr<SyncRes> sr;
1148 initSR(sr);
1149
1150 primeHints();
1151
1152 size_t queries = 0;
1153 const DNSName target("cname.powerdns.com.");
1154
1155 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) {
1156
1157 queries++;
1158
1159 if (isRootServer(ip)) {
1160 setLWResult(res, 0, false, false, true);
1161 /* Pretend that this query took 2000 ms */
1162 res->d_usec = 2000;
1163
1164 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1165 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1166 return 1;
1167 } else if (ip == ComboAddress("192.0.2.1:53")) {
1168
1169 setLWResult(res, 0, true, false, false);
1170 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1171 return 1;
1172 }
1173
1174 return 0;
1175 });
1176
1177 /* Set the maximum time to 1 ms */
1178 SyncRes::s_maxtotusec = 1000;
1179
1180 try {
1181 vector<DNSRecord> ret;
1182 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1183 BOOST_CHECK(false);
1184 }
1185 catch(const ImmediateServFailException& e) {
1186 }
1187 BOOST_CHECK_EQUAL(queries, 1);
1188 }
1189
1190 BOOST_AUTO_TEST_CASE(test_dname_processing) {
1191 std::unique_ptr<SyncRes> sr;
1192 initSR(sr);
1193
1194 primeHints();
1195
1196 const DNSName dnameOwner("powerdns.com");
1197 const DNSName dnameTarget("powerdns.net");
1198
1199 const DNSName target("dname.powerdns.com.");
1200 const DNSName cnameTarget("dname.powerdns.net");
1201
1202 const DNSName uncachedTarget("dname-uncached.powerdns.com.");
1203 const DNSName uncachedCNAMETarget("dname-uncached.powerdns.net.");
1204
1205 const DNSName synthCNAME("cname-uncached.powerdns.com.");
1206 const DNSName synthCNAMETarget("cname-uncached.powerdns.net.");
1207
1208 size_t queries = 0;
1209
1210 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) {
1211 queries++;
1212
1213 if (isRootServer(ip)) {
1214 if (domain.isPartOf(dnameOwner)) {
1215 setLWResult(res, 0, false, false, true);
1216 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1217 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1218 return 1;
1219 }
1220 if (domain.isPartOf(dnameTarget)) {
1221 setLWResult(res, 0, false, false, true);
1222 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1223 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1224 return 1;
1225 }
1226 } else if (ip == ComboAddress("192.0.2.1:53")) {
1227 if (domain == target) {
1228 setLWResult(res, 0, true, false, false);
1229 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
1230 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1231 return 1;
1232 }
1233 } else if (ip == ComboAddress("192.0.2.2:53")) {
1234 if (domain == cnameTarget) {
1235 setLWResult(res, 0, true, false, false);
1236 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1237 }
1238 if (domain == uncachedCNAMETarget) {
1239 setLWResult(res, 0, true, false, false);
1240 addRecordToLW(res, domain, QType::A, "192.0.2.3");
1241 }
1242 return 1;
1243 }
1244 return 0;
1245 });
1246
1247 vector<DNSRecord> ret;
1248 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1249
1250 BOOST_CHECK_EQUAL(res, RCode::NoError);
1251 BOOST_REQUIRE_EQUAL(ret.size(), 3);
1252
1253 BOOST_CHECK_EQUAL(queries, 4);
1254
1255 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1256 BOOST_CHECK(ret[0].d_name == dnameOwner);
1257 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1258
1259 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1260 BOOST_CHECK_EQUAL(ret[1].d_name, target);
1261
1262 BOOST_CHECK(ret[2].d_type == QType::A);
1263 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
1264
1265 // Now check the cache
1266 ret.clear();
1267 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1268
1269 BOOST_CHECK_EQUAL(res, RCode::NoError);
1270 BOOST_REQUIRE_EQUAL(ret.size(), 3);
1271
1272 BOOST_CHECK_EQUAL(queries, 4);
1273
1274 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1275 BOOST_CHECK(ret[0].d_name == dnameOwner);
1276 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1277
1278 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1279 BOOST_CHECK_EQUAL(ret[1].d_name, target);
1280
1281 BOOST_CHECK(ret[2].d_type == QType::A);
1282 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
1283
1284 // Check if we correctly return a synthesizd CNAME, should send out just 1 more query
1285 ret.clear();
1286 res = sr->beginResolve(uncachedTarget, QType(QType::A), QClass::IN, ret);
1287
1288 BOOST_CHECK_EQUAL(res, RCode::NoError);
1289 BOOST_CHECK_EQUAL(queries, 5);
1290
1291 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1292 BOOST_CHECK(ret[0].d_name == dnameOwner);
1293 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1294
1295 BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
1296 BOOST_CHECK_EQUAL(ret[1].d_name, uncachedTarget);
1297 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), uncachedCNAMETarget);
1298
1299 BOOST_CHECK(ret[2].d_type == QType::A);
1300 BOOST_CHECK_EQUAL(ret[2].d_name, uncachedCNAMETarget);
1301
1302 // Check if we correctly return the DNAME from cache when asked
1303 ret.clear();
1304 res = sr->beginResolve(dnameOwner, QType(QType::DNAME), QClass::IN, ret);
1305 BOOST_CHECK_EQUAL(res, RCode::NoError);
1306 BOOST_CHECK_EQUAL(queries, 5);
1307
1308 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1309 BOOST_CHECK(ret[0].d_name == dnameOwner);
1310 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1311
1312 // Check if we correctly return the synthesized CNAME from cache when asked
1313 ret.clear();
1314 res = sr->beginResolve(synthCNAME, QType(QType::CNAME), QClass::IN, ret);
1315 BOOST_CHECK_EQUAL(res, RCode::NoError);
1316 BOOST_CHECK_EQUAL(queries, 5);
1317
1318 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1319 BOOST_CHECK(ret[0].d_name == dnameOwner);
1320 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1321
1322 BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
1323 BOOST_CHECK(ret[1].d_name == synthCNAME);
1324 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), synthCNAMETarget);
1325 }
1326
1327 BOOST_AUTO_TEST_CASE(test_dname_dnssec_secure) {
1328 std::unique_ptr<SyncRes> sr;
1329 initSR(sr, true);
1330 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1331
1332 primeHints();
1333
1334 const DNSName dnameOwner("powerdns");
1335 const DNSName dnameTarget("example");
1336
1337 const DNSName target("dname.powerdns");
1338 const DNSName cnameTarget("dname.example");
1339
1340 testkeysset_t keys;
1341
1342 auto luaconfsCopy = g_luaconfs.getCopy();
1343 luaconfsCopy.dsAnchors.clear();
1344 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
1345 generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
1346 generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
1347 g_luaconfs.setState(luaconfsCopy);
1348
1349 size_t queries = 0;
1350
1351 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) {
1352 queries++;
1353 /* 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
1354 * As such, we need to do some more work to make the answers correct.
1355 */
1356
1357 if (isRootServer(ip)) {
1358 if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
1359 setLWResult(res, 0, true, false, true);
1360 addDNSKEY(keys, domain, 300, res->d_records);
1361 addRRSIG(keys, res->d_records, DNSName("."), 300);
1362 return 1;
1363 }
1364 if (domain.countLabels() == 1 && type == QType::DS) { // powerdns|DS or example|DS
1365 setLWResult(res, 0, true, false, true);
1366 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
1367 addRRSIG(keys, res->d_records, DNSName("."), 300);
1368 return 1;
1369 }
1370 // For the rest, delegate!
1371 if (domain.isPartOf(dnameOwner)) {
1372 setLWResult(res, 0, false, false, true);
1373 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1374 addDS(dnameOwner, 300, res->d_records, keys);
1375 addRRSIG(keys, res->d_records, DNSName("."), 300);
1376 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1377 return 1;
1378 }
1379 if (domain.isPartOf(dnameTarget)) {
1380 setLWResult(res, 0, false, false, true);
1381 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1382 addDS(dnameTarget, 300, res->d_records, keys);
1383 addRRSIG(keys, res->d_records, DNSName("."), 300);
1384 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1385 return 1;
1386 }
1387 } else if (ip == ComboAddress("192.0.2.1:53")) {
1388 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
1389 setLWResult(res, 0, true, false, true);
1390 addDNSKEY(keys, domain, 300, res->d_records);
1391 addRRSIG(keys, res->d_records, domain, 300);
1392 return 1;
1393 }
1394 if (domain == target && type == QType::DS) { // dname.powerdns|DS
1395 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1396 }
1397 if (domain == target) {
1398 setLWResult(res, 0, true, false, false);
1399 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
1400 addRRSIG(keys, res->d_records, dnameOwner, 300);
1401 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
1402 return 1;
1403 }
1404 } else if (ip == ComboAddress("192.0.2.2:53")) {
1405 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // example|DNSKEY
1406 setLWResult(res, 0, true, false, true);
1407 addDNSKEY(keys, domain, 300, res->d_records);
1408 addRRSIG(keys, res->d_records, domain, 300);
1409 return 1;
1410 }
1411 if (domain == cnameTarget && type == QType::DS) { // dname.example|DS
1412 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1413 }
1414 if (domain == cnameTarget) {
1415 setLWResult(res, 0, true, false, false);
1416 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1417 addRRSIG(keys, res->d_records, dnameTarget, 300);
1418 }
1419 return 1;
1420 }
1421 return 0;
1422 });
1423
1424 vector<DNSRecord> ret;
1425 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1426
1427 BOOST_CHECK_EQUAL(res, RCode::NoError);
1428 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
1429 BOOST_REQUIRE_EQUAL(ret.size(), 5); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
1430
1431 BOOST_CHECK_EQUAL(queries, 11);
1432
1433 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1434 BOOST_CHECK(ret[0].d_name == dnameOwner);
1435 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1436
1437 BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
1438 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
1439
1440 BOOST_CHECK(ret[2].d_type == QType::CNAME);
1441 BOOST_CHECK_EQUAL(ret[2].d_name, target);
1442
1443 BOOST_CHECK(ret[3].d_type == QType::A);
1444 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
1445
1446 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
1447 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
1448
1449 // And the cache
1450 ret.clear();
1451 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1452
1453 BOOST_CHECK_EQUAL(res, RCode::NoError);
1454 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
1455 BOOST_REQUIRE_EQUAL(ret.size(), 5); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
1456
1457 BOOST_CHECK_EQUAL(queries, 11);
1458
1459 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1460 BOOST_CHECK(ret[0].d_name == dnameOwner);
1461 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1462
1463 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
1464 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
1465
1466 BOOST_CHECK(ret[2].d_type == QType::CNAME);
1467 BOOST_CHECK_EQUAL(ret[2].d_name, target);
1468
1469 BOOST_CHECK(ret[3].d_type == QType::A);
1470 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
1471
1472 BOOST_CHECK(ret[4].d_type == QType::RRSIG);
1473 BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
1474
1475 }
1476
1477 BOOST_AUTO_TEST_CASE(test_dname_dnssec_insecure) {
1478 /*
1479 * The DNAME itself is signed, but the final A record is not
1480 */
1481 std::unique_ptr<SyncRes> sr;
1482 initSR(sr, true);
1483 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1484
1485 primeHints();
1486
1487 const DNSName dnameOwner("powerdns");
1488 const DNSName dnameTarget("example");
1489
1490 const DNSName target("dname.powerdns");
1491 const DNSName cnameTarget("dname.example");
1492
1493 testkeysset_t keys;
1494
1495 auto luaconfsCopy = g_luaconfs.getCopy();
1496 luaconfsCopy.dsAnchors.clear();
1497 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
1498 generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
1499 g_luaconfs.setState(luaconfsCopy);
1500
1501 size_t queries = 0;
1502
1503 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) {
1504 queries++;
1505
1506 if (isRootServer(ip)) {
1507 if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
1508 setLWResult(res, 0, true, false, true);
1509 addDNSKEY(keys, domain, 300, res->d_records);
1510 addRRSIG(keys, res->d_records, DNSName("."), 300);
1511 return 1;
1512 }
1513 if (domain == dnameOwner && type == QType::DS) { // powerdns|DS
1514 setLWResult(res, 0, true, false, true);
1515 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
1516 addRRSIG(keys, res->d_records, DNSName("."), 300);
1517 return 1;
1518 }
1519 if (domain == dnameTarget && type == QType::DS) { // example|DS
1520 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
1521 }
1522 // For the rest, delegate!
1523 if (domain.isPartOf(dnameOwner)) {
1524 setLWResult(res, 0, false, false, true);
1525 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1526 addDS(dnameOwner, 300, res->d_records, keys);
1527 addRRSIG(keys, res->d_records, DNSName("."), 300);
1528 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1529 return 1;
1530 }
1531 if (domain.isPartOf(dnameTarget)) {
1532 setLWResult(res, 0, false, false, true);
1533 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1534 addDS(dnameTarget, 300, res->d_records, keys);
1535 addRRSIG(keys, res->d_records, DNSName("."), 300);
1536 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1537 return 1;
1538 }
1539 } else if (ip == ComboAddress("192.0.2.1:53")) {
1540 if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
1541 setLWResult(res, 0, true, false, true);
1542 addDNSKEY(keys, domain, 300, res->d_records);
1543 addRRSIG(keys, res->d_records, domain, 300);
1544 return 1;
1545 }
1546 if (domain == target && type == QType::DS) { // dname.powerdns|DS
1547 return genericDSAndDNSKEYHandler(res, domain, dnameOwner, type, keys, false);
1548 }
1549 if (domain == target) {
1550 setLWResult(res, 0, true, false, false);
1551 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
1552 addRRSIG(keys, res->d_records, dnameOwner, 300);
1553 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
1554 return 1;
1555 }
1556 } else if (ip == ComboAddress("192.0.2.2:53")) {
1557 if (domain == target && type == QType::DS) { // dname.example|DS
1558 return genericDSAndDNSKEYHandler(res, domain, dnameTarget, type, keys, false);
1559 }
1560 if (domain == cnameTarget) {
1561 setLWResult(res, 0, true, false, false);
1562 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1563 }
1564 return 1;
1565 }
1566 return 0;
1567 });
1568
1569 vector<DNSRecord> ret;
1570 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1571
1572 BOOST_CHECK_EQUAL(res, RCode::NoError);
1573 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
1574 BOOST_REQUIRE_EQUAL(ret.size(), 4); /* DNAME + RRSIG(DNAME) + CNAME + A */
1575
1576 BOOST_CHECK_EQUAL(queries, 9);
1577
1578 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1579 BOOST_CHECK(ret[0].d_name == dnameOwner);
1580 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1581
1582 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
1583 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
1584
1585 BOOST_CHECK(ret[2].d_type == QType::CNAME);
1586 BOOST_CHECK_EQUAL(ret[2].d_name, target);
1587
1588 BOOST_CHECK(ret[3].d_type == QType::A);
1589 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
1590
1591 // And the cache
1592 ret.clear();
1593 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1594
1595 BOOST_CHECK_EQUAL(res, RCode::NoError);
1596 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
1597 BOOST_REQUIRE_EQUAL(ret.size(), 4); /* DNAME + RRSIG(DNAME) + CNAME + A */
1598
1599 BOOST_CHECK_EQUAL(queries, 9);
1600
1601 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1602 BOOST_CHECK(ret[0].d_name == dnameOwner);
1603 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1604
1605 BOOST_CHECK(ret[1].d_type == QType::RRSIG);
1606 BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
1607
1608 BOOST_CHECK(ret[2].d_type == QType::CNAME);
1609 BOOST_CHECK_EQUAL(ret[2].d_name, target);
1610
1611 BOOST_CHECK(ret[3].d_type == QType::A);
1612 BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
1613 }
1614
1615 BOOST_AUTO_TEST_CASE(test_dname_processing_no_CNAME) {
1616 std::unique_ptr<SyncRes> sr;
1617 initSR(sr);
1618
1619 primeHints();
1620
1621 const DNSName dnameOwner("powerdns.com");
1622 const DNSName dnameTarget("powerdns.net");
1623
1624 const DNSName target("dname.powerdns.com.");
1625 const DNSName cnameTarget("dname.powerdns.net");
1626
1627 size_t queries = 0;
1628
1629 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) {
1630 queries++;
1631
1632 if (isRootServer(ip)) {
1633 if (domain.isPartOf(dnameOwner)) {
1634 setLWResult(res, 0, false, false, true);
1635 addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1636 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1637 return 1;
1638 }
1639 if (domain.isPartOf(dnameTarget)) {
1640 setLWResult(res, 0, false, false, true);
1641 addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1642 addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1643 return 1;
1644 }
1645 } else if (ip == ComboAddress("192.0.2.1:53")) {
1646 if (domain == target) {
1647 setLWResult(res, 0, true, false, false);
1648 addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
1649 // No CNAME, recursor should synth
1650 return 1;
1651 }
1652 } else if (ip == ComboAddress("192.0.2.2:53")) {
1653 if (domain == cnameTarget) {
1654 setLWResult(res, 0, true, false, false);
1655 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1656 }
1657 return 1;
1658 }
1659 return 0;
1660 });
1661
1662 vector<DNSRecord> ret;
1663 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1664
1665 BOOST_CHECK_EQUAL(res, RCode::NoError);
1666 BOOST_REQUIRE_EQUAL(ret.size(), 3);
1667
1668 BOOST_CHECK_EQUAL(queries, 4);
1669
1670 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1671 BOOST_CHECK(ret[0].d_name == dnameOwner);
1672 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1673
1674 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1675 BOOST_CHECK_EQUAL(ret[1].d_name, target);
1676
1677 BOOST_CHECK(ret[2].d_type == QType::A);
1678 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
1679
1680 // Now check the cache
1681 ret.clear();
1682 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1683
1684 BOOST_CHECK_EQUAL(res, RCode::NoError);
1685 BOOST_REQUIRE_EQUAL(ret.size(), 3);
1686
1687 BOOST_CHECK_EQUAL(queries, 4);
1688
1689 BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
1690 BOOST_CHECK(ret[0].d_name == dnameOwner);
1691 BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
1692
1693 BOOST_CHECK(ret[1].d_type == QType::CNAME);
1694 BOOST_CHECK_EQUAL(ret[1].d_name, target);
1695
1696 BOOST_CHECK(ret[2].d_type == QType::A);
1697 BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
1698 }
1699
1700 /*
1701 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
1702
1703 - check out of band support
1704
1705 - check preoutquery
1706
1707 */
1708 BOOST_AUTO_TEST_SUITE_END()