]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc5.cc
7e97556b38a6f7fa8231cc332e17c17defb7d8d3
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc5.cc
1 #ifndef BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_DYN_LINK
3 #endif
4
5 #include <boost/test/unit_test.hpp>
6
7 #include "test-syncres_cc.hh"
8
9 BOOST_AUTO_TEST_SUITE(syncres_cc5)
10
11 BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos)
12 {
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();
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);
28
29 g_luaconfs.setState(luaconfsCopy);
30
31 size_t queriesCount = 0;
32
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
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 */) {
40 queriesCount++;
41
42 DNSName auth = domain;
43 if (domain == target) {
44 auth = DNSName("powerdns.com.");
45 }
46
47 if (type == QType::DS || type == QType::DNSKEY) {
48 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, true, fixedNow);
49 }
50
51 if (isRootServer(address)) {
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);
57 return LWResult::Result::Success;
58 }
59
60 if (address == ComboAddress("192.0.2.1:53")) {
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);
65 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
66 addRRSIG(keys, res->d_records, domain, 300);
67 }
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);
74 }
75 return LWResult::Result::Success;
76 }
77
78 if (address == ComboAddress("192.0.2.2:53")) {
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);
85 }
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 }
91 return LWResult::Result::Success;
92 }
93
94 return LWResult::Result::Timeout;
95 });
96
97 vector<DNSRecord> ret;
98 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
99 BOOST_CHECK_EQUAL(res, RCode::NoError);
100 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
101 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
102 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
108 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
109 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
110 BOOST_CHECK_EQUAL(queriesCount, 6U);
111 }
112
113 static 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
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 */) {
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
147 if (isRootServer(address)) {
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
156 if (address == ComboAddress("192.0.2.1:53")) {
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
174 if (address == ComboAddress("192.0.2.2:53")) {
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);
198 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
205 BOOST_CHECK_EQUAL(queriesCount, 6U);
206 }
207
208 BOOST_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
215 BOOST_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
222 BOOST_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()
231 BOOST_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
239 BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns)
240 {
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();
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);
256 g_luaconfs.setState(luaconfsCopy);
257
258 size_t queriesCount = 0;
259
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 */) {
261 queriesCount++;
262
263 DNSName auth = domain;
264 if (domain == target) {
265 auth = DNSName("powerdns.com.");
266 }
267
268 if (type == QType::DS || type == QType::DNSKEY) {
269 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
270 }
271
272 if (isRootServer(address)) {
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);
278 return LWResult::Result::Success;
279 }
280
281 if (address == ComboAddress("192.0.2.1:53")) {
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);
286 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
287 addRRSIG(keys, res->d_records, domain, 300);
288 }
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);
295 }
296 return LWResult::Result::Success;
297 }
298
299 if (address == ComboAddress("192.0.2.2:53")) {
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);
311 }
312 return LWResult::Result::Success;
313 }
314
315 return LWResult::Result::Timeout;
316 });
317
318 vector<DNSRecord> ret;
319 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
320 BOOST_CHECK_EQUAL(res, RCode::NoError);
321 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
322 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
323 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
329 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
330 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
331 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
338 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
339 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
340 BOOST_CHECK_EQUAL(queriesCount, 7U);
341 }
342
343 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns)
344 {
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();
357 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
358 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
359 g_luaconfs.setState(luaconfsCopy);
360
361 size_t queriesCount = 0;
362
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 */) {
364 queriesCount++;
365
366 DNSName auth = domain;
367 if (domain == target) {
368 auth = DNSName("powerdns.com.");
369 }
370
371 if (type == QType::DS || type == QType::DNSKEY) {
372 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
373 }
374
375 if (isRootServer(address)) {
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);
381 return LWResult::Result::Success;
382 }
383
384 if (address == ComboAddress("192.0.2.1:53")) {
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);
389 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
390 addRRSIG(keys, res->d_records, domain, 300);
391 }
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);
399 }
400 return LWResult::Result::Success;
401 }
402
403 if (address == ComboAddress("192.0.2.2:53")) {
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);
412 }
413 return LWResult::Result::Success;
414 }
415
416 return LWResult::Result::Timeout;
417 });
418
419 vector<DNSRecord> ret;
420 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
421 BOOST_CHECK_EQUAL(res, RCode::NoError);
422 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
423 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
424 BOOST_CHECK_EQUAL(queriesCount, 5U);
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);
430 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
431 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
432 BOOST_CHECK_EQUAL(queriesCount, 5U);
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);
439 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
440 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
441 BOOST_CHECK_EQUAL(queriesCount, 6U);
442 }
443
444 BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta)
445 {
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();
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);
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
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 */) {
470 queriesCount++;
471
472 DNSName auth = domain;
473 if (domain == target) {
474 auth = DNSName("powerdns.com.");
475 }
476
477 if (type == QType::DS || type == QType::DNSKEY) {
478 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
479 }
480
481 if (isRootServer(address)) {
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);
487 return LWResult::Result::Success;
488 }
489
490 if (address == ComboAddress("192.0.2.1:53")) {
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);
495 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
496 addRRSIG(keys, res->d_records, domain, 300);
497 }
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);
504 }
505 return LWResult::Result::Success;
506 }
507
508 if (address == ComboAddress("192.0.2.2:53")) {
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);
520 }
521 return LWResult::Result::Success;
522 }
523
524 return LWResult::Result::Timeout;
525 });
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 */
531 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
532 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
533 BOOST_CHECK_EQUAL(queriesCount, 5U);
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 */
540 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
541 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
542 BOOST_CHECK_EQUAL(queriesCount, 5U);
543 }
544
545 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta)
546 {
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();
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);
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
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 */) {
571 queriesCount++;
572
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);
576 return LWResult::Result::Success;
577 }
578 {
579 if (isRootServer(address)) {
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);
583 return LWResult::Result::Success;
584 }
585 if (address == ComboAddress("192.0.2.1:53")) {
586 if (domain == DNSName("com.")) {
587 setLWResult(res, 0, true, false, true);
588 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
589 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
590 }
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);
595 }
596 return LWResult::Result::Success;
597 }
598 if (address == ComboAddress("192.0.2.2:53")) {
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);
603 }
604 else {
605 setLWResult(res, RCode::NoError, true, false, true);
606 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
607 }
608 return LWResult::Result::Success;
609 }
610 }
611
612 return LWResult::Result::Timeout;
613 });
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 */
620 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
621 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
622 BOOST_CHECK_EQUAL(queriesCount, 3U);
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);
628 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
629 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
630 BOOST_CHECK_EQUAL(queriesCount, 3U);
631 }
632
633 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec)
634 {
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();
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);
649
650 g_luaconfs.setState(luaconfsCopy);
651
652 size_t queriesCount = 0;
653
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 */) {
655 queriesCount++;
656
657 if (type == QType::DS || type == QType::DNSKEY) {
658 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
659 }
660 {
661 if (isRootServer(address)) {
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);
667 return LWResult::Result::Success;
668 }
669 if (address == ComboAddress("192.0.2.1:53")) {
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);
674 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
675 addRRSIG(keys, res->d_records, domain, 300);
676 }
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);
683 }
684 return LWResult::Result::Success;
685 }
686 if (address == ComboAddress("192.0.2.2:53")) {
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);
693 }
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 }
701 return LWResult::Result::Success;
702 }
703 }
704
705 return LWResult::Result::Timeout;
706 });
707
708 vector<DNSRecord> ret;
709 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
710 BOOST_CHECK_EQUAL(res, RCode::NoError);
711 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
712 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
713 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
719 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
720 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
721 BOOST_CHECK_EQUAL(queriesCount, 6U);
722 }
723
724 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec)
725 {
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();
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);
740
741 g_luaconfs.setState(luaconfsCopy);
742
743 size_t queriesCount = 0;
744
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 */) {
746 queriesCount++;
747
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);
759 return LWResult::Result::Success;
760 }
761 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
762 }
763 {
764 if (isRootServer(address)) {
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);
770 return LWResult::Result::Success;
771 }
772 if (address == ComboAddress("192.0.2.1:53")) {
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);
779 }
780 else {
781 setLWResult(res, 0, false, false, true);
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);
786 }
787 return LWResult::Result::Success;
788 }
789 if (address == ComboAddress("192.0.2.2:53")) {
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);
795 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
796 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
797 }
798 else {
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);
803 }
804 }
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 }
815 return LWResult::Result::Success;
816 }
817 }
818
819 return LWResult::Result::Timeout;
820 });
821
822 vector<DNSRecord> ret;
823 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
824 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
825 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
826 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
827 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
833 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
834 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
835 BOOST_CHECK_EQUAL(queriesCount, 6U);
836 }
837
838 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard)
839 {
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();
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);
854
855 g_luaconfs.setState(luaconfsCopy);
856
857 size_t queriesCount = 0;
858
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 */) {
860 queriesCount++;
861
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);
869 return LWResult::Result::Success;
870 }
871 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
872 }
873 {
874 if (isRootServer(address)) {
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);
880 return LWResult::Result::Success;
881 }
882 if (address == ComboAddress("192.0.2.1:53")) {
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);
887 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
888 addRRSIG(keys, res->d_records, domain, 300);
889 }
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);
896 }
897 return LWResult::Result::Success;
898 }
899 if (address == ComboAddress("192.0.2.2:53")) {
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);
907 }
908 else {
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);
912 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
913 }
914 }
915 else {
916 addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600);
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 */
919 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records);
920 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
921 }
922 return LWResult::Result::Success;
923 }
924 }
925
926 return LWResult::Result::Timeout;
927 });
928
929 vector<DNSRecord> ret;
930 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
931 BOOST_CHECK_EQUAL(res, RCode::NoError);
932 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
933 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
934 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
940 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
941 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
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 }
946 BOOST_CHECK_EQUAL(queriesCount, 6U);
947 }
948
949 BOOST_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
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 */) {
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 }
988 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
989 }
990 {
991 if (isRootServer(address)) {
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 }
999 if (address == ComboAddress("192.0.2.1:53")) {
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 }
1016 if (address == ComboAddress("192.0.2.2:53")) {
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 {
1033 addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600);
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 */
1036 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records);
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);
1054 BOOST_CHECK_EQUAL(queriesCount, 6U);
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);
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 }
1066 BOOST_CHECK_EQUAL(queriesCount, 6U);
1067 }
1068
1069 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard)
1070 {
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();
1082 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1083 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1084
1085 g_luaconfs.setState(luaconfsCopy);
1086
1087 size_t queriesCount = 0;
1088
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 */) {
1090 queriesCount++;
1091
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);
1096
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);
1102 return LWResult::Result::Success;
1103 }
1104 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1105 }
1106 {
1107 if (isRootServer(address)) {
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);
1113 return LWResult::Result::Success;
1114 }
1115 if (address == ComboAddress("192.0.2.1:53")) {
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"));
1126 return LWResult::Result::Success;
1127 }
1128 }
1129
1130 return LWResult::Result::Timeout;
1131 });
1132
1133 vector<DNSRecord> ret;
1134 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1135 BOOST_CHECK_EQUAL(res, RCode::NoError);
1136 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1137 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
1138 BOOST_CHECK_EQUAL(queriesCount, 4U);
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);
1144 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1145 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
1146 BOOST_CHECK_EQUAL(queriesCount, 4U);
1147 }
1148
1149 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard)
1150 {
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();
1162 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1163 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1164
1165 g_luaconfs.setState(luaconfsCopy);
1166
1167 size_t queriesCount = 0;
1168
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 */) {
1170 queriesCount++;
1171
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);
1176
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"));
1189 return LWResult::Result::Success;
1190 }
1191 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1192 }
1193 {
1194 if (isRootServer(address)) {
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);
1200 return LWResult::Result::Success;
1201 }
1202 if (address == ComboAddress("192.0.2.1:53")) {
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"));
1217 return LWResult::Result::Success;
1218 }
1219 }
1220
1221 return LWResult::Result::Timeout;
1222 });
1223
1224 vector<DNSRecord> ret;
1225 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1226 BOOST_CHECK_EQUAL(res, RCode::NoError);
1227 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1228 BOOST_REQUIRE_EQUAL(ret.size(), 8U);
1229 BOOST_CHECK_EQUAL(queriesCount, 4U);
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);
1235 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1236 BOOST_REQUIRE_EQUAL(ret.size(), 8U);
1237 BOOST_CHECK_EQUAL(queriesCount, 4U);
1238 }
1239
1240 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_duplicated_nsec3)
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([&](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 */) {
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 {
1285 if (isRootServer(address)) {
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 if (address == 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 /* !! 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. */
1303 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records);
1304 /* then the next closer */
1305 addNSEC3NarrowRecordToLW(domain, DNSName("com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records);
1306 addRRSIG(keys, res->d_records, DNSName("com."), 300);
1307 /* a wildcard matches but has no record for this type */
1308 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1309 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
1310 return LWResult::Result::Success;
1311 }
1312 }
1313
1314 return LWResult::Result::Timeout;
1315 });
1316
1317 vector<DNSRecord> ret;
1318 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1319 BOOST_CHECK_EQUAL(res, RCode::NoError);
1320 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1321 /* because we pass along the duplicated NSEC3 */
1322 BOOST_REQUIRE_EQUAL(ret.size(), 9U);
1323 BOOST_CHECK_EQUAL(queriesCount, 4U);
1324
1325 /* again, to test the cache */
1326 ret.clear();
1327 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1328 BOOST_CHECK_EQUAL(res, RCode::NoError);
1329 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1330 /* because we pass along the duplicated NSEC3 */
1331 BOOST_REQUIRE_EQUAL(ret.size(), 9U);
1332 BOOST_CHECK_EQUAL(queriesCount, 4U);
1333 }
1334
1335 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations)
1336 {
1337 std::unique_ptr<SyncRes> sr;
1338 initSR(sr, true);
1339
1340 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1341
1342 primeHints();
1343 const DNSName target("www.com.");
1344 testkeysset_t keys;
1345
1346 auto luaconfsCopy = g_luaconfs.getCopy();
1347 luaconfsCopy.dsAnchors.clear();
1348 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1349 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1350
1351 g_luaconfs.setState(luaconfsCopy);
1352
1353 size_t queriesCount = 0;
1354
1355 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 */) {
1356 queriesCount++;
1357
1358 if (type == QType::DS || type == QType::DNSKEY) {
1359 if (type == QType::DS && domain == target) {
1360 DNSName auth("com.");
1361 setLWResult(res, 0, true, false, true);
1362
1363 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1364 addRRSIG(keys, res->d_records, auth, 300);
1365 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
1366 /* first the closest encloser */
1367 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records, g_maxNSEC3Iterations + 100);
1368 addRRSIG(keys, res->d_records, auth, 300);
1369 /* then the next closer */
1370 addNSEC3NarrowRecordToLW(domain, DNSName("com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records, g_maxNSEC3Iterations + 100);
1371 addRRSIG(keys, res->d_records, auth, 300);
1372 /* a wildcard matches but has no record for this type */
1373 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records, g_maxNSEC3Iterations + 100);
1374 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
1375 return LWResult::Result::Success;
1376 }
1377 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1378 }
1379 {
1380 if (isRootServer(address)) {
1381 setLWResult(res, 0, false, false, true);
1382 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
1383 addDS(DNSName("com."), 300, res->d_records, keys);
1384 addRRSIG(keys, res->d_records, DNSName("."), 300);
1385 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1386 return LWResult::Result::Success;
1387 }
1388 if (address == ComboAddress("192.0.2.1:53")) {
1389 setLWResult(res, 0, true, false, true);
1390 /* no data */
1391 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1392 addRRSIG(keys, res->d_records, DNSName("com."), 300);
1393 /* no record for this name */
1394 /* first the closest encloser */
1395 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records, g_maxNSEC3Iterations + 100);
1396 addRRSIG(keys, res->d_records, DNSName("com."), 300);
1397 /* then the next closer */
1398 addNSEC3NarrowRecordToLW(domain, DNSName("com."), {QType::RRSIG, QType::NSEC}, 600, res->d_records, g_maxNSEC3Iterations + 100);
1399 addRRSIG(keys, res->d_records, DNSName("com."), 300);
1400 /* a wildcard matches but has no record for this type */
1401 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records, g_maxNSEC3Iterations + 100);
1402 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
1403 return LWResult::Result::Success;
1404 }
1405 }
1406
1407 return LWResult::Result::Timeout;
1408 });
1409
1410 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
1411 vector<DNSRecord> ret;
1412 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1413 BOOST_CHECK_EQUAL(res, RCode::NoError);
1414 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
1415 BOOST_REQUIRE_EQUAL(ret.size(), 8U);
1416 BOOST_CHECK_EQUAL(queriesCount, 4U);
1417
1418 /* again, to test the cache */
1419 ret.clear();
1420 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1421 BOOST_CHECK_EQUAL(res, RCode::NoError);
1422 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
1423 BOOST_REQUIRE_EQUAL(ret.size(), 8U);
1424 BOOST_CHECK_EQUAL(queriesCount, 4U);
1425 }
1426
1427 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard)
1428 {
1429 std::unique_ptr<SyncRes> sr;
1430 initSR(sr, true);
1431
1432 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1433
1434 primeHints();
1435 const DNSName target("www.sub.powerdns.com.");
1436 testkeysset_t keys;
1437
1438 auto luaconfsCopy = g_luaconfs.getCopy();
1439 luaconfsCopy.dsAnchors.clear();
1440 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1441 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1442 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1443
1444 g_luaconfs.setState(luaconfsCopy);
1445
1446 size_t queriesCount = 0;
1447
1448 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 */) {
1449 queriesCount++;
1450
1451 if (type == QType::DS || type == QType::DNSKEY) {
1452 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
1453 setLWResult(res, RCode::NoError, true, false, true);
1454 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1455 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1456 if (domain == DNSName("sub.powerdns.com")) {
1457 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1458 }
1459 else if (domain == target) {
1460 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1461 }
1462 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1463 return LWResult::Result::Success;
1464 }
1465 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1466 }
1467 {
1468 if (isRootServer(address)) {
1469 setLWResult(res, 0, false, false, true);
1470 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
1471 addDS(DNSName("com."), 300, res->d_records, keys);
1472 addRRSIG(keys, res->d_records, DNSName("."), 300);
1473 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1474 return LWResult::Result::Success;
1475 }
1476 if (address == ComboAddress("192.0.2.1:53")) {
1477 if (domain == DNSName("com.")) {
1478 setLWResult(res, 0, true, false, true);
1479 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
1480 addRRSIG(keys, res->d_records, domain, 300);
1481 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1482 addRRSIG(keys, res->d_records, domain, 300);
1483 }
1484 else {
1485 setLWResult(res, 0, false, false, true);
1486 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
1487 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
1488 addRRSIG(keys, res->d_records, DNSName("com."), 300);
1489 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1490 }
1491 return LWResult::Result::Success;
1492 }
1493 if (address == ComboAddress("192.0.2.2:53")) {
1494 setLWResult(res, 0, true, false, true);
1495 if (type == QType::NS) {
1496 if (domain == DNSName("powerdns.com.")) {
1497 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
1498 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1499 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1500 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1501 }
1502 else {
1503 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1504 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1505 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1506 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1507 }
1508 }
1509 else {
1510 addRecordToLW(res, domain, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, 600);
1511 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1512 /* we need to add the proof that this name does not exist, so the wildcard may apply */
1513 /* first the closest encloser */
1514 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records);
1515 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1516 /* then the next closer */
1517 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 60, res->d_records);
1518 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1519 }
1520 return LWResult::Result::Success;
1521 }
1522 }
1523
1524 return LWResult::Result::Timeout;
1525 });
1526
1527 vector<DNSRecord> ret;
1528 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1529 BOOST_CHECK_EQUAL(res, RCode::NoError);
1530 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1531 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
1532 BOOST_CHECK_EQUAL(queriesCount, 6U);
1533
1534 /* again, to test the cache */
1535 ret.clear();
1536 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1537 BOOST_CHECK_EQUAL(res, RCode::NoError);
1538 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1539 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
1540 for (const auto& rec : ret) {
1541 /* check that we applied the lowest TTL, here this is from the NSEC3 proving that the exact name did not exist (next closer) */
1542 BOOST_CHECK_LE(rec.d_ttl, 60U);
1543 }
1544 BOOST_CHECK_EQUAL(queriesCount, 6U);
1545 }
1546
1547 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations)
1548 {
1549 std::unique_ptr<SyncRes> sr;
1550 initSR(sr, true);
1551
1552 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1553
1554 primeHints();
1555 const DNSName target("www.powerdns.com.");
1556 testkeysset_t keys;
1557
1558 auto luaconfsCopy = g_luaconfs.getCopy();
1559 luaconfsCopy.dsAnchors.clear();
1560 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1561 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1562 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1563
1564 g_luaconfs.setState(luaconfsCopy);
1565
1566 size_t queriesCount = 0;
1567
1568 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 */) {
1569 queriesCount++;
1570
1571 if (type == QType::DS || type == QType::DNSKEY) {
1572 if (type == QType::DS && domain == target) {
1573 setLWResult(res, RCode::NoError, true, false, true);
1574 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1575 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1576 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1577 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1578 return LWResult::Result::Success;
1579 }
1580 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1581 }
1582 {
1583 if (isRootServer(address)) {
1584 setLWResult(res, 0, false, false, true);
1585 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
1586 addDS(DNSName("com."), 300, res->d_records, keys);
1587 addRRSIG(keys, res->d_records, DNSName("."), 300);
1588 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1589 return LWResult::Result::Success;
1590 }
1591 if (address == ComboAddress("192.0.2.1:53")) {
1592 if (domain == DNSName("com.")) {
1593 setLWResult(res, 0, true, false, true);
1594 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
1595 addRRSIG(keys, res->d_records, domain, 300);
1596 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1597 addRRSIG(keys, res->d_records, domain, 300);
1598 }
1599 else {
1600 setLWResult(res, 0, false, false, true);
1601 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
1602 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
1603 addRRSIG(keys, res->d_records, DNSName("com."), 300);
1604 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1605 }
1606 return LWResult::Result::Success;
1607 }
1608 if (address == ComboAddress("192.0.2.2:53")) {
1609 setLWResult(res, 0, true, false, true);
1610 if (type == QType::NS) {
1611 if (domain == DNSName("powerdns.com.")) {
1612 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
1613 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1614 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1615 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1616 }
1617 else {
1618 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1619 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1620 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1621 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1622 }
1623 }
1624 else {
1625 addRecordToLW(res, domain, QType::A, "192.0.2.42");
1626 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1627 /* we need to add the proof that this name does not exist, so the wildcard may apply */
1628 /* first the closest encloser */
1629 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records);
1630 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1631 /* then the next closer */
1632 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, res->d_records, g_maxNSEC3Iterations + 100);
1633 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1634 }
1635 return LWResult::Result::Success;
1636 }
1637 }
1638
1639 return LWResult::Result::Timeout;
1640 });
1641
1642 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
1643 we should end up Insecure */
1644 vector<DNSRecord> ret;
1645 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1646 BOOST_CHECK_EQUAL(res, RCode::NoError);
1647 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
1648 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
1649 BOOST_CHECK_EQUAL(queriesCount, 6U);
1650
1651 /* again, to test the cache */
1652 ret.clear();
1653 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1654 BOOST_CHECK_EQUAL(res, RCode::NoError);
1655 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
1656 BOOST_REQUIRE_EQUAL(ret.size(), 6U);
1657 BOOST_CHECK_EQUAL(queriesCount, 6U);
1658 }
1659
1660 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing)
1661 {
1662 std::unique_ptr<SyncRes> sr;
1663 initSR(sr, true);
1664
1665 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1666
1667 primeHints();
1668 const DNSName target("www.powerdns.com.");
1669 testkeysset_t keys;
1670
1671 auto luaconfsCopy = g_luaconfs.getCopy();
1672 luaconfsCopy.dsAnchors.clear();
1673 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1674 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1675 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1676
1677 g_luaconfs.setState(luaconfsCopy);
1678
1679 size_t queriesCount = 0;
1680
1681 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 */) {
1682 queriesCount++;
1683
1684 if (type == QType::DS || type == QType::DNSKEY) {
1685 if (type == QType::DS && domain == target) {
1686 setLWResult(res, RCode::NoError, true, false, true);
1687 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1688 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1689 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1690 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1691 return LWResult::Result::Success;
1692 }
1693 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1694 }
1695 {
1696 if (isRootServer(address)) {
1697 setLWResult(res, 0, false, false, true);
1698 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
1699 addDS(DNSName("com."), 300, res->d_records, keys);
1700 addRRSIG(keys, res->d_records, DNSName("."), 300);
1701 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1702 return LWResult::Result::Success;
1703 }
1704 if (address == ComboAddress("192.0.2.1:53")) {
1705 if (domain == DNSName("com.")) {
1706 setLWResult(res, 0, true, false, true);
1707 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
1708 addRRSIG(keys, res->d_records, domain, 300);
1709 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1710 addRRSIG(keys, res->d_records, domain, 300);
1711 }
1712 else {
1713 setLWResult(res, 0, false, false, true);
1714 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
1715 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
1716 addRRSIG(keys, res->d_records, DNSName("com."), 300);
1717 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1718 }
1719 return LWResult::Result::Success;
1720 }
1721 if (address == ComboAddress("192.0.2.2:53")) {
1722 setLWResult(res, 0, true, false, true);
1723 if (type == QType::NS) {
1724 if (domain == DNSName("powerdns.com.")) {
1725 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
1726 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1727 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1728 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1729 }
1730 else {
1731 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1732 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1733 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1734 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
1735 }
1736 }
1737 else {
1738 addRecordToLW(res, domain, QType::A, "192.0.2.42");
1739 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1740 }
1741 return LWResult::Result::Success;
1742 }
1743 }
1744
1745 return LWResult::Result::Timeout;
1746 });
1747
1748 vector<DNSRecord> ret;
1749 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1750 BOOST_CHECK_EQUAL(res, RCode::NoError);
1751 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusInvalidDenial);
1752 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1753 BOOST_CHECK_EQUAL(queriesCount, 7U);
1754
1755 /* again, to test the cache */
1756 ret.clear();
1757 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1758 BOOST_CHECK_EQUAL(res, RCode::NoError);
1759 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusInvalidDenial);
1760 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1761 BOOST_CHECK_EQUAL(queriesCount, 7U);
1762 }
1763
1764 BOOST_AUTO_TEST_CASE(test_dnssec_validation_wildcard_expanded_onto_itself)
1765 {
1766 std::unique_ptr<SyncRes> sr;
1767 initSR(sr, true);
1768
1769 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1770
1771 primeHints();
1772 const DNSName target("*.powerdns.com.");
1773 testkeysset_t keys;
1774
1775 auto luaconfsCopy = g_luaconfs.getCopy();
1776 luaconfsCopy.dsAnchors.clear();
1777 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1778 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1779 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1780
1781 g_luaconfs.setState(luaconfsCopy);
1782
1783 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 */) {
1784 if (type == QType::DS || type == QType::DNSKEY) {
1785 if (domain == target) {
1786 const auto auth = DNSName("powerdns.com.");
1787 /* we don't want a cut there */
1788 setLWResult(res, 0, true, false, true);
1789 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1790 addRRSIG(keys, res->d_records, auth, 300);
1791 /* add a NSEC denying the DS */
1792 std::set<uint16_t> types = {QType::NSEC};
1793 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
1794 addRRSIG(keys, res->d_records, auth, 300);
1795 return LWResult::Result::Success;
1796 }
1797 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1798 }
1799 {
1800 setLWResult(res, 0, true, false, true);
1801 addRecordToLW(res, domain, QType::A, "192.0.2.42");
1802 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com"));
1803 /* we don't _really_ need to add the proof that the exact name does not exist because it does,
1804 it's the wildcard itself, but let's do it so other validators don't choke on it */
1805 addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1806 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1807 return LWResult::Result::Success;
1808 }
1809 });
1810
1811 vector<DNSRecord> ret;
1812 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1813 BOOST_CHECK_EQUAL(res, RCode::NoError);
1814 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1815 /* A + RRSIG, NSEC + RRSIG */
1816 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1817 }
1818
1819 BOOST_AUTO_TEST_CASE(test_dnssec_validation_wildcard_expanded_onto_itself_nodata)
1820 {
1821 std::unique_ptr<SyncRes> sr;
1822 initSR(sr, true);
1823
1824 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1825
1826 primeHints();
1827 const DNSName target("*.powerdns.com.");
1828 testkeysset_t keys;
1829
1830 auto luaconfsCopy = g_luaconfs.getCopy();
1831 luaconfsCopy.dsAnchors.clear();
1832 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1833 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1834 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1835
1836 g_luaconfs.setState(luaconfsCopy);
1837
1838 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 */) {
1839 if (type == QType::DS || type == QType::DNSKEY) {
1840 if (domain == target) {
1841 const auto auth = DNSName("powerdns.com.");
1842 /* we don't want a cut there */
1843 setLWResult(res, 0, true, false, true);
1844 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1845 addRRSIG(keys, res->d_records, auth, 300);
1846 /* add a NSEC denying the DS */
1847 std::set<uint16_t> types = {QType::NSEC};
1848 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
1849 addRRSIG(keys, res->d_records, auth, 300);
1850 return LWResult::Result::Success;
1851 }
1852 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1853 }
1854 {
1855 setLWResult(res, 0, true, false, true);
1856 addRecordToLW(res, domain, QType::SOA, "powerdns.com. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1857 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
1858 /* add the proof that the exact name does exist but that this type does not */
1859 addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("\\000.*.powerdns.com."), {QType::AAAA, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1860 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1861 return LWResult::Result::Success;
1862 }
1863 });
1864
1865 vector<DNSRecord> ret;
1866 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1867 BOOST_CHECK_EQUAL(res, RCode::NoError);
1868 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1869 /* SOA + RRSIG, NSEC + RRSIG */
1870 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1871 }
1872
1873 BOOST_AUTO_TEST_CASE(test_dnssec_validation_wildcard_like_expanded_from_wildcard)
1874 {
1875 std::unique_ptr<SyncRes> sr;
1876 initSR(sr, true);
1877
1878 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1879
1880 primeHints();
1881 const DNSName target("*.sub.powerdns.com.");
1882 testkeysset_t keys;
1883
1884 auto luaconfsCopy = g_luaconfs.getCopy();
1885 luaconfsCopy.dsAnchors.clear();
1886 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1887 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1888 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1889
1890 g_luaconfs.setState(luaconfsCopy);
1891
1892 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 */) {
1893 if (type == QType::DS || type == QType::DNSKEY) {
1894 if (domain == target) {
1895 const auto auth = DNSName("powerdns.com.");
1896 /* we don't want a cut there */
1897 setLWResult(res, 0, true, false, true);
1898 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1899 addRRSIG(keys, res->d_records, auth, 300);
1900 addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1901 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1902 return LWResult::Result::Success;
1903 }
1904 if (domain == DNSName("sub.powerdns.com.")) {
1905 const auto auth = DNSName("powerdns.com.");
1906 /* we don't want a cut there */
1907 setLWResult(res, 0, true, false, true);
1908 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1909 addRRSIG(keys, res->d_records, auth, 300);
1910 /* add a NSEC denying the DS */
1911 addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1912 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1913 return LWResult::Result::Success;
1914 }
1915 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
1916 }
1917 {
1918 setLWResult(res, 0, true, false, true);
1919 addRecordToLW(res, domain, QType::A, "192.0.2.42");
1920 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, false, boost::none, DNSName("*.powerdns.com"));
1921 addNSECRecordToLW(DNSName("*.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
1922 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
1923 return LWResult::Result::Success;
1924 }
1925 });
1926
1927 vector<DNSRecord> ret;
1928 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1929 BOOST_CHECK_EQUAL(res, RCode::NoError);
1930 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1931 /* A + RRSIG, NSEC + RRSIG */
1932 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1933 }
1934
1935 // Tests PR 8648
1936 BOOST_AUTO_TEST_CASE(test_dnssec_incomplete_cache_zonecut_qm)
1937 {
1938 std::unique_ptr<SyncRes> sr;
1939 initSR(sr, true, false);
1940 sr->setQNameMinimization();
1941 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1942
1943 primeHints();
1944 testkeysset_t keys;
1945
1946 auto luaconfsCopy = g_luaconfs.getCopy();
1947 luaconfsCopy.dsAnchors.clear();
1948 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1949 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1950 generateKeyMaterial(DNSName("net."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1951 generateKeyMaterial(DNSName("herokuapp.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1952 generateKeyMaterial(DNSName("nsone.net."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1953 g_luaconfs.setState(luaconfsCopy);
1954
1955 size_t queriesCount = 0;
1956
1957 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 */) {
1958 queriesCount++;
1959
1960 DNSName auth(domain);
1961 DNSName com("com.");
1962 DNSName net("net.");
1963 DNSName nsone("nsone.net.");
1964 DNSName hero("herokuapp.com.");
1965 DNSName p03nsone("dns1.p03.nsone.net.");
1966
1967 // cerr << ip.toString() << ": " << domain << '|' << QType(type).toString() << endl;
1968 if (type == QType::DS || type == QType::DNSKEY) {
1969 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
1970 }
1971
1972 if (isRootServer(address)) {
1973 if (domain == com) {
1974 setLWResult(res, 0, false, false, true);
1975 addRecordToLW(res, com, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 3600);
1976 addDS(com, 300, res->d_records, keys);
1977 addRRSIG(keys, res->d_records, g_rootdnsname, 300);
1978 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1979 }
1980 else if (domain == net) {
1981 setLWResult(res, 0, false, false, true);
1982 addRecordToLW(res, net, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 3600);
1983 addDS(net, 300, res->d_records, keys);
1984 addRRSIG(keys, res->d_records, g_rootdnsname, 300);
1985 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1986 }
1987 else if (domain == p03nsone && type == QType::A) {
1988 setLWResult(res, 0, false, false, true);
1989 addRecordToLW(res, nsone, QType::NS, "dns1.p01.nsone.net.", DNSResourceRecord::AUTHORITY, 3600);
1990 addNSECRecordToLW(nsone, DNSName("zzz.nsone.net."), {QType::NS, QType::SOA, QType::RRSIG, QType::DNSKEY}, 600, res->d_records);
1991 addRRSIG(keys, res->d_records, net, 300);
1992 addRecordToLW(res, "dns1.p01.nsone.net", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1993 }
1994 else {
1995 BOOST_ASSERT(0);
1996 }
1997 return LWResult::Result::Success;
1998 }
1999
2000 if (address == ComboAddress("192.0.2.1:53")) {
2001 if (domain == hero && type == QType::NS) {
2002 setLWResult(res, 0, false, false, true);
2003 addRecordToLW(res, hero, QType::NS, "dns1.p03.nsone.net.", DNSResourceRecord::AUTHORITY, 3600);
2004 addDS(hero, 300, res->d_records, keys);
2005 addRRSIG(keys, res->d_records, com, 300);
2006 }
2007 else if (domain == nsone && type == QType::A) {
2008 setLWResult(res, 0, false, false, true);
2009 addRecordToLW(res, nsone, QType::NS, "dns1.p01.nsone.net.", DNSResourceRecord::AUTHORITY, 3600);
2010 addNSECRecordToLW(nsone, DNSName("zzz.nsone.net."), {QType::NS, QType::SOA, QType::RRSIG, QType::DNSKEY}, 600, res->d_records);
2011 addRRSIG(keys, res->d_records, net, 300);
2012 addRecordToLW(res, "dns1.p01.nsone.net", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2013 }
2014 else {
2015 BOOST_ASSERT(0);
2016 }
2017 return LWResult::Result::Success;
2018 }
2019 if (address == ComboAddress("192.0.2.2:53")) {
2020 DNSName p01("p01.nsone.net.");
2021 DNSName p03("p03.nsone.net.");
2022 DNSName p01nsone("dns1.p01.nsone.net.");
2023 if (domain == hero && type == QType::NS) {
2024 setLWResult(res, 0, true, false, true);
2025 addRecordToLW(res, hero, QType::NS, "dns1.p03.nsone.net.", DNSResourceRecord::ANSWER, 3600);
2026 addRRSIG(keys, res->d_records, hero, 300);
2027 }
2028 else if (domain == p01nsone && type == QType::A) {
2029 setLWResult(res, 0, true, false, true);
2030 addRecordToLW(res, p01nsone, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 3600);
2031 }
2032 else if (domain == p03nsone && type == QType::A) {
2033 setLWResult(res, 0, true, false, true);
2034 addRecordToLW(res, p03nsone, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 3600);
2035 }
2036 else if (domain == p01 && type == QType::A) {
2037 setLWResult(res, 0, true, false, true);
2038 addRecordToLW(res, p01, QType::SOA, "dns1.p01.nsone.net. hostmaster.nsone.net. 123 43200 7200 1209600 10800", DNSResourceRecord::AUTHORITY, 3600);
2039 }
2040 else if (domain == p03 && type == QType::A) {
2041 setLWResult(res, 0, true, false, true);
2042 addRecordToLW(res, p03, QType::SOA, "dns1.p03.nsone.net. hostmaster.nsone.net. 123 43200 7200 1209600 10800", DNSResourceRecord::AUTHORITY, 3600);
2043 }
2044 else {
2045 BOOST_ASSERT(0);
2046 }
2047 return LWResult::Result::Success;
2048 }
2049 BOOST_ASSERT(0);
2050 return LWResult::Result::Timeout;
2051 });
2052
2053 vector<DNSRecord> ret;
2054 int res = sr->beginResolve(DNSName("herokuapp.com."), QType(QType::NS), QClass::IN, ret);
2055 BOOST_CHECK_EQUAL(res, RCode::NoError);
2056 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2057 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2058 BOOST_CHECK_EQUAL(queriesCount, 8U);
2059
2060 ret.clear();
2061 res = sr->beginResolve(DNSName("dns1.p03.nsone.net."), QType(QType::A), QClass::IN, ret);
2062 BOOST_CHECK_EQUAL(res, RCode::NoError);
2063 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2064 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2065 BOOST_CHECK_EQUAL(queriesCount, 14U);
2066 }
2067
2068 BOOST_AUTO_TEST_CASE(test_dnssec_secure_servfail_ds)
2069 {
2070 std::unique_ptr<SyncRes> sr;
2071 initSR(sr, true);
2072
2073 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2074
2075 primeHints();
2076 const DNSName target("powerdns.com.");
2077 const ComboAddress targetAddr("192.0.2.42");
2078 testkeysset_t keys;
2079
2080 auto luaconfsCopy = g_luaconfs.getCopy();
2081 luaconfsCopy.dsAnchors.clear();
2082 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2083 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2084 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2085
2086 g_luaconfs.setState(luaconfsCopy);
2087
2088 size_t queriesCount = 0;
2089
2090 /* make sure that the signature inception and validity times are computed
2091 based on the SyncRes time, not the current one, in case the function
2092 takes too long. */
2093
2094 const time_t fixedNow = sr->getNow().tv_sec;
2095
2096 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 */) {
2097 queriesCount++;
2098
2099 DNSName auth = domain;
2100 if (domain == target) {
2101 auth = DNSName("powerdns.com.");
2102 }
2103
2104 if (type == QType::DS && domain == DNSName("powerdns.com.")) {
2105 /* time out */
2106 return LWResult::Result::Timeout;
2107 }
2108
2109 if (type == QType::DS || type == QType::DNSKEY) {
2110 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, true, fixedNow);
2111 }
2112
2113 if (isRootServer(address)) {
2114 setLWResult(res, 0, false, false, true);
2115 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2116 addDS(DNSName("com."), 300, res->d_records, keys);
2117 addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow);
2118 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2119 return LWResult::Result::Success;
2120 }
2121
2122 if (address == ComboAddress("192.0.2.1:53")) {
2123 if (domain == DNSName("com.")) {
2124 setLWResult(res, 0, true, false, true);
2125 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
2126 addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow);
2127 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2128 addRRSIG(keys, res->d_records, domain, 300);
2129 }
2130 else {
2131 setLWResult(res, 0, false, false, true);
2132 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2133 /* do NOT include the DS here */
2134 //addDS(auth, 300, res->d_records, keys);
2135 //addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow);
2136 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2137 }
2138 return LWResult::Result::Success;
2139 }
2140
2141 if (address == ComboAddress("192.0.2.2:53")) {
2142 if (type == QType::NS) {
2143 setLWResult(res, 0, true, false, true);
2144 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
2145 addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow);
2146 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2147 addRRSIG(keys, res->d_records, auth, 300);
2148 }
2149 else {
2150 setLWResult(res, RCode::NoError, true, false, true);
2151 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2152 addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow);
2153 }
2154 return LWResult::Result::Success;
2155 }
2156
2157 return LWResult::Result::Timeout;
2158 });
2159
2160 vector<DNSRecord> ret;
2161 try {
2162 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2163 BOOST_CHECK(false);
2164 }
2165 catch (const ImmediateServFailException& e) {
2166 BOOST_CHECK(e.reason.find("Server Failure while retrieving DS records for powerdns.com") != string::npos);
2167 }
2168
2169 /* and a second time to check nothing was cached */
2170 try {
2171 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2172 BOOST_CHECK(false);
2173 }
2174 catch (const ImmediateServFailException& e) {
2175 BOOST_CHECK(e.reason.find("Server Failure while retrieving DS records for powerdns.com") != string::npos);
2176 }
2177 }
2178
2179 static void dnssec_secure_servfail_dnskey(DNSSECMode mode, vState /* expectedValidationResult */)
2180 {
2181 std::unique_ptr<SyncRes> sr;
2182 initSR(sr, true);
2183
2184 setDNSSECValidation(sr, mode);
2185
2186 primeHints();
2187 const DNSName target("powerdns.com.");
2188 const ComboAddress targetAddr("192.0.2.42");
2189 testkeysset_t keys;
2190
2191 auto luaconfsCopy = g_luaconfs.getCopy();
2192 luaconfsCopy.dsAnchors.clear();
2193 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2194 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2195 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2196
2197 g_luaconfs.setState(luaconfsCopy);
2198
2199 size_t queriesCount = 0;
2200
2201 /* make sure that the signature inception and validity times are computed
2202 based on the SyncRes time, not the current one, in case the function
2203 takes too long. */
2204
2205 const time_t fixedNow = sr->getNow().tv_sec;
2206
2207 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 */) {
2208 queriesCount++;
2209
2210 DNSName auth = domain;
2211 if (domain == target) {
2212 auth = DNSName("powerdns.com.");
2213 }
2214
2215 if (type == QType::DNSKEY && domain == DNSName("powerdns.com.")) {
2216 /* time out */
2217 return LWResult::Result::Timeout;
2218 }
2219
2220 if (type == QType::DS || type == QType::DNSKEY) {
2221 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, true, fixedNow);
2222 }
2223
2224 if (isRootServer(address)) {
2225 setLWResult(res, 0, false, false, true);
2226 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2227 addDS(DNSName("com."), 300, res->d_records, keys);
2228 addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow);
2229 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2230 return LWResult::Result::Success;
2231 }
2232
2233 if (address == ComboAddress("192.0.2.1:53")) {
2234 if (domain == DNSName("com.")) {
2235 setLWResult(res, 0, true, false, true);
2236 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
2237 addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow);
2238 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2239 addRRSIG(keys, res->d_records, domain, 300);
2240 }
2241 else {
2242 setLWResult(res, 0, false, false, true);
2243 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2244 addDS(auth, 300, res->d_records, keys);
2245 addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow);
2246 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2247 }
2248 return LWResult::Result::Success;
2249 }
2250
2251 if (address == ComboAddress("192.0.2.2:53")) {
2252 if (type == QType::NS) {
2253 setLWResult(res, 0, true, false, true);
2254 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
2255 addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow);
2256 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2257 addRRSIG(keys, res->d_records, auth, 300);
2258 }
2259 else {
2260 setLWResult(res, RCode::NoError, true, false, true);
2261 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2262 addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow);
2263 }
2264 return LWResult::Result::Success;
2265 }
2266
2267 return LWResult::Result::Timeout;
2268 });
2269
2270 vector<DNSRecord> ret;
2271 try {
2272 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2273 BOOST_CHECK(false);
2274 }
2275 catch (const ImmediateServFailException& e) {
2276 BOOST_CHECK(e.reason.find("Server Failure while retrieving DNSKEY records for powerdns.com") != string::npos);
2277 }
2278
2279 /* and a second time to check nothing was cached */
2280 try {
2281 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2282 BOOST_CHECK(false);
2283 }
2284 catch (const ImmediateServFailException& e) {
2285 BOOST_CHECK(e.reason.find("Server Failure while retrieving DNSKEY records for powerdns.com") != string::npos);
2286 }
2287 }
2288
2289 BOOST_AUTO_TEST_CASE(test_dnssec_secure_servfail_dnskey)
2290 {
2291 dnssec_secure_servfail_dnskey(DNSSECMode::ValidateAll, vState::Indeterminate);
2292 dnssec_secure_servfail_dnskey(DNSSECMode::Off, vState::Indeterminate);
2293 }
2294
2295 // Same test as above but powerdns.com is now Insecure according to parent, so failure to retrieve DNSSKEYs
2296 // should be mostly harmless.
2297 static void dnssec_secure_servfail_dnskey_insecure(DNSSECMode mode, vState expectedValidationResult)
2298 {
2299 std::unique_ptr<SyncRes> sr;
2300 initSR(sr, true);
2301
2302 setDNSSECValidation(sr, mode);
2303
2304 primeHints();
2305 const DNSName target("powerdns.com.");
2306 const ComboAddress targetAddr("192.0.2.42");
2307
2308 // We use two sets of keys, as powerdns.com is Insecure according to parent but returns signed results,
2309 // triggering a (failing) DNSKEY retrieval.
2310 testkeysset_t keys;
2311 testkeysset_t pdnskeys;
2312
2313 auto luaconfsCopy = g_luaconfs.getCopy();
2314 luaconfsCopy.dsAnchors.clear();
2315 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2316 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2317 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, pdnskeys);
2318
2319 g_luaconfs.setState(luaconfsCopy);
2320
2321 size_t queriesCount = 0;
2322
2323 /* make sure that the signature inception and validity times are computed
2324 based on the SyncRes time, not the current one, in case the function
2325 takes too long. */
2326
2327 const time_t fixedNow = sr->getNow().tv_sec;
2328
2329 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 */) {
2330 queriesCount++;
2331
2332 DNSName auth = domain;
2333 if (domain == target) {
2334 auth = DNSName("powerdns.com.");
2335 }
2336
2337 if (type == QType::DNSKEY && domain == DNSName("powerdns.com.")) {
2338 /* time out */
2339 return LWResult::Result::Timeout;
2340 }
2341
2342 if (type == QType::DS || type == QType::DNSKEY) {
2343 // This one does not know about pdnskeys, so it will declare powerdns.com as Insecure
2344 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, true, fixedNow);
2345 }
2346
2347 if (isRootServer(address)) {
2348 setLWResult(res, 0, false, false, true);
2349 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2350 addDS(DNSName("com."), 300, res->d_records, keys);
2351 addRRSIG(keys, res->d_records, DNSName("."), 300, false, boost::none, boost::none, fixedNow);
2352 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2353 return LWResult::Result::Success;
2354 }
2355
2356 if (address == ComboAddress("192.0.2.1:53")) {
2357 if (domain == DNSName("com.")) {
2358 setLWResult(res, 0, true, false, true);
2359 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
2360 addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow);
2361 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2362 addRRSIG(keys, res->d_records, domain, 300);
2363 }
2364 else {
2365 setLWResult(res, 0, false, false, true);
2366 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2367 addDS(auth, 300, res->d_records, keys);
2368 addRRSIG(keys, res->d_records, DNSName("com."), 300, false, boost::none, boost::none, fixedNow);
2369 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2370 }
2371 return LWResult::Result::Success;
2372 }
2373
2374 if (address == ComboAddress("192.0.2.2:53")) {
2375 if (type == QType::NS) {
2376 setLWResult(res, 0, true, false, true);
2377 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
2378 addRRSIG(pdnskeys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow);
2379 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2380 addRRSIG(pdnskeys, res->d_records, auth, 300);
2381 }
2382 else {
2383 setLWResult(res, RCode::NoError, true, false, true);
2384 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2385 addRRSIG(pdnskeys, res->d_records, auth, 300, false, boost::none, boost::none, fixedNow);
2386 }
2387 return LWResult::Result::Success;
2388 }
2389
2390 return LWResult::Result::Timeout;
2391 });
2392
2393 vector<DNSRecord> ret;
2394 auto res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2395 BOOST_CHECK_EQUAL(res, 0);
2396 BOOST_CHECK_EQUAL(sr->getValidationState(), expectedValidationResult);
2397 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2398 }
2399
2400 BOOST_AUTO_TEST_CASE(test_dnssec_secure_servfail_dnskey_insecure)
2401 {
2402 dnssec_secure_servfail_dnskey_insecure(DNSSECMode::ValidateAll, vState::Insecure);
2403 dnssec_secure_servfail_dnskey_insecure(DNSSECMode::Off, vState::Insecure);
2404 }
2405
2406 BOOST_AUTO_TEST_SUITE_END()