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