1 #define BOOST_TEST_DYN_LINK
2 #include <boost/test/unit_test.hpp>
4 #include "test-syncres_cc.hh"
6 BOOST_AUTO_TEST_SUITE(syncres_cc1
)
8 BOOST_AUTO_TEST_CASE(test_root_primed
) {
9 std::unique_ptr
<SyncRes
> sr
;
14 const DNSName
target("a.root-servers.net.");
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
);
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
);
33 BOOST_AUTO_TEST_CASE(test_root_primed_ns
) {
34 std::unique_ptr
<SyncRes
> sr
;
38 const DNSName
target(".");
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 */
43 size_t queriesCount
= 0;
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
) {
48 if (domain
== target
&& type
== QType::NS
) {
50 setLWResult(res
, 0, true, false, true);
51 char addr
[] = "a.root-servers.net.";
52 for (char idx
= 'a'; idx
<= 'm'; idx
++) {
54 addRecordToLW(res
, g_rootdnsname
, QType::NS
, std::string(addr
), DNSResourceRecord::ANSWER
, 3600);
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);
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);
73 BOOST_AUTO_TEST_CASE(test_root_not_primed
) {
74 std::unique_ptr
<SyncRes
> sr
;
77 size_t queriesCount
= 0;
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
) {
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);
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);
103 BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response
) {
104 std::unique_ptr
<SyncRes
> sr
;
106 std::set
<ComboAddress
> downServers
;
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.
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
) {
114 downServers
.insert(ip
);
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);
129 static void test_edns_formerr_fallback_f(bool sample
) {
130 std::unique_ptr
<SyncRes
> sr
;
133 sr
->setQNameMinimization();
135 ComboAddress noEDNSServer
;
136 size_t queriesWithEDNS
= 0;
137 size_t queriesWithoutEDNS
= 0;
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) {
144 setLWResult(res
, RCode::FormErr
);
148 queriesWithoutEDNS
++;
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");
156 return sample
? basicRecordsForQnameMinimization(res
, domain
, type
) : 0;
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
);
172 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback
) {
173 test_edns_formerr_fallback_f(false);
176 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback_qmin
) {
177 // DISABLED UNTIL QNAME MINIMIZATON IS THERE
179 test_edns_formerr_fallback_f(true);
182 BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled
) {
183 std::unique_ptr
<SyncRes
> sr
;
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.
190 size_t queriesWithEDNS
= 0;
191 size_t queriesWithoutEDNS
= 0;
192 std::set
<ComboAddress
> usedServers
;
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
) {
196 if (EDNS0Level
> 0) {
200 queriesWithoutEDNS
++;
202 usedServers
.insert(ip
);
204 if (type
== QType::DNAME
) {
205 setLWResult(res
, RCode::FormErr
);
206 if (EDNS0Level
> 0) {
207 res
->d_haveEDNS
= true;
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
);
230 BOOST_AUTO_TEST_CASE(test_meta_types
) {
231 std::unique_ptr
<SyncRes
> sr
;
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 };
236 for (const auto qtype
: invalidTypes
) {
237 size_t queriesCount
= 0;
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
) {
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);
255 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp
) {
256 std::unique_ptr
<SyncRes
> sr
;
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
) {
261 setLWResult(res
, 0, false, true, false);
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");
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
);
281 BOOST_AUTO_TEST_CASE(test_tc_over_tcp
) {
282 std::unique_ptr
<SyncRes
> sr
;
285 size_t tcpQueriesCount
= 0;
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
) {
289 setLWResult(res
, 0, true, true, false);
293 /* first TCP query is answered with a TC response */
295 if (tcpQueriesCount
== 1) {
296 setLWResult(res
, 0, true, true, false);
299 setLWResult(res
, 0, true, false, false);
302 addRecordToLW(res
, domain
, QType::A
, "192.0.2.1");
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);
314 BOOST_AUTO_TEST_CASE(test_all_nss_down
) {
315 std::unique_ptr
<SyncRes
> sr
;
317 std::set
<ComboAddress
> downServers
;
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
) {
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);
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);
341 downServers
.insert(ip
);
346 DNSName
target("powerdns.com.");
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);
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
));
361 BOOST_AUTO_TEST_CASE(test_all_nss_network_error
) {
362 std::unique_ptr
<SyncRes
> sr
;
364 std::set
<ComboAddress
> downServers
;
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
) {
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);
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);
388 downServers
.insert(ip
);
393 /* exact same test than the previous one, except instead of a time out we fake a network error */
394 DNSName
target("powerdns.com.");
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);
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
));
409 BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue
) {
410 std::unique_ptr
<SyncRes
> sr
;
415 DNSName
target("www.powerdns.com.");
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
) {
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);
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);
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");
441 else if (type
== QType::AAAA
) {
442 addRecordToLW(res
, "pdns-public-ns2.powerdns.net.", QType::AAAA
, "2001:DB8::3");
445 else if (domain
== target
) {
446 if (type
== QType::A
) {
447 addRecordToLW(res
, domain
, QType::A
, "192.0.2.1");
449 else if (type
== QType::AAAA
) {
450 addRecordToLW(res
, domain
, QType::AAAA
, "2001:DB8::1");
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);
464 BOOST_AUTO_TEST_CASE(test_os_limit_errors
) {
465 std::unique_ptr
<SyncRes
> sr
;
467 std::set
<ComboAddress
> downServers
;
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
) {
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);
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);
491 if (downServers
.size() < 3) {
492 /* only the last one will answer */
493 downServers
.insert(ip
);
497 setLWResult(res
, 0, true, false, true);
498 addRecordToLW(res
, "powerdns.com.", QType::A
, "192.0.2.42");
504 DNSName
target("powerdns.com.");
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);
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
));
520 BOOST_AUTO_TEST_CASE(test_glued_referral
) {
521 std::unique_ptr
<SyncRes
> sr
;
526 const DNSName
target("powerdns.com.");
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
) {
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);
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);
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");
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
);
569 BOOST_AUTO_TEST_CASE(test_glueless_referral
) {
570 std::unique_ptr
<SyncRes
> sr
;
575 const DNSName
target("powerdns.com.");
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
) {
579 if (isRootServer(ip
)) {
580 setLWResult(res
, 0, false, false, true);
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);
588 setLWResult(res
, RCode::NXDomain
, false, false, true);
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);
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);
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");
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");
616 setLWResult(res
, RCode::NXDomain
, false, false, true);
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");
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
);
637 BOOST_AUTO_TEST_CASE(test_edns_subnet_by_domain
) {
638 std::unique_ptr
<SyncRes
> sr
;
643 const DNSName
target("powerdns.com.");
644 SyncRes::addEDNSDomain(target
);
646 EDNSSubnetOpts incomingECS
;
647 incomingECS
.source
= Netmask("192.0.2.128/32");
648 sr
->setQuerySource(ComboAddress(), boost::optional
<const EDNSSubnetOpts
&>(incomingECS
));
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
) {
652 BOOST_REQUIRE(srcmask
);
653 BOOST_CHECK_EQUAL(srcmask
->toString(), "192.0.2.0/24");
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);
660 /* this one did not use the ECS info */
661 srcmask
= boost::none
;
664 } else if (ip
== ComboAddress("192.0.2.1:53")) {
666 setLWResult(res
, 0, true, false, false);
667 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
669 /* this one did, but only up to a precision of /16, not the full /24 */
670 srcmask
= Netmask("192.0.0.0/16");
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);
691 for (const auto& entry
: SyncRes::s_ecsResponsesBySubnetSize6
) {
692 BOOST_CHECK_EQUAL(entry
.second
, 0);
696 BOOST_AUTO_TEST_CASE(test_edns_subnet_by_addr
) {
697 std::unique_ptr
<SyncRes
> sr
;
702 const DNSName
target("powerdns.com.");
703 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
705 EDNSSubnetOpts incomingECS
;
706 incomingECS
.source
= Netmask("2001:DB8::FF/128");
707 sr
->setQuerySource(ComboAddress(), boost::optional
<const EDNSSubnetOpts
&>(incomingECS
));
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
) {
711 if (isRootServer(ip
)) {
712 BOOST_REQUIRE(!srcmask
);
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);
718 } else if (ip
== ComboAddress("192.0.2.1:53")) {
720 BOOST_REQUIRE(srcmask
);
721 BOOST_CHECK_EQUAL(srcmask
->toString(), "2001:db8::/56");
723 setLWResult(res
, 0, true, false, false);
724 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
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);
744 for (const auto& entry
: SyncRes::s_ecsResponsesBySubnetSize6
) {
745 BOOST_CHECK_EQUAL(entry
.second
, entry
.first
== 55 ? 1 : 0);
749 BOOST_AUTO_TEST_CASE(test_ecs_use_requestor
) {
750 std::unique_ptr
<SyncRes
> sr
;
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
);
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
) {
762 if (isRootServer(ip
)) {
763 BOOST_REQUIRE(!srcmask
);
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);
769 } else if (ip
== ComboAddress("192.0.2.1:53")) {
771 BOOST_REQUIRE(srcmask
);
772 BOOST_CHECK_EQUAL(srcmask
->toString(), "192.0.2.0/24");
774 setLWResult(res
, 0, true, false, false);
775 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
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
);
790 BOOST_AUTO_TEST_CASE(test_ecs_use_scope_zero
) {
791 std::unique_ptr
<SyncRes
> sr
;
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
);
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
) {
805 if (isRootServer(ip
)) {
806 BOOST_REQUIRE(!srcmask
);
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);
812 } else if (ip
== ComboAddress("192.0.2.1:53")) {
814 BOOST_REQUIRE(srcmask
);
815 BOOST_CHECK_EQUAL(srcmask
->toString(), "127.0.0.1/32");
817 setLWResult(res
, 0, true, false, false);
818 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
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
);
833 BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask
) {
834 std::unique_ptr
<SyncRes
> sr
;
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
));
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
) {
849 if (isRootServer(ip
)) {
850 BOOST_REQUIRE(!srcmask
);
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);
856 } else if (ip
== ComboAddress("192.0.2.1:53")) {
858 BOOST_REQUIRE(srcmask
);
859 BOOST_CHECK_EQUAL(srcmask
->toString(), "192.0.0.0/16");
861 setLWResult(res
, 0, true, false, false);
862 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
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
);
877 BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask_zero
) {
878 std::unique_ptr
<SyncRes
> sr
;
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
));
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
) {
893 if (isRootServer(ip
)) {
894 BOOST_REQUIRE(!srcmask
);
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);
900 } else if (ip
== ComboAddress("192.0.2.1:53")) {
902 BOOST_REQUIRE(srcmask
);
903 BOOST_CHECK_EQUAL(srcmask
->toString(), "127.0.0.1/32");
905 setLWResult(res
, 0, true, false, false);
906 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
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
);
921 BOOST_AUTO_TEST_CASE(test_following_cname
) {
922 std::unique_ptr
<SyncRes
> sr
;
927 const DNSName
target("cname.powerdns.com.");
928 const DNSName
cnameTarget("cname-target.powerdns.com");
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
) {
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);
937 } else if (ip
== ComboAddress("192.0.2.1:53")) {
939 if (domain
== target
) {
940 setLWResult(res
, 0, true, false, false);
941 addRecordToLW(res
, domain
, QType::CNAME
, cnameTarget
.toString());
944 else if (domain
== cnameTarget
) {
945 setLWResult(res
, 0, true, false, false);
946 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
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
);
965 BOOST_AUTO_TEST_CASE(test_cname_nxdomain
) {
966 std::unique_ptr
<SyncRes
> sr
;
971 const DNSName
target("cname.powerdns.com.");
972 const DNSName
cnameTarget("cname-target.powerdns.com");
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
) {
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);
981 } else if (ip
== ComboAddress("192.0.2.1:53")) {
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);
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
);
1007 /* a second time, to check the cache */
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
);
1017 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname
) {
1018 std::unique_ptr
<SyncRes
> sr
;
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");
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
) {
1032 if (isRootServer(ip
)) {
1034 setLWResult(res
, 0, false, false, true);
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);
1039 } else if (ip
== ComboAddress("192.0.2.1:53")) {
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
);
1046 } else if (domain
== cnameTarget
) {
1047 setLWResult(res
, 0, true, false, false);
1048 addRecordToLW(res
, cnameTarget
, QType::A
, "192.0.2.3");
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"));
1070 BOOST_AUTO_TEST_CASE(test_cname_loop
) {
1071 std::unique_ptr
<SyncRes
> sr
;
1077 const DNSName
target("cname.powerdns.com.");
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
) {
1083 if (isRootServer(ip
)) {
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);
1089 } else if (ip
== ComboAddress("192.0.2.1:53")) {
1091 if (domain
== target
) {
1092 setLWResult(res
, 0, true, false, false);
1093 addRecordToLW(res
, domain
, QType::CNAME
, domain
.toString());
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);
1110 BOOST_AUTO_TEST_CASE(test_cname_depth
) {
1111 std::unique_ptr
<SyncRes
> sr
;
1117 const DNSName
target("cname.powerdns.com.");
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
) {
1121 if (isRootServer(ip
)) {
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);
1127 } else if (ip
== ComboAddress("192.0.2.1:53")) {
1129 setLWResult(res
, 0, true, false, false);
1130 addRecordToLW(res
, domain
, QType::CNAME
, std::to_string(depth
) + "-cname.powerdns.com");
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);
1146 BOOST_AUTO_TEST_CASE(test_time_limit
) {
1147 std::unique_ptr
<SyncRes
> sr
;
1153 const DNSName
target("cname.powerdns.com.");
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
) {
1159 if (isRootServer(ip
)) {
1160 setLWResult(res
, 0, false, false, true);
1161 /* Pretend that this query took 2000 ms */
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);
1167 } else if (ip
== ComboAddress("192.0.2.1:53")) {
1169 setLWResult(res
, 0, true, false, false);
1170 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
1177 /* Set the maximum time to 1 ms */
1178 SyncRes::s_maxtotusec
= 1000;
1181 vector
<DNSRecord
> ret
;
1182 sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
1185 catch(const ImmediateServFailException
& e
) {
1187 BOOST_CHECK_EQUAL(queries
, 1);
1190 BOOST_AUTO_TEST_CASE(test_dname_processing
) {
1191 std::unique_ptr
<SyncRes
> sr
;
1196 const DNSName
dnameOwner("powerdns.com");
1197 const DNSName
dnameTarget("powerdns.net");
1199 const DNSName
target("dname.powerdns.com.");
1200 const DNSName
cnameTarget("dname.powerdns.net");
1202 const DNSName
uncachedTarget("dname-uncached.powerdns.com.");
1203 const DNSName
uncachedCNAMETarget("dname-uncached.powerdns.net.");
1205 const DNSName
synthCNAME("cname-uncached.powerdns.com.");
1206 const DNSName
synthCNAMETarget("cname-uncached.powerdns.net.");
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
) {
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);
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);
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());
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");
1238 if (domain
== uncachedCNAMETarget
) {
1239 setLWResult(res
, 0, true, false, false);
1240 addRecordToLW(res
, domain
, QType::A
, "192.0.2.3");
1247 vector
<DNSRecord
> ret
;
1248 int res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
1250 BOOST_CHECK_EQUAL(res
, RCode::NoError
);
1251 BOOST_REQUIRE_EQUAL(ret
.size(), 3);
1253 BOOST_CHECK_EQUAL(queries
, 4);
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
);
1259 BOOST_CHECK(ret
[1].d_type
== QType::CNAME
);
1260 BOOST_CHECK_EQUAL(ret
[1].d_name
, target
);
1262 BOOST_CHECK(ret
[2].d_type
== QType::A
);
1263 BOOST_CHECK_EQUAL(ret
[2].d_name
, cnameTarget
);
1265 // Now check the cache
1267 res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
1269 BOOST_CHECK_EQUAL(res
, RCode::NoError
);
1270 BOOST_REQUIRE_EQUAL(ret
.size(), 3);
1272 BOOST_CHECK_EQUAL(queries
, 4);
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
);
1278 BOOST_CHECK(ret
[1].d_type
== QType::CNAME
);
1279 BOOST_CHECK_EQUAL(ret
[1].d_name
, target
);
1281 BOOST_CHECK(ret
[2].d_type
== QType::A
);
1282 BOOST_CHECK_EQUAL(ret
[2].d_name
, cnameTarget
);
1284 // Check if we correctly return a synthesizd CNAME, should send out just 1 more query
1286 res
= sr
->beginResolve(uncachedTarget
, QType(QType::A
), QClass::IN
, ret
);
1288 BOOST_CHECK_EQUAL(res
, RCode::NoError
);
1289 BOOST_CHECK_EQUAL(queries
, 5);
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
);
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
);
1299 BOOST_CHECK(ret
[2].d_type
== QType::A
);
1300 BOOST_CHECK_EQUAL(ret
[2].d_name
, uncachedCNAMETarget
);
1302 // Check if we correctly return the DNAME from cache when asked
1304 res
= sr
->beginResolve(dnameOwner
, QType(QType::DNAME
), QClass::IN
, ret
);
1305 BOOST_CHECK_EQUAL(res
, RCode::NoError
);
1306 BOOST_CHECK_EQUAL(queries
, 5);
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
);
1312 // Check if we correctly return the synthesized CNAME from cache when asked
1314 res
= sr
->beginResolve(synthCNAME
, QType(QType::CNAME
), QClass::IN
, ret
);
1315 BOOST_CHECK_EQUAL(res
, RCode::NoError
);
1316 BOOST_CHECK_EQUAL(queries
, 5);
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
);
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
);
1327 BOOST_AUTO_TEST_CASE(test_dname_dnssec_secure
) {
1328 std::unique_ptr
<SyncRes
> sr
;
1330 setDNSSECValidation(sr
, DNSSECMode::ValidateAll
);
1334 const DNSName
dnameOwner("powerdns");
1335 const DNSName
dnameTarget("example");
1337 const DNSName
target("dname.powerdns");
1338 const DNSName
cnameTarget("dname.example");
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
);
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
) {
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.
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);
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);
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);
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);
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);
1394 if (domain
== target
&& type
== QType::DS
) { // dname.powerdns|DS
1395 return genericDSAndDNSKEYHandler(res
, domain
, domain
, type
, keys
, false);
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
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);
1411 if (domain
== cnameTarget
&& type
== QType::DS
) { // dname.example|DS
1412 return genericDSAndDNSKEYHandler(res
, domain
, domain
, type
, keys
, false);
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);
1424 vector
<DNSRecord
> ret
;
1425 int res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
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) */
1431 BOOST_CHECK_EQUAL(queries
, 11);
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
);
1437 BOOST_REQUIRE(ret
[1].d_type
== QType::RRSIG
);
1438 BOOST_CHECK_EQUAL(ret
[1].d_name
, dnameOwner
);
1440 BOOST_CHECK(ret
[2].d_type
== QType::CNAME
);
1441 BOOST_CHECK_EQUAL(ret
[2].d_name
, target
);
1443 BOOST_CHECK(ret
[3].d_type
== QType::A
);
1444 BOOST_CHECK_EQUAL(ret
[3].d_name
, cnameTarget
);
1446 BOOST_CHECK(ret
[4].d_type
== QType::RRSIG
);
1447 BOOST_CHECK_EQUAL(ret
[4].d_name
, cnameTarget
);
1451 res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
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) */
1457 BOOST_CHECK_EQUAL(queries
, 11);
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
);
1463 BOOST_CHECK(ret
[1].d_type
== QType::RRSIG
);
1464 BOOST_CHECK_EQUAL(ret
[1].d_name
, dnameOwner
);
1466 BOOST_CHECK(ret
[2].d_type
== QType::CNAME
);
1467 BOOST_CHECK_EQUAL(ret
[2].d_name
, target
);
1469 BOOST_CHECK(ret
[3].d_type
== QType::A
);
1470 BOOST_CHECK_EQUAL(ret
[3].d_name
, cnameTarget
);
1472 BOOST_CHECK(ret
[4].d_type
== QType::RRSIG
);
1473 BOOST_CHECK_EQUAL(ret
[4].d_name
, cnameTarget
);
1477 BOOST_AUTO_TEST_CASE(test_dname_dnssec_insecure
) {
1479 * The DNAME itself is signed, but the final A record is not
1481 std::unique_ptr
<SyncRes
> sr
;
1483 setDNSSECValidation(sr
, DNSSECMode::ValidateAll
);
1487 const DNSName
dnameOwner("powerdns");
1488 const DNSName
dnameTarget("example");
1490 const DNSName
target("dname.powerdns");
1491 const DNSName
cnameTarget("dname.example");
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
);
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
) {
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);
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);
1519 if (domain
== dnameTarget
&& type
== QType::DS
) { // example|DS
1520 return genericDSAndDNSKEYHandler(res
, domain
, DNSName("."), type
, keys
);
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);
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);
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);
1546 if (domain
== target
&& type
== QType::DS
) { // dname.powerdns|DS
1547 return genericDSAndDNSKEYHandler(res
, domain
, dnameOwner
, type
, keys
, false);
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
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);
1560 if (domain
== cnameTarget
) {
1561 setLWResult(res
, 0, true, false, false);
1562 addRecordToLW(res
, domain
, QType::A
, "192.0.2.2");
1569 vector
<DNSRecord
> ret
;
1570 int res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
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 */
1576 BOOST_CHECK_EQUAL(queries
, 9);
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
);
1582 BOOST_CHECK(ret
[1].d_type
== QType::RRSIG
);
1583 BOOST_CHECK_EQUAL(ret
[1].d_name
, dnameOwner
);
1585 BOOST_CHECK(ret
[2].d_type
== QType::CNAME
);
1586 BOOST_CHECK_EQUAL(ret
[2].d_name
, target
);
1588 BOOST_CHECK(ret
[3].d_type
== QType::A
);
1589 BOOST_CHECK_EQUAL(ret
[3].d_name
, cnameTarget
);
1593 res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
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 */
1599 BOOST_CHECK_EQUAL(queries
, 9);
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
);
1605 BOOST_CHECK(ret
[1].d_type
== QType::RRSIG
);
1606 BOOST_CHECK_EQUAL(ret
[1].d_name
, dnameOwner
);
1608 BOOST_CHECK(ret
[2].d_type
== QType::CNAME
);
1609 BOOST_CHECK_EQUAL(ret
[2].d_name
, target
);
1611 BOOST_CHECK(ret
[3].d_type
== QType::A
);
1612 BOOST_CHECK_EQUAL(ret
[3].d_name
, cnameTarget
);
1615 BOOST_AUTO_TEST_CASE(test_dname_processing_no_CNAME
) {
1616 std::unique_ptr
<SyncRes
> sr
;
1621 const DNSName
dnameOwner("powerdns.com");
1622 const DNSName
dnameTarget("powerdns.net");
1624 const DNSName
target("dname.powerdns.com.");
1625 const DNSName
cnameTarget("dname.powerdns.net");
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
) {
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);
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);
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
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");
1662 vector
<DNSRecord
> ret
;
1663 int res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
1665 BOOST_CHECK_EQUAL(res
, RCode::NoError
);
1666 BOOST_REQUIRE_EQUAL(ret
.size(), 3);
1668 BOOST_CHECK_EQUAL(queries
, 4);
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
);
1674 BOOST_CHECK(ret
[1].d_type
== QType::CNAME
);
1675 BOOST_CHECK_EQUAL(ret
[1].d_name
, target
);
1677 BOOST_CHECK(ret
[2].d_type
== QType::A
);
1678 BOOST_CHECK_EQUAL(ret
[2].d_name
, cnameTarget
);
1680 // Now check the cache
1682 res
= sr
->beginResolve(target
, QType(QType::A
), QClass::IN
, ret
);
1684 BOOST_CHECK_EQUAL(res
, RCode::NoError
);
1685 BOOST_REQUIRE_EQUAL(ret
.size(), 3);
1687 BOOST_CHECK_EQUAL(queries
, 4);
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
);
1693 BOOST_CHECK(ret
[1].d_type
== QType::CNAME
);
1694 BOOST_CHECK_EQUAL(ret
[1].d_name
, target
);
1696 BOOST_CHECK(ret
[2].d_type
== QType::A
);
1697 BOOST_CHECK_EQUAL(ret
[2].d_name
, cnameTarget
);
1701 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
1703 - check out of band support
1708 BOOST_AUTO_TEST_SUITE_END()