]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc8.cc
rec: CVE-2023-50387 and CVE-2023-50868
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc8.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_cc8)
10
11 static dState getDenial(const cspmap_t& validrrsets, const DNSName& qname, uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof, const OptLog& log = std::nullopt, bool needWildcardProof = true, unsigned int wildcardLabelsCount = 0)
12 {
13 pdns::validation::ValidationContext context;
14 context.d_nsec3IterationsRemainingQuota = std::numeric_limits<decltype(context.d_nsec3IterationsRemainingQuota)>::max();
15 return getDenial(validrrsets, qname, qtype, referralToUnsigned, wantsNoDataProof, context, log, needWildcardProof, wildcardLabelsCount);
16 }
17
18 BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap)
19 {
20 initSR();
21
22 testkeysset_t keys;
23 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
24
25 vector<DNSRecord> records;
26
27 sortedRecords_t recordContents;
28 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
29
30 /*
31 No wrap test case:
32 a.example.org. -> d.example.org. denies the existence of b.example.org.
33 */
34 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
35 recordContents.insert(records.at(0).getContent());
36 addRRSIG(keys, records, DNSName("example.org."), 300);
37 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
38 records.clear();
39
40 ContentSigPair pair;
41 pair.records = recordContents;
42 pair.signatures = signatureContents;
43 cspmap_t denialMap;
44 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
45
46 /* add wildcard denial */
47 recordContents.clear();
48 signatureContents.clear();
49 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
50 recordContents.insert(records.at(0).getContent());
51 addRRSIG(keys, records, DNSName("example.org."), 300);
52 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
53 records.clear();
54
55 pair.records = recordContents;
56 pair.signatures = signatureContents;
57 denialMap[std::pair(DNSName("example.org."), QType::NSEC)] = pair;
58
59 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
60 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
61
62 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
63 /* let's check that d.example.org. is not denied by this proof */
64 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
65 }
66
67 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1)
68 {
69 initSR();
70
71 testkeysset_t keys;
72 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
73
74 vector<DNSRecord> records;
75
76 sortedRecords_t recordContents;
77 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
78
79 /*
80 Wrap case 1 test case:
81 z.example.org. -> b.example.org. denies the existence of a.example.org.
82 */
83 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
84 recordContents.insert(records.at(0).getContent());
85 addRRSIG(keys, records, DNSName("example.org."), 300);
86 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
87 records.clear();
88
89 ContentSigPair pair;
90 pair.records = recordContents;
91 pair.signatures = signatureContents;
92 cspmap_t denialMap;
93 denialMap[std::pair(DNSName("z.example.org."), QType::NSEC)] = pair;
94
95 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
96 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
97
98 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
99 /* let's check that d.example.org. is not denied by this proof */
100 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
101 }
102
103 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2)
104 {
105 initSR();
106
107 testkeysset_t keys;
108 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
109
110 vector<DNSRecord> records;
111
112 sortedRecords_t recordContents;
113 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
114
115 /*
116 Wrap case 2 test case:
117 y.example.org. -> a.example.org. denies the existence of z.example.org.
118 */
119 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
120 recordContents.insert(records.at(0).getContent());
121 addRRSIG(keys, records, DNSName("example.org."), 300);
122 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
123 records.clear();
124
125 ContentSigPair pair;
126 pair.records = recordContents;
127 pair.signatures = signatureContents;
128 cspmap_t denialMap;
129 denialMap[std::pair(DNSName("y.example.org."), QType::NSEC)] = pair;
130
131 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
132 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
133
134 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
135 /* let's check that d.example.org. is not denied by this proof */
136 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
137 }
138
139 BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec)
140 {
141 initSR();
142
143 testkeysset_t keys;
144 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
145
146 vector<DNSRecord> records;
147
148 sortedRecords_t recordContents;
149 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
150
151 /*
152 Only one NSEC in the whole zone test case:
153 a.example.org. -> a.example.org. denies the existence of b.example.org.
154 */
155 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
156 recordContents.insert(records.at(0).getContent());
157 addRRSIG(keys, records, DNSName("example.org."), 300);
158 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
159 records.clear();
160
161 ContentSigPair pair;
162 pair.records = recordContents;
163 pair.signatures = signatureContents;
164 cspmap_t denialMap;
165 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
166
167 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
168 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
169
170 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
171 /* let's check that d.example.org. is not denied by this proof */
172 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
173 }
174
175 BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial)
176 {
177 initSR();
178
179 testkeysset_t keys;
180 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
181
182 vector<DNSRecord> records;
183
184 sortedRecords_t recordContents;
185 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
186
187 /*
188 The RRSIG from "." denies the existence of anything between a. and c.,
189 including b.
190 */
191 addNSECRecordToLW(DNSName("a."), DNSName("c."), {QType::NS}, 600, records);
192 recordContents.insert(records.at(0).getContent());
193 addRRSIG(keys, records, DNSName("."), 300);
194 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
195 records.clear();
196
197 ContentSigPair pair;
198 pair.records = recordContents;
199 pair.signatures = signatureContents;
200 cspmap_t denialMap;
201 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
202
203 /* add wildcard denial */
204 recordContents.clear();
205 signatureContents.clear();
206 addNSECRecordToLW(DNSName("."), DNSName("+"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
207 recordContents.insert(records.at(0).getContent());
208 addRRSIG(keys, records, DNSName("."), 300);
209 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
210 records.clear();
211
212 pair.records = recordContents;
213 pair.signatures = signatureContents;
214 denialMap[std::pair(DNSName("."), QType::NSEC)] = pair;
215
216 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
217 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
218 }
219
220 BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial)
221 {
222 initSR();
223
224 testkeysset_t keys;
225 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
226
227 vector<DNSRecord> records;
228
229 sortedRecords_t recordContents;
230 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
231
232 /*
233 The RRSIG from "." denies the existence of any type except NS at a.
234 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
235 signer field that is shorter than the owner name of the NSEC RR) it can't
236 be used to deny anything except the whole name (which does not make sense here)
237 or a DS.
238 */
239 addNSECRecordToLW(DNSName("a."), DNSName("b."), {QType::NS}, 600, records);
240 recordContents.insert(records.at(0).getContent());
241 addRRSIG(keys, records, DNSName("."), 300);
242 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
243 records.clear();
244
245 ContentSigPair pair;
246 pair.records = recordContents;
247 pair.signatures = signatureContents;
248 cspmap_t denialMap;
249 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
250
251 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
252 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
253 nonexistence of any RRs below that zone cut, which include all RRs at
254 that (original) owner name other than DS RRs, and all RRs below that
255 owner name regardless of type.
256 */
257
258 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
259 /* no data means the qname/qtype is not denied, because an ancestor
260 delegation NSEC can only deny the DS */
261 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
262
263 /* it can not be used to deny any RRs below that owner name either */
264 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
265 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
266
267 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
268 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
269 }
270
271 BOOST_AUTO_TEST_CASE(test_nsec_ds_denial_from_child)
272 {
273 initSR();
274
275 testkeysset_t keys;
276 generateKeyMaterial(DNSName("org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
277 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
278
279 vector<DNSRecord> records;
280
281 sortedRecords_t recordContents;
282 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
283
284 addNSECRecordToLW(DNSName("example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
285 recordContents.insert(records.at(0).getContent());
286 addRRSIG(keys, records, DNSName("example.org."), 300);
287 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
288 records.clear();
289
290 ContentSigPair pair;
291 pair.records = recordContents;
292 pair.signatures = signatureContents;
293 cspmap_t denialMap;
294 denialMap[std::pair(DNSName("example.org."), QType::NSEC)] = pair;
295
296 /* check that this NSEC from the child zone can deny a AAAA at the apex */
297 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("example.org."), QType::AAAA, false, true, std::nullopt, true), dState::NXQTYPE);
298
299 /* but not that the DS does not exist, since we need the parent for that */
300 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("example.org."), QType::DS, false, true, std::nullopt, true), dState::NODENIAL);
301 }
302
303 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial)
304 {
305 initSR();
306
307 testkeysset_t keys;
308 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
309
310 vector<DNSRecord> records;
311
312 sortedRecords_t recordContents;
313 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
314
315 /*
316 * RFC 5155 section 8.9:
317 * If there is an NSEC3 RR present in the response that matches the
318 * delegation name, then the validator MUST ensure that the NS bit is
319 * set and that the DS bit is not set in the Type Bit Maps field of the
320 * NSEC3 RR.
321 */
322 /*
323 The RRSIG from "." denies the existence of any type at a.
324 NS should be set if it was proving an insecure delegation, let's check that
325 we correctly detect that it's not.
326 */
327 addNSECRecordToLW(DNSName("a."), DNSName("b."), {}, 600, records);
328 recordContents.insert(records.at(0).getContent());
329 addRRSIG(keys, records, DNSName("."), 300);
330 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
331 records.clear();
332
333 ContentSigPair pair;
334 pair.records = recordContents;
335 pair.signatures = signatureContents;
336 cspmap_t denialMap;
337 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
338
339 /* Insecure because the NS is not set, so while it does
340 denies the DS, it can't prove an insecure delegation */
341 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
342 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
343 }
344
345 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial_soa)
346 {
347 initSR();
348
349 testkeysset_t keys;
350 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
351
352 vector<DNSRecord> records;
353
354 sortedRecords_t recordContents;
355 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
356
357 /*
358 * RFC 5155 section 8.9:
359 * If there is an NSEC3 RR present in the response that matches the
360 * delegation name, then the validator MUST ensure that the NS bit is
361 * set and that the DS bit is not set in the Type Bit Maps field of the
362 * NSEC3 RR.
363 */
364 /*
365 The RRSIG from "." denies the existence of any type at a except NS and SOA.
366 NS has to be set since it is proving an insecure delegation, but SOA should NOT!
367 */
368 addNSECRecordToLW(DNSName("a."), DNSName("b."), {QType::NS, QType::SOA}, 600, records);
369 recordContents.insert(records.at(0).getContent());
370 addRRSIG(keys, records, DNSName("."), 300);
371 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
372 records.clear();
373
374 ContentSigPair pair;
375 pair.records = recordContents;
376 pair.signatures = signatureContents;
377 cspmap_t denialMap;
378 denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair;
379
380 /* Insecure because both NS and SOA are set, so this is not a proper delegation */
381 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
382 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
383 }
384
385 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname)
386 {
387 initSR();
388
389 testkeysset_t keys;
390 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
391
392 vector<DNSRecord> records;
393
394 sortedRecords_t recordContents;
395 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
396
397 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), {QType::CNAME}, 600, records);
398 recordContents.insert(records.at(0).getContent());
399 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
400 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
401 records.clear();
402
403 ContentSigPair pair;
404 pair.records = recordContents;
405 pair.signatures = signatureContents;
406 cspmap_t denialMap;
407 denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
408
409 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
410 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
411 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
412 }
413
414 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_ds)
415 {
416 initSR();
417
418 testkeysset_t keys;
419 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
420
421 vector<DNSRecord> records;
422
423 sortedRecords_t recordContents;
424 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
425 const unsigned int nbIterations = 10;
426 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A}, 600, records, nbIterations);
427 recordContents.insert(records.at(0).getContent());
428 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
429 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
430
431 ContentSigPair pair;
432 pair.records = recordContents;
433 pair.signatures = signatureContents;
434 cspmap_t denialMap;
435 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
436 records.clear();
437
438 pdns::validation::ValidationContext validationContext;
439 validationContext.d_nsec3IterationsRemainingQuota = 100U;
440 /* this NSEC3 is not valid to deny the DS since it is from the child zone */
441 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("powerdns.com."), QType::DS, false, true, validationContext), dState::NODENIAL);
442 /* the NSEC3 hash is not computed since we it is from the child zone */
443 BOOST_CHECK_EQUAL(validationContext.d_nsec3IterationsRemainingQuota, 100U);
444 /* AAAA should be fine, though */
445 BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("powerdns.com."), QType::AAAA, false, true, validationContext), dState::NXQTYPE);
446 BOOST_CHECK_EQUAL(validationContext.d_nsec3IterationsRemainingQuota, (100U - nbIterations));
447 }
448
449 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname)
450 {
451 initSR();
452
453 testkeysset_t keys;
454 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
455
456 vector<DNSRecord> records;
457
458 sortedRecords_t recordContents;
459 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
460
461 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::CNAME}, 600, records);
462 recordContents.insert(records.at(0).getContent());
463 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
464 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
465
466 ContentSigPair pair;
467 pair.records = recordContents;
468 pair.signatures = signatureContents;
469 cspmap_t denialMap;
470 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
471 records.clear();
472
473 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
474 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
475 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
476 }
477
478 BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard)
479 {
480 initSR();
481
482 testkeysset_t keys;
483 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
484
485 vector<DNSRecord> records;
486
487 sortedRecords_t recordContents;
488 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
489
490 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
491 recordContents.insert(records.at(0).getContent());
492 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
493 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
494 records.clear();
495
496 ContentSigPair pair;
497 pair.records = recordContents;
498 pair.signatures = signatureContents;
499 cspmap_t denialMap;
500 denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
501
502 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
503 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
504 }
505
506 BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard)
507 {
508 initSR();
509
510 testkeysset_t keys;
511 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
512
513 vector<DNSRecord> records;
514
515 sortedRecords_t recordContents;
516 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
517
518 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records, 10);
519 recordContents.insert(records.at(0).getContent());
520 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
521 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
522
523 ContentSigPair pair;
524 pair.records = recordContents;
525 pair.signatures = signatureContents;
526 cspmap_t denialMap;
527 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
528
529 /* Add NSEC3 for the closest encloser */
530 recordContents.clear();
531 signatureContents.clear();
532 records.clear();
533 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records, 10);
534 recordContents.insert(records.at(0).getContent());
535 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
536 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
537
538 pair.records = recordContents;
539 pair.signatures = signatureContents;
540 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
541
542 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, false);
543 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
544 }
545
546 BOOST_AUTO_TEST_CASE(test_nsec_expanded_wildcard_proof)
547 {
548 initSR();
549
550 testkeysset_t keys;
551 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
552
553 vector<DNSRecord> records;
554
555 sortedRecords_t recordContents;
556 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
557
558 /* proves that a.example.com does exist, and has been generated from a wildcard (see the RRSIG below) */
559 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
560 recordContents.insert(records.at(0).getContent());
561 addRRSIG(keys, records, DNSName("example.org."), 300, false, boost::none, DNSName("example.org."));
562 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
563 records.clear();
564
565 ContentSigPair pair;
566 pair.records = recordContents;
567 pair.signatures = signatureContents;
568 cspmap_t denialMap;
569 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
570
571 /* This is an expanded wildcard proof, meaning that it does prove that the exact name
572 does not exist so the wildcard can apply */
573 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType(0).getCode(), false, false, std::nullopt, false, /* normally retrieved from the RRSIG's d_labels */ 2);
574 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
575 }
576
577 BOOST_AUTO_TEST_CASE(test_nsec_wildcard_with_cname)
578 {
579 initSR();
580
581 testkeysset_t keys;
582 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
583
584 vector<DNSRecord> records;
585
586 sortedRecords_t recordContents;
587 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
588
589 /* proves that b.example.com does not exist */
590 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
591 recordContents.insert(records.at(0).getContent());
592 addRRSIG(keys, records, DNSName("example.org."), 300);
593 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
594 records.clear();
595
596 ContentSigPair pair;
597 pair.records = recordContents;
598 pair.signatures = signatureContents;
599 cspmap_t denialMap;
600 denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair;
601
602 /* add a NSEC proving that a wildcard exists, without a CNAME type */
603 recordContents.clear();
604 signatureContents.clear();
605 addNSECRecordToLW(DNSName("*.example.org."), DNSName("+.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
606 recordContents.insert(records.at(0).getContent());
607 addRRSIG(keys, records, DNSName("example.org."), 300);
608 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
609 records.clear();
610
611 pair.records = recordContents;
612 pair.signatures = signatureContents;
613 denialMap[std::pair(DNSName("*.example.org."), QType::NSEC)] = pair;
614
615 /* A does exist at the wildcard, AAAA does not */
616 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
617 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
618
619 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
620 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
621
622 /* now we replace the wildcard by one with a CNAME */
623 recordContents.clear();
624 signatureContents.clear();
625 addNSECRecordToLW(DNSName("*.example.org."), DNSName("+.example.org"), {QType::CNAME, QType::RRSIG, QType::NSEC}, 600, records);
626 recordContents.insert(records.at(0).getContent());
627 addRRSIG(keys, records, DNSName("example.org."), 300);
628 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
629 records.clear();
630
631 pair.records = recordContents;
632 pair.signatures = signatureContents;
633 denialMap[std::pair(DNSName("*.example.org."), QType::NSEC)] = pair;
634
635 /* A and AAAA do not exist but we have a CNAME so at the wildcard */
636 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
637 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
638
639 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
640 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
641 }
642
643 BOOST_AUTO_TEST_CASE(test_nsec3_wildcard_with_cname)
644 {
645 initSR();
646
647 testkeysset_t keys;
648 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
649
650 vector<DNSRecord> records;
651
652 sortedRecords_t recordContents;
653 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
654
655 /* proves that b.example.com does not exist */
656 addNSEC3NarrowRecordToLW(DNSName("b.example.org"), DNSName("example.org."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
657 recordContents.insert(records.at(0).getContent());
658 addRRSIG(keys, records, DNSName("example.org."), 300);
659 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
660
661 ContentSigPair pair;
662 pair.records = recordContents;
663 pair.signatures = signatureContents;
664 cspmap_t denialMap;
665 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
666
667 /* Add NSEC3 for the closest encloser */
668 recordContents.clear();
669 signatureContents.clear();
670 records.clear();
671 addNSEC3UnhashedRecordToLW(DNSName("example.org."), DNSName("example.org."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records);
672 recordContents.insert(records.at(0).getContent());
673 addRRSIG(keys, records, DNSName("example.org."), 300);
674 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
675
676 pair.records = recordContents;
677 pair.signatures = signatureContents;
678 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
679
680 /* add wildcard, without a CNAME type */
681 recordContents.clear();
682 signatureContents.clear();
683 records.clear();
684 addNSEC3UnhashedRecordToLW(DNSName("*.example.org."), DNSName("example.org"), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
685 recordContents.insert(records.at(0).getContent());
686 addRRSIG(keys, records, DNSName("example.org."), 300);
687 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
688
689 pair.records = recordContents;
690 pair.signatures = signatureContents;
691 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
692
693 /* A does exist at the wildcard, AAAA does not */
694 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
695 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
696
697 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
698 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
699
700 /* now we replace the wildcard by one with a CNAME */
701 recordContents.clear();
702 signatureContents.clear();
703 records.clear();
704 addNSEC3UnhashedRecordToLW(DNSName("*.example.org."), DNSName("example.org"), "whatever", {QType::CNAME, QType::RRSIG, QType::NSEC3}, 600, records);
705 recordContents.insert(records.at(0).getContent());
706 addRRSIG(keys, records, DNSName("example.org."), 300);
707 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
708
709 pair.records = recordContents;
710 pair.signatures = signatureContents;
711 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
712
713 /* A and AAAA do not exist but we have a CNAME so at the wildcard */
714 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, true);
715 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
716
717 denialState = getDenial(denialMap, DNSName("b.example.org."), QType::AAAA, false, true);
718 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
719 }
720
721 BOOST_AUTO_TEST_CASE(test_nsec_ent_denial)
722 {
723 initSR();
724
725 testkeysset_t keys;
726 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
727
728 vector<DNSRecord> records;
729
730 sortedRecords_t recordContents;
731 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
732
733 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), {QType::A}, 600, records);
734 recordContents.insert(records.at(0).getContent());
735 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
736 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
737 records.clear();
738
739 ContentSigPair pair;
740 pair.records = recordContents;
741 pair.signatures = signatureContents;
742 cspmap_t denialMap;
743 denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
744
745 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
746 it is an ENT */
747 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
748 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
749
750 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
751 it could prove a NXDOMAIN if it had an additional wildcard denial */
752 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
753 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
754
755 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
756 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
757 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
758
759 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
760 recordContents.clear();
761 signatureContents.clear();
762 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), {}, 600, records);
763 recordContents.insert(records.at(0).getContent());
764 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
765 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
766 records.clear();
767 pair.records = recordContents;
768 pair.signatures = signatureContents;
769 denialMap[std::pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
770
771 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
772 BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN);
773
774 /* this NSEC is NOT valid to prove a NXDOMAIN at c.powerdns.com because it proves that
775 it exists and is an ENT */
776 denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, false);
777 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
778 }
779
780 BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial)
781 {
782 initSR();
783
784 testkeysset_t keys;
785 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
786
787 vector<DNSRecord> records;
788
789 sortedRecords_t recordContents;
790 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
791
792 /*
793 The RRSIG from "." denies the existence of any type except NS at a.
794 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
795 signer field that is shorter than the owner name of the NSEC RR) it can't
796 be used to deny anything except the whole name or a DS.
797 */
798 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::NS}, 600, records);
799 recordContents.insert(records.at(0).getContent());
800 addRRSIG(keys, records, DNSName("."), 300);
801 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
802
803 ContentSigPair pair;
804 pair.records = recordContents;
805 pair.signatures = signatureContents;
806 cspmap_t denialMap;
807 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
808 records.clear();
809
810 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
811 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
812 nonexistence of any RRs below that zone cut, which include all RRs at
813 that (original) owner name other than DS RRs, and all RRs below that
814 owner name regardless of type.
815 */
816
817 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
818 /* no denial means the qname/qtype is not denied, because an ancestor
819 delegation NSEC3 can only deny the DS */
820 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
821
822 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
823 BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE);
824
825 /* it can not be used to deny any RRs below that owner name either */
826 /* Add NSEC3 for the next closer */
827 recordContents.clear();
828 signatureContents.clear();
829 records.clear();
830 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
831 recordContents.insert(records.at(0).getContent());
832 addRRSIG(keys, records, DNSName("."), 300);
833 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
834
835 pair.records = recordContents;
836 pair.signatures = signatureContents;
837 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
838
839 /* add wildcard denial */
840 recordContents.clear();
841 signatureContents.clear();
842 records.clear();
843 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records);
844 recordContents.insert(records.at(0).getContent());
845 addRRSIG(keys, records, DNSName("."), 300);
846 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
847
848 pair.records = recordContents;
849 pair.signatures = signatureContents;
850 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
851
852 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
853 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
854
855 /* not even the DS! */
856 denialState = getDenial(denialMap, DNSName("sub.a."), QType::DS, false, true);
857 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
858 }
859
860 BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations)
861 {
862 initSR();
863
864 testkeysset_t keys;
865 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
866
867 vector<DNSRecord> records;
868
869 sortedRecords_t recordContents;
870 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
871
872 /* adding a NSEC3 with more iterations that we support */
873 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::AAAA}, 600, records, g_maxNSEC3Iterations + 100);
874 recordContents.insert(records.at(0).getContent());
875 addRRSIG(keys, records, DNSName("."), 300);
876 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
877
878 ContentSigPair pair;
879 pair.records = recordContents;
880 pair.signatures = signatureContents;
881 cspmap_t denialMap;
882 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
883 records.clear();
884
885 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
886 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
887 BOOST_CHECK_EQUAL(denialState, dState::INSECURE);
888 }
889
890 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial)
891 {
892 initSR();
893
894 testkeysset_t keys;
895 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
896
897 vector<DNSRecord> records;
898
899 sortedRecords_t recordContents;
900 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
901
902 /*
903 * RFC 5155 section 8.9:
904 * If there is an NSEC3 RR present in the response that matches the
905 * delegation name, then the validator MUST ensure that the NS bit is
906 * set and that the DS bit is not set in the Type Bit Maps field of the
907 * NSEC3 RR.
908 */
909 /*
910 The RRSIG from "." denies the existence of any type at a.
911 NS should be set if it was proving an insecure delegation, let's check that
912 we correctly detect that it's not.
913 */
914 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {}, 600, records);
915 recordContents.insert(records.at(0).getContent());
916 addRRSIG(keys, records, DNSName("."), 300);
917 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
918
919 ContentSigPair pair;
920 pair.records = recordContents;
921 pair.signatures = signatureContents;
922 cspmap_t denialMap;
923 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
924 records.clear();
925
926 /* Insecure because the NS is not set, so while it does
927 denies the DS, it can't prove an insecure delegation */
928 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
929 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
930 }
931
932 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial_soa)
933 {
934 initSR();
935
936 testkeysset_t keys;
937 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
938
939 vector<DNSRecord> records;
940
941 sortedRecords_t recordContents;
942 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
943
944 /*
945 * RFC 5155 section 8.9:
946 * If there is an NSEC3 RR present in the response that matches the
947 * delegation name, then the validator MUST ensure that the NS bit is
948 * set and that the DS bit is not set in the Type Bit Maps field of the
949 * NSEC3 RR.
950 */
951 /*
952 The RRSIG from "." denies the existence of any type at a except NS and SOA.
953 NS has to be set since it is proving an insecure delegation, but SOA should NOT!
954 */
955 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::NS, QType::SOA}, 600, records);
956 recordContents.insert(records.at(0).getContent());
957 addRRSIG(keys, records, DNSName("."), 300);
958 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
959
960 ContentSigPair pair;
961 pair.records = recordContents;
962 pair.signatures = signatureContents;
963 cspmap_t denialMap;
964 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
965 records.clear();
966
967 /* Insecure because both NS and SOA are set, so it is not a proper delegation */
968 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
969 BOOST_CHECK_EQUAL(denialState, dState::NODENIAL);
970 }
971
972 BOOST_AUTO_TEST_CASE(test_nsec3_ent_opt_out)
973 {
974 initSR();
975
976 testkeysset_t keys;
977 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
978
979 vector<DNSRecord> records;
980
981 sortedRecords_t recordContents;
982 vector<shared_ptr<const RRSIGRecordContent>> signatureContents;
983
984 /*
985 * RFC 7129 section 5.1:
986 * A recently discovered corner case (see RFC Errata ID 3441 [Err3441])
987 * shows that not only those delegations remain insecure but also the
988 * empty non-terminal space that is derived from those delegations.
989 */
990 /*
991 We have a NSEC3 proving that was.here does exist, and a second
992 one proving that ent.was.here. does not,
993 There NSEC3 are opt-out, so the result should be insecure (and we don't need
994 a wildcard proof).
995 */
996 addNSEC3UnhashedRecordToLW(DNSName("was.here."), DNSName("."), "whatever", {}, 600, records, 10, true /* opt out */);
997 recordContents.insert(records.at(0).getContent());
998 addRRSIG(keys, records, DNSName("."), 300);
999 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
1000
1001 ContentSigPair pair;
1002 pair.records = recordContents;
1003 pair.signatures = signatureContents;
1004 cspmap_t denialMap;
1005 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
1006
1007 /* it can not be used to deny any RRs below that owner name either */
1008 /* Add NSEC3 for the next closer */
1009 recordContents.clear();
1010 signatureContents.clear();
1011 records.clear();
1012 addNSEC3NarrowRecordToLW(DNSName("ent.was.here."), DNSName("."), {QType::RRSIG, QType::NSEC3}, 600, records, 10, true /* opt-out */);
1013 recordContents.insert(records.at(0).getContent());
1014 addRRSIG(keys, records, DNSName("."), 300);
1015 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
1016
1017 pair.records = recordContents;
1018 pair.signatures = signatureContents;
1019 denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair;
1020
1021 /* Insecure because the opt-out bit is set */
1022 dState denialState = getDenial(denialMap, DNSName("ent.was.here."), QType::A, false, true);
1023 BOOST_CHECK_EQUAL(denialState, dState::OPTOUT);
1024 }
1025
1026 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity)
1027 {
1028 std::unique_ptr<SyncRes> sr;
1029 initSR(sr, true);
1030
1031 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1032
1033 primeHints();
1034 const DNSName target("com.");
1035 testkeysset_t keys;
1036
1037 auto luaconfsCopy = g_luaconfs.getCopy();
1038 luaconfsCopy.dsAnchors.clear();
1039 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1040 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1041 g_luaconfs.setState(luaconfsCopy);
1042
1043 size_t queriesCount = 0;
1044 const time_t fixedNow = sr->getNow().tv_sec;
1045
1046 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 */) {
1047 queriesCount++;
1048
1049 DNSName auth = domain;
1050 auth.chopOff();
1051
1052 if (type == QType::DS || type == QType::DNSKEY) {
1053 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
1054 }
1055 {
1056 setLWResult(res, RCode::NoError, true, false, true);
1057 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1058 addRRSIG(keys, res->d_records, domain, 300);
1059 addNSECRecordToLW(domain, DNSName("z."), {QType::NSEC, QType::RRSIG}, 600, res->d_records);
1060 addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, fixedNow);
1061 return LWResult::Result::Success;
1062 }
1063
1064 return LWResult::Result::Timeout;
1065 });
1066
1067 vector<DNSRecord> ret;
1068 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1069 BOOST_CHECK_EQUAL(res, RCode::NoError);
1070 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1071 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1072 BOOST_CHECK_EQUAL(queriesCount, 4U);
1073
1074 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
1075 NegCache::NegCacheEntry ne;
1076 BOOST_CHECK_EQUAL(g_negCache->size(), 1U);
1077 BOOST_REQUIRE_EQUAL(g_negCache->get(target, QType(QType::A), sr->getNow(), ne), true);
1078 BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + 1);
1079 BOOST_CHECK_EQUAL(ne.d_validationState, vState::Secure);
1080 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
1081 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
1082 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1U);
1083 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1U);
1084
1085 /* again, to test the cache */
1086 ret.clear();
1087 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1088 BOOST_CHECK_EQUAL(res, RCode::NoError);
1089 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1090 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1091 BOOST_CHECK_EQUAL(queriesCount, 4U);
1092 }
1093
1094 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_bogus_validity)
1095 {
1096 std::unique_ptr<SyncRes> sr;
1097 initSR(sr, true);
1098
1099 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1100
1101 primeHints();
1102 const DNSName target("com.");
1103 testkeysset_t keys;
1104
1105 auto luaconfsCopy = g_luaconfs.getCopy();
1106 luaconfsCopy.dsAnchors.clear();
1107 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1108 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1109 g_luaconfs.setState(luaconfsCopy);
1110
1111 size_t queriesCount = 0;
1112 const time_t fixedNow = sr->getNow().tv_sec;
1113
1114 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 */) {
1115 queriesCount++;
1116
1117 DNSName auth = domain;
1118 auth.chopOff();
1119
1120 if (type == QType::DS || type == QType::DNSKEY) {
1121 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
1122 }
1123 {
1124 setLWResult(res, RCode::NoError, true, false, true);
1125 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 86400);
1126 addRRSIG(keys, res->d_records, domain, 86400);
1127 addNSECRecordToLW(domain, DNSName("z."), {QType::NSEC, QType::RRSIG}, 86400, res->d_records);
1128 /* no RRSIG */
1129 return LWResult::Result::Success;
1130 }
1131
1132 return LWResult::Result::Timeout;
1133 });
1134
1135 SyncRes::s_maxnegttl = 3600;
1136 SyncRes::s_maxbogusttl = 360;
1137
1138 vector<DNSRecord> ret;
1139 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1140 BOOST_CHECK_EQUAL(res, RCode::NoError);
1141 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
1142 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1143 BOOST_CHECK_EQUAL(queriesCount, 4U);
1144
1145 /* check that the entry has been negatively cached but not longer than s_maxbogusttl */
1146 NegCache::NegCacheEntry ne;
1147 BOOST_CHECK_EQUAL(g_negCache->size(), 1U);
1148 BOOST_REQUIRE_EQUAL(g_negCache->get(target, QType(QType::A), sr->getNow(), ne), true);
1149 BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + SyncRes::s_maxbogusttl);
1150 BOOST_CHECK_EQUAL(ne.d_validationState, vState::BogusNoRRSIG);
1151 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
1152 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
1153 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1U);
1154 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0U);
1155
1156 /* again, to test the cache */
1157 ret.clear();
1158 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1159 BOOST_CHECK_EQUAL(res, RCode::NoError);
1160 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
1161 BOOST_REQUIRE_EQUAL(ret.size(), 3U);
1162 BOOST_CHECK_EQUAL(queriesCount, 4U);
1163 }
1164
1165 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity)
1166 {
1167 std::unique_ptr<SyncRes> sr;
1168 initSR(sr, true);
1169
1170 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
1171
1172 primeHints();
1173 const DNSName target("com.");
1174 const ComboAddress targetAddr("192.0.2.42");
1175 testkeysset_t keys;
1176
1177 auto luaconfsCopy = g_luaconfs.getCopy();
1178 luaconfsCopy.dsAnchors.clear();
1179 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1180 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
1181 g_luaconfs.setState(luaconfsCopy);
1182
1183 size_t queriesCount = 0;
1184 const time_t tnow = sr->getNow().tv_sec;
1185
1186 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 */) {
1187 queriesCount++;
1188
1189 DNSName auth = domain;
1190 auth.chopOff();
1191
1192 if (type == QType::DS || type == QType::DNSKEY) {
1193 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
1194 }
1195 {
1196 setLWResult(res, RCode::NoError, true, false, true);
1197 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
1198 addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, tnow);
1199 return LWResult::Result::Success;
1200 }
1201
1202 return LWResult::Result::Timeout;
1203 });
1204
1205 vector<DNSRecord> ret;
1206 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1207 BOOST_CHECK_EQUAL(res, RCode::NoError);
1208 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1209 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1210 BOOST_CHECK_EQUAL(queriesCount, 4U);
1211
1212 /* check that the entry has not been cached for longer than the RRSIG validity */
1213 const ComboAddress who;
1214 vector<DNSRecord> cached;
1215 vector<std::shared_ptr<const RRSIGRecordContent>> signatures;
1216 BOOST_REQUIRE_EQUAL(g_recCache->get(tnow, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who, boost::none, &signatures), 1);
1217 BOOST_REQUIRE_EQUAL(cached.size(), 1U);
1218 BOOST_REQUIRE_EQUAL(signatures.size(), 1U);
1219 BOOST_CHECK_EQUAL((cached[0].d_ttl - tnow), 1);
1220
1221 /* again, to test the cache */
1222 ret.clear();
1223 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1224 BOOST_CHECK_EQUAL(res, RCode::NoError);
1225 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1226 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1227 BOOST_CHECK_EQUAL(queriesCount, 4U);
1228 }
1229
1230 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure)
1231 {
1232 /*
1233 Validation is optional, and the first query does not ask for it,
1234 so the answer is cached as Indeterminate.
1235 The second query asks for validation, answer should be marked as
1236 Secure, after just-in-time validation.
1237 */
1238 std::unique_ptr<SyncRes> sr;
1239 initSR(sr, true);
1240
1241 setDNSSECValidation(sr, DNSSECMode::Process);
1242
1243 primeHints();
1244 const DNSName target("com.");
1245 testkeysset_t keys;
1246
1247 auto luaconfsCopy = g_luaconfs.getCopy();
1248 luaconfsCopy.dsAnchors.clear();
1249 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1250 g_luaconfs.setState(luaconfsCopy);
1251
1252 size_t queriesCount = 0;
1253
1254 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 */) {
1255 queriesCount++;
1256
1257 if (type == QType::DS || type == QType::DNSKEY) {
1258 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1259 }
1260 {
1261 if (domain == target && type == QType::A) {
1262 setLWResult(res, 0, true, false, true);
1263 addRecordToLW(res, target, QType::A, "192.0.2.1");
1264 addRRSIG(keys, res->d_records, DNSName("."), 300);
1265 return LWResult::Result::Success;
1266 }
1267 }
1268
1269 return LWResult::Result::Timeout;
1270 });
1271
1272 vector<DNSRecord> ret;
1273 /* first query does not require validation */
1274 sr->setDNSSECValidationRequested(false);
1275 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1276 BOOST_CHECK_EQUAL(res, RCode::NoError);
1277 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
1278 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1279 for (const auto& record : ret) {
1280 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
1281 }
1282 BOOST_CHECK_EQUAL(queriesCount, 1U);
1283
1284 ret.clear();
1285 /* second one _does_ require validation */
1286 sr->setDNSSECValidationRequested(true);
1287 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1288 BOOST_CHECK_EQUAL(res, RCode::NoError);
1289 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1290 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1291 for (const auto& record : ret) {
1292 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
1293 }
1294 BOOST_CHECK_EQUAL(queriesCount, 2U);
1295 }
1296
1297 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure)
1298 {
1299 /*
1300 Validation is optional, and the first query does not ask for it,
1301 so the answer is cached as Indeterminate.
1302 The second query asks for validation, answer should be marked as
1303 Insecure.
1304 */
1305 std::unique_ptr<SyncRes> sr;
1306 initSR(sr, true);
1307
1308 setDNSSECValidation(sr, DNSSECMode::Process);
1309
1310 primeHints();
1311 const DNSName target("com.");
1312 testkeysset_t keys;
1313
1314 auto luaconfsCopy = g_luaconfs.getCopy();
1315 luaconfsCopy.dsAnchors.clear();
1316 g_luaconfs.setState(luaconfsCopy);
1317
1318 size_t queriesCount = 0;
1319
1320 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 */) {
1321 queriesCount++;
1322
1323 if (type == QType::DS || type == QType::DNSKEY) {
1324 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1325 }
1326 {
1327 if (domain == target && type == QType::A) {
1328 setLWResult(res, 0, true, false, true);
1329 addRecordToLW(res, target, QType::A, "192.0.2.1");
1330 return LWResult::Result::Success;
1331 }
1332 }
1333
1334 return LWResult::Result::Timeout;
1335 });
1336
1337 vector<DNSRecord> ret;
1338 /* first query does not require validation */
1339 sr->setDNSSECValidationRequested(false);
1340 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1341 BOOST_CHECK_EQUAL(res, RCode::NoError);
1342 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
1343 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1344 for (const auto& record : ret) {
1345 BOOST_CHECK(record.d_type == QType::A);
1346 }
1347 BOOST_CHECK_EQUAL(queriesCount, 1U);
1348
1349 ret.clear();
1350 /* second one _does_ require validation */
1351 sr->setDNSSECValidationRequested(true);
1352 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1353 BOOST_CHECK_EQUAL(res, RCode::NoError);
1354 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
1355 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1356 for (const auto& record : ret) {
1357 BOOST_CHECK(record.d_type == QType::A);
1358 }
1359 BOOST_CHECK_EQUAL(queriesCount, 1U);
1360 }
1361
1362 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus)
1363 {
1364 /*
1365 Validation is optional, and the first query does not ask for it,
1366 so the answer is cached as Indeterminate.
1367 The second query asks for validation, answer should be marked as
1368 Bogus.
1369 */
1370 std::unique_ptr<SyncRes> sr;
1371 initSR(sr, true);
1372
1373 setDNSSECValidation(sr, DNSSECMode::Process);
1374
1375 primeHints();
1376 const DNSName target("com.");
1377 testkeysset_t keys;
1378
1379 auto luaconfsCopy = g_luaconfs.getCopy();
1380 luaconfsCopy.dsAnchors.clear();
1381 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1382 g_luaconfs.setState(luaconfsCopy);
1383
1384 size_t queriesCount = 0;
1385
1386 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 */) {
1387 queriesCount++;
1388
1389 if (type == QType::DS || type == QType::DNSKEY) {
1390 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1391 }
1392 {
1393 if (domain == target && type == QType::A) {
1394 setLWResult(res, 0, true, false, true);
1395 addRecordToLW(res, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, 86400);
1396 /* no RRSIG */
1397 return LWResult::Result::Success;
1398 }
1399 }
1400
1401 return LWResult::Result::Timeout;
1402 });
1403
1404 SyncRes::s_maxbogusttl = 3600;
1405
1406 vector<DNSRecord> ret;
1407 /* first query does not require validation */
1408 sr->setDNSSECValidationRequested(false);
1409 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1410 BOOST_CHECK_EQUAL(res, RCode::NoError);
1411 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
1412 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1413 for (const auto& record : ret) {
1414 BOOST_CHECK(record.d_type == QType::A);
1415 BOOST_CHECK_EQUAL(record.d_ttl, 86400U);
1416 }
1417 BOOST_CHECK_EQUAL(queriesCount, 1U);
1418
1419 ret.clear();
1420 /* second one _does_ require validation */
1421 sr->setDNSSECValidationRequested(true);
1422 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1423 BOOST_CHECK_EQUAL(res, RCode::NoError);
1424 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
1425 /* check that we correctly capped the TTD for a Bogus record after
1426 just-in-time validation */
1427 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1428 for (const auto& record : ret) {
1429 BOOST_CHECK(record.d_type == QType::A);
1430 BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
1431 }
1432 BOOST_CHECK_EQUAL(queriesCount, 3U);
1433
1434 ret.clear();
1435 /* third time also _does_ require validation, so we
1436 can check that the cache has been updated */
1437 sr->setDNSSECValidationRequested(true);
1438 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1439 BOOST_CHECK_EQUAL(res, RCode::NoError);
1440 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
1441 BOOST_REQUIRE_EQUAL(ret.size(), 1U);
1442 for (const auto& record : ret) {
1443 BOOST_CHECK(record.d_type == QType::A);
1444 BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
1445 }
1446 BOOST_CHECK_EQUAL(queriesCount, 3U);
1447 }
1448
1449 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure_any)
1450 {
1451 /*
1452 Validation is optional, and the first two queries (A, AAAA) do not ask for it,
1453 so the answer are cached as Indeterminate.
1454 The third query asks for validation, and is for ANY, so the answer should be marked as
1455 Secure, after just-in-time validation.
1456 The last query also requests validation but is for AAAA only.
1457 */
1458 std::unique_ptr<SyncRes> sr;
1459 initSR(sr, true);
1460
1461 setDNSSECValidation(sr, DNSSECMode::Process);
1462
1463 primeHints();
1464 const DNSName target("com.");
1465 testkeysset_t keys;
1466
1467 auto luaconfsCopy = g_luaconfs.getCopy();
1468 luaconfsCopy.dsAnchors.clear();
1469 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
1470 g_luaconfs.setState(luaconfsCopy);
1471
1472 size_t queriesCount = 0;
1473
1474 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 */) {
1475 queriesCount++;
1476
1477 if (type == QType::DS || type == QType::DNSKEY) {
1478 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
1479 }
1480 {
1481 if (domain == target && type == QType::A) {
1482 setLWResult(res, 0, true, false, true);
1483 addRecordToLW(res, target, QType::A, "192.0.2.1");
1484 addRRSIG(keys, res->d_records, DNSName("."), 300);
1485 return LWResult::Result::Success;
1486 }
1487 if (domain == target && type == QType::AAAA) {
1488 setLWResult(res, 0, true, false, true);
1489 addRecordToLW(res, target, QType::AAAA, "2001:db8::1");
1490 addRRSIG(keys, res->d_records, DNSName("."), 300);
1491 return LWResult::Result::Success;
1492 }
1493 }
1494
1495 return LWResult::Result::Timeout;
1496 });
1497
1498 vector<DNSRecord> ret;
1499 /* first query does not require validation */
1500 sr->setDNSSECValidationRequested(false);
1501 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1502 BOOST_CHECK_EQUAL(res, RCode::NoError);
1503 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
1504 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1505 for (const auto& record : ret) {
1506 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
1507 }
1508 BOOST_CHECK_EQUAL(queriesCount, 1U);
1509
1510 ret.clear();
1511 /* second query does not require validation either */
1512 sr->setDNSSECValidationRequested(false);
1513 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
1514 BOOST_CHECK_EQUAL(res, RCode::NoError);
1515 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
1516 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1517 for (const auto& record : ret) {
1518 BOOST_CHECK(record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
1519 }
1520 BOOST_CHECK_EQUAL(queriesCount, 2U);
1521
1522 ret.clear();
1523 /* third one _does_ require validation */
1524 sr->setDNSSECValidationRequested(true);
1525 res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
1526 BOOST_CHECK_EQUAL(res, RCode::NoError);
1527 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1528 BOOST_REQUIRE_EQUAL(ret.size(), 4U);
1529 for (const auto& record : ret) {
1530 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
1531 }
1532 BOOST_CHECK_EQUAL(queriesCount, 3U);
1533
1534 ret.clear();
1535 /* last one also requires validation */
1536 sr->setDNSSECValidationRequested(true);
1537 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
1538 BOOST_CHECK_EQUAL(res, RCode::NoError);
1539 BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
1540 BOOST_REQUIRE_EQUAL(ret.size(), 2U);
1541 for (const auto& record : ret) {
1542 BOOST_CHECK(record.d_type == QType::AAAA || record.d_type == QType::RRSIG);
1543 }
1544 BOOST_CHECK_EQUAL(queriesCount, 3U);
1545 }
1546
1547 BOOST_AUTO_TEST_SUITE_END()