1 #ifndef BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_DYN_LINK
5 #include <boost/test/unit_test.hpp>
7 #include "test-syncres_cc.hh"
9 BOOST_AUTO_TEST_SUITE(syncres_cc8
)
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)
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
);
18 BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap
)
23 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
25 vector
<DNSRecord
> records
;
27 sortedRecords_t recordContents
;
28 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
32 a.example.org. -> d.example.org. denies the existence of b.example.org.
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)));
41 pair
.records
= recordContents
;
42 pair
.signatures
= signatureContents
;
44 denialMap
[std::pair(DNSName("a.example.org."), QType::NSEC
)] = pair
;
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)));
55 pair
.records
= recordContents
;
56 pair
.signatures
= signatureContents
;
57 denialMap
[std::pair(DNSName("example.org."), QType::NSEC
)] = pair
;
59 dState denialState
= getDenial(denialMap
, DNSName("b.example.org."), QType::A
, false, false);
60 BOOST_CHECK_EQUAL(denialState
, dState::NXDOMAIN
);
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
);
67 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1
)
72 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
74 vector
<DNSRecord
> records
;
76 sortedRecords_t recordContents
;
77 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
80 Wrap case 1 test case:
81 z.example.org. -> b.example.org. denies the existence of a.example.org.
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)));
90 pair
.records
= recordContents
;
91 pair
.signatures
= signatureContents
;
93 denialMap
[std::pair(DNSName("z.example.org."), QType::NSEC
)] = pair
;
95 dState denialState
= getDenial(denialMap
, DNSName("a.example.org."), QType::A
, false, false);
96 BOOST_CHECK_EQUAL(denialState
, dState::NXDOMAIN
);
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
);
103 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2
)
108 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
110 vector
<DNSRecord
> records
;
112 sortedRecords_t recordContents
;
113 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
116 Wrap case 2 test case:
117 y.example.org. -> a.example.org. denies the existence of z.example.org.
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)));
126 pair
.records
= recordContents
;
127 pair
.signatures
= signatureContents
;
129 denialMap
[std::pair(DNSName("y.example.org."), QType::NSEC
)] = pair
;
131 dState denialState
= getDenial(denialMap
, DNSName("z.example.org."), QType::A
, false, false);
132 BOOST_CHECK_EQUAL(denialState
, dState::NXDOMAIN
);
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
);
139 BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec
)
144 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
146 vector
<DNSRecord
> records
;
148 sortedRecords_t recordContents
;
149 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
152 Only one NSEC in the whole zone test case:
153 a.example.org. -> a.example.org. denies the existence of b.example.org.
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)));
162 pair
.records
= recordContents
;
163 pair
.signatures
= signatureContents
;
165 denialMap
[std::pair(DNSName("a.example.org."), QType::NSEC
)] = pair
;
167 dState denialState
= getDenial(denialMap
, DNSName("b.example.org."), QType::A
, false, false);
168 BOOST_CHECK_EQUAL(denialState
, dState::NXDOMAIN
);
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
);
175 BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial
)
180 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
182 vector
<DNSRecord
> records
;
184 sortedRecords_t recordContents
;
185 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
188 The RRSIG from "." denies the existence of anything between a. and c.,
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)));
198 pair
.records
= recordContents
;
199 pair
.signatures
= signatureContents
;
201 denialMap
[std::pair(DNSName("a."), QType::NSEC
)] = pair
;
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)));
212 pair
.records
= recordContents
;
213 pair
.signatures
= signatureContents
;
214 denialMap
[std::pair(DNSName("."), QType::NSEC
)] = pair
;
216 dState denialState
= getDenial(denialMap
, DNSName("b."), QType::A
, false, false);
217 BOOST_CHECK_EQUAL(denialState
, dState::NXDOMAIN
);
220 BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial
)
225 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
227 vector
<DNSRecord
> records
;
229 sortedRecords_t recordContents
;
230 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)
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)));
246 pair
.records
= recordContents
;
247 pair
.signatures
= signatureContents
;
249 denialMap
[std::pair(DNSName("a."), QType::NSEC
)] = pair
;
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.
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
);
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
);
267 denialState
= getDenial(denialMap
, DNSName("a."), QType::DS
, true, true);
268 BOOST_CHECK_EQUAL(denialState
, dState::NXQTYPE
);
271 BOOST_AUTO_TEST_CASE(test_nsec_ds_denial_from_child
)
276 generateKeyMaterial(DNSName("org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
277 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
279 vector
<DNSRecord
> records
;
281 sortedRecords_t recordContents
;
282 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
291 pair
.records
= recordContents
;
292 pair
.signatures
= signatureContents
;
294 denialMap
[std::pair(DNSName("example.org."), QType::NSEC
)] = pair
;
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
);
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
);
303 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial
)
308 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
310 vector
<DNSRecord
> records
;
312 sortedRecords_t recordContents
;
313 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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
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.
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)));
334 pair
.records
= recordContents
;
335 pair
.signatures
= signatureContents
;
337 denialMap
[std::pair(DNSName("a."), QType::NSEC
)] = pair
;
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
);
345 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial_soa
)
350 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
352 vector
<DNSRecord
> records
;
354 sortedRecords_t recordContents
;
355 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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
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!
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)));
375 pair
.records
= recordContents
;
376 pair
.signatures
= signatureContents
;
378 denialMap
[std::pair(DNSName("a."), QType::NSEC
)] = pair
;
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
);
385 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname
)
390 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
392 vector
<DNSRecord
> records
;
394 sortedRecords_t recordContents
;
395 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
404 pair
.records
= recordContents
;
405 pair
.signatures
= signatureContents
;
407 denialMap
[std::pair(DNSName("a.powerdns.com."), QType::NSEC
)] = pair
;
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
);
414 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_ds
)
419 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
421 vector
<DNSRecord
> records
;
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)));
432 pair
.records
= recordContents
;
433 pair
.signatures
= signatureContents
;
435 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
));
449 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname
)
454 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
456 vector
<DNSRecord
> records
;
458 sortedRecords_t recordContents
;
459 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
467 pair
.records
= recordContents
;
468 pair
.signatures
= signatureContents
;
470 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
);
478 BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard
)
483 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
485 vector
<DNSRecord
> records
;
487 sortedRecords_t recordContents
;
488 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
497 pair
.records
= recordContents
;
498 pair
.signatures
= signatureContents
;
500 denialMap
[std::pair(DNSName("a.powerdns.com."), QType::NSEC
)] = pair
;
502 dState denialState
= getDenial(denialMap
, DNSName("b.powerdns.com."), QType::A
, false, false);
503 BOOST_CHECK_EQUAL(denialState
, dState::NODENIAL
);
506 BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard
)
511 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
513 vector
<DNSRecord
> records
;
515 sortedRecords_t recordContents
;
516 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
524 pair
.records
= recordContents
;
525 pair
.signatures
= signatureContents
;
527 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
529 /* Add NSEC3 for the closest encloser */
530 recordContents
.clear();
531 signatureContents
.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)));
538 pair
.records
= recordContents
;
539 pair
.signatures
= signatureContents
;
540 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
542 dState denialState
= getDenial(denialMap
, DNSName("a.powerdns.com."), QType::A
, false, false);
543 BOOST_CHECK_EQUAL(denialState
, dState::NODENIAL
);
546 BOOST_AUTO_TEST_CASE(test_nsec_expanded_wildcard_proof
)
551 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
553 vector
<DNSRecord
> records
;
555 sortedRecords_t recordContents
;
556 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
566 pair
.records
= recordContents
;
567 pair
.signatures
= signatureContents
;
569 denialMap
[std::pair(DNSName("a.example.org."), QType::NSEC
)] = pair
;
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
);
577 BOOST_AUTO_TEST_CASE(test_nsec_wildcard_with_cname
)
582 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
584 vector
<DNSRecord
> records
;
586 sortedRecords_t recordContents
;
587 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
597 pair
.records
= recordContents
;
598 pair
.signatures
= signatureContents
;
600 denialMap
[std::pair(DNSName("a.example.org."), QType::NSEC
)] = pair
;
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)));
611 pair
.records
= recordContents
;
612 pair
.signatures
= signatureContents
;
613 denialMap
[std::pair(DNSName("*.example.org."), QType::NSEC
)] = pair
;
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
);
619 denialState
= getDenial(denialMap
, DNSName("b.example.org."), QType::AAAA
, false, true);
620 BOOST_CHECK_EQUAL(denialState
, dState::NXQTYPE
);
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)));
631 pair
.records
= recordContents
;
632 pair
.signatures
= signatureContents
;
633 denialMap
[std::pair(DNSName("*.example.org."), QType::NSEC
)] = pair
;
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
);
639 denialState
= getDenial(denialMap
, DNSName("b.example.org."), QType::AAAA
, false, true);
640 BOOST_CHECK_EQUAL(denialState
, dState::NODENIAL
);
643 BOOST_AUTO_TEST_CASE(test_nsec3_wildcard_with_cname
)
648 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
650 vector
<DNSRecord
> records
;
652 sortedRecords_t recordContents
;
653 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
662 pair
.records
= recordContents
;
663 pair
.signatures
= signatureContents
;
665 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
667 /* Add NSEC3 for the closest encloser */
668 recordContents
.clear();
669 signatureContents
.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)));
676 pair
.records
= recordContents
;
677 pair
.signatures
= signatureContents
;
678 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
680 /* add wildcard, without a CNAME type */
681 recordContents
.clear();
682 signatureContents
.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)));
689 pair
.records
= recordContents
;
690 pair
.signatures
= signatureContents
;
691 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
);
697 denialState
= getDenial(denialMap
, DNSName("b.example.org."), QType::AAAA
, false, true);
698 BOOST_CHECK_EQUAL(denialState
, dState::NXQTYPE
);
700 /* now we replace the wildcard by one with a CNAME */
701 recordContents
.clear();
702 signatureContents
.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)));
709 pair
.records
= recordContents
;
710 pair
.signatures
= signatureContents
;
711 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
);
717 denialState
= getDenial(denialMap
, DNSName("b.example.org."), QType::AAAA
, false, true);
718 BOOST_CHECK_EQUAL(denialState
, dState::NODENIAL
);
721 BOOST_AUTO_TEST_CASE(test_nsec_ent_denial
)
726 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
728 vector
<DNSRecord
> records
;
730 sortedRecords_t recordContents
;
731 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
740 pair
.records
= recordContents
;
741 pair
.signatures
= signatureContents
;
743 denialMap
[std::pair(DNSName("a.powerdns.com."), QType::NSEC
)] = pair
;
745 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
747 dState denialState
= getDenial(denialMap
, DNSName("c.powerdns.com."), QType::AAAA
, true, true);
748 BOOST_CHECK_EQUAL(denialState
, dState::NXQTYPE
);
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
);
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
);
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)));
767 pair
.records
= recordContents
;
768 pair
.signatures
= signatureContents
;
769 denialMap
[std::pair(DNSName(").powerdns.com."), QType::NSEC
)] = pair
;
771 denialState
= getDenial(denialMap
, DNSName("b.powerdns.com."), QType::A
, true, false);
772 BOOST_CHECK_EQUAL(denialState
, dState::NXDOMAIN
);
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
);
780 BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial
)
785 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
787 vector
<DNSRecord
> records
;
789 sortedRecords_t recordContents
;
790 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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.
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)));
804 pair
.records
= recordContents
;
805 pair
.signatures
= signatureContents
;
807 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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.
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
);
822 denialState
= getDenial(denialMap
, DNSName("a."), QType::DS
, true, true);
823 BOOST_CHECK_EQUAL(denialState
, dState::NXQTYPE
);
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();
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)));
835 pair
.records
= recordContents
;
836 pair
.signatures
= signatureContents
;
837 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
839 /* add wildcard denial */
840 recordContents
.clear();
841 signatureContents
.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)));
848 pair
.records
= recordContents
;
849 pair
.signatures
= signatureContents
;
850 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
852 denialState
= getDenial(denialMap
, DNSName("sub.a."), QType::A
, false, true);
853 BOOST_CHECK_EQUAL(denialState
, dState::NODENIAL
);
855 /* not even the DS! */
856 denialState
= getDenial(denialMap
, DNSName("sub.a."), QType::DS
, false, true);
857 BOOST_CHECK_EQUAL(denialState
, dState::NODENIAL
);
860 BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations
)
865 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
867 vector
<DNSRecord
> records
;
869 sortedRecords_t recordContents
;
870 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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)));
879 pair
.records
= recordContents
;
880 pair
.signatures
= signatureContents
;
882 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
);
890 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial
)
895 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
897 vector
<DNSRecord
> records
;
899 sortedRecords_t recordContents
;
900 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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
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.
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)));
920 pair
.records
= recordContents
;
921 pair
.signatures
= signatureContents
;
923 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
);
932 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial_soa
)
937 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
939 vector
<DNSRecord
> records
;
941 sortedRecords_t recordContents
;
942 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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
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!
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)));
961 pair
.records
= recordContents
;
962 pair
.signatures
= signatureContents
;
964 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
);
972 BOOST_AUTO_TEST_CASE(test_nsec3_ent_opt_out
)
977 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256
, DNSSECKeeper::DIGEST_SHA256
, keys
);
979 vector
<DNSRecord
> records
;
981 sortedRecords_t recordContents
;
982 vector
<shared_ptr
<const RRSIGRecordContent
>> signatureContents
;
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.
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
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)));
1001 ContentSigPair pair
;
1002 pair
.records
= recordContents
;
1003 pair
.signatures
= signatureContents
;
1005 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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();
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)));
1017 pair
.records
= recordContents
;
1018 pair
.signatures
= signatureContents
;
1019 denialMap
[std::pair(records
.at(0).d_name
, records
.at(0).d_type
)] = pair
;
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
);
1026 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity
)
1028 std::unique_ptr
<SyncRes
> sr
;
1031 setDNSSECValidation(sr
, DNSSECMode::ValidateAll
);
1034 const DNSName
target("com.");
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
);
1043 size_t queriesCount
= 0;
1044 const time_t fixedNow
= sr
->getNow().tv_sec
;
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 */) {
1049 DNSName auth
= domain
;
1052 if (type
== QType::DS
|| type
== QType::DNSKEY
) {
1053 return genericDSAndDNSKEYHandler(res
, domain
, auth
, type
, keys
);
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
;
1064 return LWResult::Result::Timeout
;
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);
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);
1085 /* again, to test the cache */
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);
1094 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_bogus_validity
)
1096 std::unique_ptr
<SyncRes
> sr
;
1099 setDNSSECValidation(sr
, DNSSECMode::ValidateAll
);
1102 const DNSName
target("com.");
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
);
1111 size_t queriesCount
= 0;
1112 const time_t fixedNow
= sr
->getNow().tv_sec
;
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 */) {
1117 DNSName auth
= domain
;
1120 if (type
== QType::DS
|| type
== QType::DNSKEY
) {
1121 return genericDSAndDNSKEYHandler(res
, domain
, auth
, type
, keys
);
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
);
1129 return LWResult::Result::Success
;
1132 return LWResult::Result::Timeout
;
1135 SyncRes::s_maxnegttl
= 3600;
1136 SyncRes::s_maxbogusttl
= 360;
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);
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);
1156 /* again, to test the cache */
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);
1165 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity
)
1167 std::unique_ptr
<SyncRes
> sr
;
1170 setDNSSECValidation(sr
, DNSSECMode::ValidateAll
);
1173 const DNSName
target("com.");
1174 const ComboAddress
targetAddr("192.0.2.42");
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
);
1183 size_t queriesCount
= 0;
1184 const time_t tnow
= sr
->getNow().tv_sec
;
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 */) {
1189 DNSName auth
= domain
;
1192 if (type
== QType::DS
|| type
== QType::DNSKEY
) {
1193 return genericDSAndDNSKEYHandler(res
, domain
, auth
, type
, keys
);
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
;
1202 return LWResult::Result::Timeout
;
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);
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);
1221 /* again, to test the cache */
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);
1230 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure
)
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.
1238 std::unique_ptr
<SyncRes
> sr
;
1241 setDNSSECValidation(sr
, DNSSECMode::Process
);
1244 const DNSName
target("com.");
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
);
1252 size_t queriesCount
= 0;
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 */) {
1257 if (type
== QType::DS
|| type
== QType::DNSKEY
) {
1258 return genericDSAndDNSKEYHandler(res
, domain
, domain
, type
, keys
, false);
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
;
1269 return LWResult::Result::Timeout
;
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
);
1282 BOOST_CHECK_EQUAL(queriesCount
, 1U);
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
);
1294 BOOST_CHECK_EQUAL(queriesCount
, 2U);
1297 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure
)
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
1305 std::unique_ptr
<SyncRes
> sr
;
1308 setDNSSECValidation(sr
, DNSSECMode::Process
);
1311 const DNSName
target("com.");
1314 auto luaconfsCopy
= g_luaconfs
.getCopy();
1315 luaconfsCopy
.dsAnchors
.clear();
1316 g_luaconfs
.setState(luaconfsCopy
);
1318 size_t queriesCount
= 0;
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 */) {
1323 if (type
== QType::DS
|| type
== QType::DNSKEY
) {
1324 return genericDSAndDNSKEYHandler(res
, domain
, domain
, type
, keys
, false);
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
;
1334 return LWResult::Result::Timeout
;
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
);
1347 BOOST_CHECK_EQUAL(queriesCount
, 1U);
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
);
1359 BOOST_CHECK_EQUAL(queriesCount
, 1U);
1362 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus
)
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
1370 std::unique_ptr
<SyncRes
> sr
;
1373 setDNSSECValidation(sr
, DNSSECMode::Process
);
1376 const DNSName
target("com.");
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
);
1384 size_t queriesCount
= 0;
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 */) {
1389 if (type
== QType::DS
|| type
== QType::DNSKEY
) {
1390 return genericDSAndDNSKEYHandler(res
, domain
, domain
, type
, keys
, false);
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);
1397 return LWResult::Result::Success
;
1401 return LWResult::Result::Timeout
;
1404 SyncRes::s_maxbogusttl
= 3600;
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);
1417 BOOST_CHECK_EQUAL(queriesCount
, 1U);
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
);
1432 BOOST_CHECK_EQUAL(queriesCount
, 3U);
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
);
1446 BOOST_CHECK_EQUAL(queriesCount
, 3U);
1449 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure_any
)
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.
1458 std::unique_ptr
<SyncRes
> sr
;
1461 setDNSSECValidation(sr
, DNSSECMode::Process
);
1464 const DNSName
target("com.");
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
);
1472 size_t queriesCount
= 0;
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 */) {
1477 if (type
== QType::DS
|| type
== QType::DNSKEY
) {
1478 return genericDSAndDNSKEYHandler(res
, domain
, domain
, type
, keys
, false);
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
;
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
;
1495 return LWResult::Result::Timeout
;
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
);
1508 BOOST_CHECK_EQUAL(queriesCount
, 1U);
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
);
1520 BOOST_CHECK_EQUAL(queriesCount
, 2U);
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
);
1532 BOOST_CHECK_EQUAL(queriesCount
, 3U);
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
);
1544 BOOST_CHECK_EQUAL(queriesCount
, 3U);
1547 BOOST_AUTO_TEST_SUITE_END()