]>
Commit | Line | Data |
---|---|---|
1c2d079d | 1 | #ifndef BOOST_TEST_DYN_LINK |
86675669 | 2 | #define BOOST_TEST_DYN_LINK |
1c2d079d FM |
3 | #endif |
4 | ||
86675669 OM |
5 | #include <boost/test/unit_test.hpp> |
6 | ||
7 | #include "test-syncres_cc.hh" | |
8 | ||
9 | BOOST_AUTO_TEST_SUITE(syncres_cc8) | |
10 | ||
15e973d6 OM |
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 | ||
42dcf516 OM |
18 | BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) |
19 | { | |
86675669 OM |
20 | initSR(); |
21 | ||
22 | testkeysset_t keys; | |
690b86b7 | 23 | generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
24 | |
25 | vector<DNSRecord> records; | |
26 | ||
c1e7b833 | 27 | sortedRecords_t recordContents; |
d06dcda4 | 28 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
29 | |
30 | /* | |
31 | No wrap test case: | |
32 | a.example.org. -> d.example.org. denies the existence of b.example.org. | |
33 | */ | |
da2636b6 | 34 | addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 35 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 44 | denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair; |
86675669 OM |
45 | |
46 | /* add wildcard denial */ | |
47 | recordContents.clear(); | |
48 | signatureContents.clear(); | |
da2636b6 | 49 | addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 50 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 57 | denialMap[std::pair(DNSName("example.org."), QType::NSEC)] = pair; |
86675669 OM |
58 | |
59 | dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false); | |
98307d0f | 60 | BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); |
86675669 OM |
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 */ | |
98307d0f | 64 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
65 | } |
66 | ||
42dcf516 OM |
67 | BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) |
68 | { | |
86675669 OM |
69 | initSR(); |
70 | ||
71 | testkeysset_t keys; | |
690b86b7 | 72 | generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
73 | |
74 | vector<DNSRecord> records; | |
75 | ||
c1e7b833 | 76 | sortedRecords_t recordContents; |
d06dcda4 | 77 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
78 | |
79 | /* | |
80 | Wrap case 1 test case: | |
81 | z.example.org. -> b.example.org. denies the existence of a.example.org. | |
82 | */ | |
da2636b6 | 83 | addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 84 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 93 | denialMap[std::pair(DNSName("z.example.org."), QType::NSEC)] = pair; |
86675669 OM |
94 | |
95 | dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false); | |
98307d0f | 96 | BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); |
86675669 OM |
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 */ | |
98307d0f | 100 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
101 | } |
102 | ||
42dcf516 OM |
103 | BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) |
104 | { | |
86675669 OM |
105 | initSR(); |
106 | ||
107 | testkeysset_t keys; | |
690b86b7 | 108 | generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
109 | |
110 | vector<DNSRecord> records; | |
111 | ||
c1e7b833 | 112 | sortedRecords_t recordContents; |
d06dcda4 | 113 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
114 | |
115 | /* | |
116 | Wrap case 2 test case: | |
117 | y.example.org. -> a.example.org. denies the existence of z.example.org. | |
118 | */ | |
da2636b6 | 119 | addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 120 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 129 | denialMap[std::pair(DNSName("y.example.org."), QType::NSEC)] = pair; |
86675669 OM |
130 | |
131 | dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false); | |
98307d0f | 132 | BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); |
86675669 OM |
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 */ | |
98307d0f | 136 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
137 | } |
138 | ||
42dcf516 OM |
139 | BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) |
140 | { | |
86675669 OM |
141 | initSR(); |
142 | ||
143 | testkeysset_t keys; | |
690b86b7 | 144 | generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
145 | |
146 | vector<DNSRecord> records; | |
147 | ||
c1e7b833 | 148 | sortedRecords_t recordContents; |
d06dcda4 | 149 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
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 | */ | |
da2636b6 | 155 | addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 156 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 165 | denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair; |
86675669 OM |
166 | |
167 | dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false); | |
98307d0f | 168 | BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); |
86675669 OM |
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 */ | |
98307d0f | 172 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
173 | } |
174 | ||
42dcf516 OM |
175 | BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) |
176 | { | |
86675669 OM |
177 | initSR(); |
178 | ||
179 | testkeysset_t keys; | |
690b86b7 | 180 | generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
181 | |
182 | vector<DNSRecord> records; | |
183 | ||
c1e7b833 | 184 | sortedRecords_t recordContents; |
d06dcda4 | 185 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
186 | |
187 | /* | |
188 | The RRSIG from "." denies the existence of anything between a. and c., | |
189 | including b. | |
190 | */ | |
da2636b6 | 191 | addNSECRecordToLW(DNSName("a."), DNSName("c."), {QType::NS}, 600, records); |
d06dcda4 | 192 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 201 | denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair; |
86675669 OM |
202 | |
203 | /* add wildcard denial */ | |
204 | recordContents.clear(); | |
205 | signatureContents.clear(); | |
da2636b6 | 206 | addNSECRecordToLW(DNSName("."), DNSName("+"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 207 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 214 | denialMap[std::pair(DNSName("."), QType::NSEC)] = pair; |
86675669 OM |
215 | |
216 | dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false); | |
98307d0f | 217 | BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); |
86675669 OM |
218 | } |
219 | ||
42dcf516 OM |
220 | BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) |
221 | { | |
86675669 OM |
222 | initSR(); |
223 | ||
224 | testkeysset_t keys; | |
690b86b7 | 225 | generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
226 | |
227 | vector<DNSRecord> records; | |
228 | ||
c1e7b833 | 229 | sortedRecords_t recordContents; |
d06dcda4 | 230 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
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 | |
0a9dcd16 RG |
236 | be used to deny anything except the whole name (which does not make sense here) |
237 | or a DS. | |
86675669 | 238 | */ |
da2636b6 | 239 | addNSECRecordToLW(DNSName("a."), DNSName("b."), {QType::NS}, 600, records); |
d06dcda4 | 240 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 249 | denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair; |
86675669 OM |
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 | ||
0a9dcd16 | 258 | dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true); |
86675669 OM |
259 | /* no data means the qname/qtype is not denied, because an ancestor |
260 | delegation NSEC can only deny the DS */ | |
98307d0f | 261 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
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); | |
98307d0f | 265 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
266 | |
267 | denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); | |
98307d0f | 268 | BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE); |
86675669 OM |
269 | } |
270 | ||
0a9dcd16 RG |
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; | |
d06dcda4 | 282 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
0a9dcd16 RG |
283 | |
284 | addNSECRecordToLW(DNSName("example.org."), DNSName("a.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); | |
d06dcda4 | 285 | recordContents.insert(records.at(0).getContent()); |
0a9dcd16 RG |
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; | |
faa05786 | 294 | denialMap[std::pair(DNSName("example.org."), QType::NSEC)] = pair; |
0a9dcd16 RG |
295 | |
296 | /* check that this NSEC from the child zone can deny a AAAA at the apex */ | |
10971f78 | 297 | BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("example.org."), QType::AAAA, false, true, std::nullopt, true), dState::NXQTYPE); |
0a9dcd16 RG |
298 | |
299 | /* but not that the DS does not exist, since we need the parent for that */ | |
10971f78 | 300 | BOOST_CHECK_EQUAL(getDenial(denialMap, DNSName("example.org."), QType::DS, false, true, std::nullopt, true), dState::NODENIAL); |
0a9dcd16 RG |
301 | } |
302 | ||
42dcf516 OM |
303 | BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) |
304 | { | |
86675669 OM |
305 | initSR(); |
306 | ||
307 | testkeysset_t keys; | |
690b86b7 | 308 | generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
309 | |
310 | vector<DNSRecord> records; | |
311 | ||
c1e7b833 | 312 | sortedRecords_t recordContents; |
d06dcda4 | 313 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
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 | */ | |
da2636b6 | 327 | addNSECRecordToLW(DNSName("a."), DNSName("b."), {}, 600, records); |
d06dcda4 | 328 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 337 | denialMap[std::pair(DNSName("a."), QType::NSEC)] = pair; |
86675669 OM |
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); | |
98307d0f | 342 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
343 | } |
344 | ||
be5d851d RG |
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; | |
d06dcda4 | 355 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
be5d851d RG |
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); | |
d06dcda4 | 369 | recordContents.insert(records.at(0).getContent()); |
be5d851d RG |
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 | ||
42dcf516 OM |
385 | BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) |
386 | { | |
86675669 OM |
387 | initSR(); |
388 | ||
389 | testkeysset_t keys; | |
690b86b7 | 390 | generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
391 | |
392 | vector<DNSRecord> records; | |
393 | ||
c1e7b833 | 394 | sortedRecords_t recordContents; |
d06dcda4 | 395 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 | 396 | |
da2636b6 | 397 | addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), {QType::CNAME}, 600, records); |
d06dcda4 | 398 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 407 | denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair; |
86675669 OM |
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); | |
98307d0f | 411 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
412 | } |
413 | ||
0a9dcd16 RG |
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; | |
d06dcda4 | 424 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
15e973d6 OM |
425 | const unsigned int nbIterations = 10; |
426 | addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A}, 600, records, nbIterations); | |
d06dcda4 | 427 | recordContents.insert(records.at(0).getContent()); |
0a9dcd16 RG |
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; | |
faa05786 | 435 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
0a9dcd16 RG |
436 | records.clear(); |
437 | ||
15e973d6 OM |
438 | pdns::validation::ValidationContext validationContext; |
439 | validationContext.d_nsec3IterationsRemainingQuota = 100U; | |
0a9dcd16 | 440 | /* this NSEC3 is not valid to deny the DS since it is from the child zone */ |
15e973d6 OM |
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); | |
0a9dcd16 | 444 | /* AAAA should be fine, though */ |
15e973d6 OM |
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)); | |
0a9dcd16 RG |
447 | } |
448 | ||
42dcf516 OM |
449 | BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) |
450 | { | |
86675669 OM |
451 | initSR(); |
452 | ||
453 | testkeysset_t keys; | |
690b86b7 | 454 | generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
455 | |
456 | vector<DNSRecord> records; | |
457 | ||
c1e7b833 | 458 | sortedRecords_t recordContents; |
d06dcda4 | 459 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 | 460 | |
da2636b6 | 461 | addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::CNAME}, 600, records); |
d06dcda4 | 462 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 470 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 OM |
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); | |
98307d0f | 475 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
476 | } |
477 | ||
42dcf516 OM |
478 | BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) |
479 | { | |
86675669 OM |
480 | initSR(); |
481 | ||
482 | testkeysset_t keys; | |
690b86b7 | 483 | generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
484 | |
485 | vector<DNSRecord> records; | |
486 | ||
c1e7b833 | 487 | sortedRecords_t recordContents; |
d06dcda4 | 488 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 | 489 | |
da2636b6 | 490 | addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 491 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 500 | denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair; |
86675669 OM |
501 | |
502 | dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false); | |
98307d0f | 503 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
504 | } |
505 | ||
42dcf516 OM |
506 | BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) |
507 | { | |
86675669 OM |
508 | initSR(); |
509 | ||
510 | testkeysset_t keys; | |
690b86b7 | 511 | generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
512 | |
513 | vector<DNSRecord> records; | |
514 | ||
c1e7b833 | 515 | sortedRecords_t recordContents; |
d06dcda4 | 516 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 | 517 | |
d270600b | 518 | addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records, 10); |
d06dcda4 | 519 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 527 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 OM |
528 | |
529 | /* Add NSEC3 for the closest encloser */ | |
530 | recordContents.clear(); | |
531 | signatureContents.clear(); | |
532 | records.clear(); | |
d270600b | 533 | addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records, 10); |
d06dcda4 | 534 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 540 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 | 541 | |
0cbcfeda RG |
542 | dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, false); |
543 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); | |
544 | } | |
545 | ||
399f391d RG |
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; | |
d06dcda4 | 556 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
399f391d RG |
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); | |
d06dcda4 | 560 | recordContents.insert(records.at(0).getContent()); |
399f391d RG |
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; | |
faa05786 | 569 | denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair; |
399f391d RG |
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 */ | |
10971f78 | 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); |
399f391d RG |
574 | BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); |
575 | } | |
576 | ||
0cbcfeda RG |
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; | |
d06dcda4 | 587 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
0cbcfeda RG |
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); | |
d06dcda4 | 591 | recordContents.insert(records.at(0).getContent()); |
0cbcfeda RG |
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; | |
faa05786 | 600 | denialMap[std::pair(DNSName("a.example.org."), QType::NSEC)] = pair; |
0cbcfeda RG |
601 | |
602 | /* add a NSEC proving that a wildcard exists, without a CNAME type */ | |
603 | recordContents.clear(); | |
604 | signatureContents.clear(); | |
45c1026d | 605 | addNSECRecordToLW(DNSName("*.example.org."), DNSName("+.example.org"), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 606 | recordContents.insert(records.at(0).getContent()); |
0cbcfeda RG |
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; | |
faa05786 | 613 | denialMap[std::pair(DNSName("*.example.org."), QType::NSEC)] = pair; |
0cbcfeda RG |
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(); | |
45c1026d | 625 | addNSECRecordToLW(DNSName("*.example.org."), DNSName("+.example.org"), {QType::CNAME, QType::RRSIG, QType::NSEC}, 600, records); |
d06dcda4 | 626 | recordContents.insert(records.at(0).getContent()); |
0cbcfeda RG |
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; | |
faa05786 | 633 | denialMap[std::pair(DNSName("*.example.org."), QType::NSEC)] = pair; |
0cbcfeda RG |
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; | |
d06dcda4 | 653 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
0cbcfeda RG |
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); | |
d06dcda4 | 657 | recordContents.insert(records.at(0).getContent()); |
0cbcfeda RG |
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; | |
faa05786 | 665 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
0cbcfeda RG |
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); | |
d06dcda4 | 672 | recordContents.insert(records.at(0).getContent()); |
0cbcfeda RG |
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; | |
faa05786 | 678 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
0cbcfeda RG |
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); | |
d06dcda4 | 685 | recordContents.insert(records.at(0).getContent()); |
0cbcfeda RG |
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; | |
faa05786 | 691 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
0cbcfeda RG |
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); | |
d06dcda4 | 705 | recordContents.insert(records.at(0).getContent()); |
0cbcfeda RG |
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; | |
faa05786 | 711 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
0cbcfeda RG |
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); | |
98307d0f | 718 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
719 | } |
720 | ||
42dcf516 OM |
721 | BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) |
722 | { | |
86675669 OM |
723 | initSR(); |
724 | ||
725 | testkeysset_t keys; | |
690b86b7 | 726 | generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
727 | |
728 | vector<DNSRecord> records; | |
729 | ||
c1e7b833 | 730 | sortedRecords_t recordContents; |
d06dcda4 | 731 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 | 732 | |
da2636b6 | 733 | addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), {QType::A}, 600, records); |
d06dcda4 | 734 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 743 | denialMap[std::pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair; |
86675669 OM |
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); | |
98307d0f | 748 | BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE); |
86675669 OM |
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); | |
98307d0f | 753 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
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); | |
98307d0f | 757 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
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(); | |
da2636b6 | 762 | addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), {}, 600, records); |
d06dcda4 | 763 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 769 | denialMap[std::pair(DNSName(").powerdns.com."), QType::NSEC)] = pair; |
86675669 OM |
770 | |
771 | denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false); | |
98307d0f | 772 | BOOST_CHECK_EQUAL(denialState, dState::NXDOMAIN); |
95256c05 RG |
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); | |
98307d0f | 777 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
778 | } |
779 | ||
42dcf516 OM |
780 | BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) |
781 | { | |
86675669 OM |
782 | initSR(); |
783 | ||
784 | testkeysset_t keys; | |
690b86b7 | 785 | generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
786 | |
787 | vector<DNSRecord> records; | |
788 | ||
c1e7b833 | 789 | sortedRecords_t recordContents; |
d06dcda4 | 790 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
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 | */ | |
da2636b6 | 798 | addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::NS}, 600, records); |
d06dcda4 | 799 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 807 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 OM |
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); | |
0cbcfeda | 818 | /* no denial means the qname/qtype is not denied, because an ancestor |
86675669 | 819 | delegation NSEC3 can only deny the DS */ |
98307d0f | 820 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
821 | |
822 | denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); | |
98307d0f | 823 | BOOST_CHECK_EQUAL(denialState, dState::NXQTYPE); |
86675669 OM |
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(); | |
da2636b6 | 830 | addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records); |
d06dcda4 | 831 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
832 | addRRSIG(keys, records, DNSName("."), 300); |
833 | signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1))); | |
834 | ||
835 | pair.records = recordContents; | |
836 | pair.signatures = signatureContents; | |
faa05786 | 837 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 OM |
838 | |
839 | /* add wildcard denial */ | |
840 | recordContents.clear(); | |
841 | signatureContents.clear(); | |
842 | records.clear(); | |
da2636b6 | 843 | addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), {QType::A, QType::TXT, QType::RRSIG, QType::NSEC3}, 600, records); |
d06dcda4 | 844 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
845 | addRRSIG(keys, records, DNSName("."), 300); |
846 | signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1))); | |
847 | ||
848 | pair.records = recordContents; | |
849 | pair.signatures = signatureContents; | |
faa05786 | 850 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 OM |
851 | |
852 | denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true); | |
98307d0f | 853 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
0a9dcd16 RG |
854 | |
855 | /* not even the DS! */ | |
856 | denialState = getDenial(denialMap, DNSName("sub.a."), QType::DS, false, true); | |
857 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); | |
86675669 OM |
858 | } |
859 | ||
42dcf516 OM |
860 | BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) |
861 | { | |
86675669 OM |
862 | initSR(); |
863 | ||
864 | testkeysset_t keys; | |
690b86b7 | 865 | generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
866 | |
867 | vector<DNSRecord> records; | |
868 | ||
c1e7b833 | 869 | sortedRecords_t recordContents; |
d06dcda4 | 870 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
871 | |
872 | /* adding a NSEC3 with more iterations that we support */ | |
da2636b6 | 873 | addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {QType::AAAA}, 600, records, g_maxNSEC3Iterations + 100); |
d06dcda4 | 874 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 882 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 OM |
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 */ | |
98307d0f | 887 | BOOST_CHECK_EQUAL(denialState, dState::INSECURE); |
86675669 OM |
888 | } |
889 | ||
42dcf516 OM |
890 | BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) |
891 | { | |
86675669 OM |
892 | initSR(); |
893 | ||
894 | testkeysset_t keys; | |
690b86b7 | 895 | generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); |
86675669 OM |
896 | |
897 | vector<DNSRecord> records; | |
898 | ||
c1e7b833 | 899 | sortedRecords_t recordContents; |
d06dcda4 | 900 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
86675669 OM |
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 | */ | |
da2636b6 | 914 | addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", {}, 600, records); |
d06dcda4 | 915 | recordContents.insert(records.at(0).getContent()); |
86675669 OM |
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; | |
faa05786 | 923 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
86675669 OM |
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); | |
98307d0f | 929 | BOOST_CHECK_EQUAL(denialState, dState::NODENIAL); |
86675669 OM |
930 | } |
931 | ||
be5d851d RG |
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; | |
d06dcda4 | 942 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
be5d851d RG |
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); | |
d06dcda4 | 956 | recordContents.insert(records.at(0).getContent()); |
be5d851d RG |
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 | ||
ce454638 RG |
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; | |
d06dcda4 | 982 | vector<shared_ptr<const RRSIGRecordContent>> signatureContents; |
ce454638 RG |
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 */); | |
d06dcda4 | 997 | recordContents.insert(records.at(0).getContent()); |
ce454638 RG |
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; | |
faa05786 | 1005 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
ce454638 RG |
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 */); | |
d06dcda4 | 1013 | recordContents.insert(records.at(0).getContent()); |
ce454638 RG |
1014 | addRRSIG(keys, records, DNSName("."), 300); |
1015 | signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1))); | |
1016 | ||
1017 | pair.records = recordContents; | |
1018 | pair.signatures = signatureContents; | |
faa05786 | 1019 | denialMap[std::pair(records.at(0).d_name, records.at(0).d_type)] = pair; |
ce454638 RG |
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 | ||
42dcf516 OM |
1026 | BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) |
1027 | { | |
86675669 OM |
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(); | |
690b86b7 OM |
1039 | generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); |
1040 | generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); | |
86675669 OM |
1041 | g_luaconfs.setState(luaconfsCopy); |
1042 | ||
1043 | size_t queriesCount = 0; | |
1044 | const time_t fixedNow = sr->getNow().tv_sec; | |
1045 | ||
c0f8e484 | 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 */) { |
42dcf516 | 1047 | queriesCount++; |
86675669 | 1048 | |
42dcf516 OM |
1049 | DNSName auth = domain; |
1050 | auth.chopOff(); | |
86675669 | 1051 | |
42dcf516 OM |
1052 | if (type == QType::DS || type == QType::DNSKEY) { |
1053 | return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); | |
1054 | } | |
c0f8e484 | 1055 | { |
42dcf516 OM |
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); | |
308f4c43 | 1061 | return LWResult::Result::Success; |
42dcf516 | 1062 | } |
86675669 | 1063 | |
308f4c43 | 1064 | return LWResult::Result::Timeout; |
42dcf516 | 1065 | }); |
86675669 OM |
1066 | |
1067 | vector<DNSRecord> ret; | |
1068 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1069 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
98307d0f | 1070 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); |
690b86b7 OM |
1071 | BOOST_REQUIRE_EQUAL(ret.size(), 4U); |
1072 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
86675669 OM |
1073 | |
1074 | /* check that the entry has not been negatively cached for longer than the RRSIG validity */ | |
33433a8a | 1075 | NegCache::NegCacheEntry ne; |
ccfadb6c OM |
1076 | BOOST_CHECK_EQUAL(g_negCache->size(), 1U); |
1077 | BOOST_REQUIRE_EQUAL(g_negCache->get(target, QType(QType::A), sr->getNow(), ne), true); | |
33433a8a | 1078 | BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + 1); |
98307d0f | 1079 | BOOST_CHECK_EQUAL(ne.d_validationState, vState::Secure); |
33433a8a RG |
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); | |
86675669 OM |
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); | |
98307d0f | 1089 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); |
690b86b7 OM |
1090 | BOOST_REQUIRE_EQUAL(ret.size(), 4U); |
1091 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
86675669 OM |
1092 | } |
1093 | ||
42dcf516 OM |
1094 | BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_bogus_validity) |
1095 | { | |
86675669 OM |
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(); | |
690b86b7 OM |
1107 | generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); |
1108 | generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); | |
86675669 OM |
1109 | g_luaconfs.setState(luaconfsCopy); |
1110 | ||
1111 | size_t queriesCount = 0; | |
1112 | const time_t fixedNow = sr->getNow().tv_sec; | |
1113 | ||
c0f8e484 | 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 */) { |
42dcf516 | 1115 | queriesCount++; |
86675669 | 1116 | |
42dcf516 OM |
1117 | DNSName auth = domain; |
1118 | auth.chopOff(); | |
86675669 | 1119 | |
42dcf516 OM |
1120 | if (type == QType::DS || type == QType::DNSKEY) { |
1121 | return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); | |
1122 | } | |
c0f8e484 | 1123 | { |
42dcf516 OM |
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 */ | |
308f4c43 | 1129 | return LWResult::Result::Success; |
42dcf516 | 1130 | } |
86675669 | 1131 | |
308f4c43 | 1132 | return LWResult::Result::Timeout; |
42dcf516 | 1133 | }); |
86675669 OM |
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); | |
fd870915 | 1141 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG); |
690b86b7 OM |
1142 | BOOST_REQUIRE_EQUAL(ret.size(), 3U); |
1143 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
86675669 OM |
1144 | |
1145 | /* check that the entry has been negatively cached but not longer than s_maxbogusttl */ | |
33433a8a | 1146 | NegCache::NegCacheEntry ne; |
ccfadb6c OM |
1147 | BOOST_CHECK_EQUAL(g_negCache->size(), 1U); |
1148 | BOOST_REQUIRE_EQUAL(g_negCache->get(target, QType(QType::A), sr->getNow(), ne), true); | |
33433a8a | 1149 | BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + SyncRes::s_maxbogusttl); |
fd870915 | 1150 | BOOST_CHECK_EQUAL(ne.d_validationState, vState::BogusNoRRSIG); |
33433a8a RG |
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); | |
86675669 OM |
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); | |
fd870915 | 1160 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG); |
690b86b7 OM |
1161 | BOOST_REQUIRE_EQUAL(ret.size(), 3U); |
1162 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
86675669 OM |
1163 | } |
1164 | ||
42dcf516 OM |
1165 | BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) |
1166 | { | |
86675669 OM |
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(); | |
690b86b7 OM |
1179 | generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); |
1180 | generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); | |
86675669 OM |
1181 | g_luaconfs.setState(luaconfsCopy); |
1182 | ||
1183 | size_t queriesCount = 0; | |
1184 | const time_t tnow = sr->getNow().tv_sec; | |
1185 | ||
c0f8e484 | 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 */) { |
42dcf516 | 1187 | queriesCount++; |
86675669 | 1188 | |
42dcf516 OM |
1189 | DNSName auth = domain; |
1190 | auth.chopOff(); | |
86675669 | 1191 | |
42dcf516 OM |
1192 | if (type == QType::DS || type == QType::DNSKEY) { |
1193 | return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); | |
1194 | } | |
c0f8e484 | 1195 | { |
42dcf516 OM |
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); | |
308f4c43 | 1199 | return LWResult::Result::Success; |
42dcf516 | 1200 | } |
86675669 | 1201 | |
308f4c43 | 1202 | return LWResult::Result::Timeout; |
42dcf516 | 1203 | }); |
86675669 OM |
1204 | |
1205 | vector<DNSRecord> ret; | |
1206 | int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); | |
1207 | BOOST_CHECK_EQUAL(res, RCode::NoError); | |
98307d0f | 1208 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); |
690b86b7 OM |
1209 | BOOST_REQUIRE_EQUAL(ret.size(), 2U); |
1210 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
86675669 OM |
1211 | |
1212 | /* check that the entry has not been cached for longer than the RRSIG validity */ | |
1213 | const ComboAddress who; | |
1214 | vector<DNSRecord> cached; | |
d06dcda4 | 1215 | vector<std::shared_ptr<const RRSIGRecordContent>> signatures; |
171089f5 | 1216 | BOOST_REQUIRE_EQUAL(g_recCache->get(tnow, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who, boost::none, &signatures), 1); |
690b86b7 OM |
1217 | BOOST_REQUIRE_EQUAL(cached.size(), 1U); |
1218 | BOOST_REQUIRE_EQUAL(signatures.size(), 1U); | |
86675669 OM |
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); | |
98307d0f | 1225 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); |
690b86b7 OM |
1226 | BOOST_REQUIRE_EQUAL(ret.size(), 2U); |
1227 | BOOST_CHECK_EQUAL(queriesCount, 4U); | |
86675669 OM |
1228 | } |
1229 | ||
42dcf516 OM |
1230 | BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) |
1231 | { | |
86675669 OM |
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(); | |
690b86b7 | 1249 | generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); |
86675669 OM |
1250 | g_luaconfs.setState(luaconfsCopy); |
1251 | ||
1252 | size_t queriesCount = 0; | |
1253 | ||
c0f8e484 | 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 */) { |
42dcf516 OM |
1255 | queriesCount++; |
1256 | ||
1257 | if (type == QType::DS || type == QType::DNSKEY) { | |
1258 | return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); | |
1259 | } | |
c0f8e484 | 1260 | { |
42dcf516 OM |
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); | |
308f4c43 | 1265 | return LWResult::Result::Success; |
86675669 | 1266 | } |
42dcf516 | 1267 | } |
86675669 | 1268 | |
308f4c43 | 1269 | return LWResult::Result::Timeout; |
42dcf516 | 1270 | }); |
86675669 OM |
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); | |
98307d0f | 1277 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate); |
690b86b7 | 1278 | BOOST_REQUIRE_EQUAL(ret.size(), 2U); |
86675669 OM |
1279 | for (const auto& record : ret) { |
1280 | BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG); | |
1281 | } | |
690b86b7 | 1282 | BOOST_CHECK_EQUAL(queriesCount, 1U); |
86675669 | 1283 | |
86675669 OM |
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); | |
98307d0f | 1289 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); |
690b86b7 | 1290 | BOOST_REQUIRE_EQUAL(ret.size(), 2U); |
86675669 OM |
1291 | for (const auto& record : ret) { |
1292 | BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG); | |
1293 | } | |
7c1fe83b | 1294 | BOOST_CHECK_EQUAL(queriesCount, 2U); |
86675669 OM |
1295 | } |
1296 | ||
42dcf516 OM |
1297 | BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) |
1298 | { | |
86675669 OM |
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 | ||
c0f8e484 | 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 */) { |
42dcf516 | 1321 | queriesCount++; |
86675669 | 1322 | |
42dcf516 OM |
1323 | if (type == QType::DS || type == QType::DNSKEY) { |
1324 | return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); | |
1325 | } | |
c0f8e484 | 1326 | { |
42dcf516 OM |
1327 | if (domain == target && type == QType::A) { |
1328 | setLWResult(res, 0, true, false, true); | |
1329 | addRecordToLW(res, target, QType::A, "192.0.2.1"); | |
308f4c43 | 1330 | return LWResult::Result::Success; |
86675669 | 1331 | } |
42dcf516 | 1332 | } |
86675669 | 1333 | |
308f4c43 | 1334 | return LWResult::Result::Timeout; |
42dcf516 | 1335 | }); |
86675669 OM |
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); | |
98307d0f | 1342 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate); |
690b86b7 | 1343 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
1344 | for (const auto& record : ret) { |
1345 | BOOST_CHECK(record.d_type == QType::A); | |
1346 | } | |
690b86b7 | 1347 | BOOST_CHECK_EQUAL(queriesCount, 1U); |
86675669 | 1348 | |
86675669 OM |
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); | |
98307d0f | 1354 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure); |
690b86b7 | 1355 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
1356 | for (const auto& record : ret) { |
1357 | BOOST_CHECK(record.d_type == QType::A); | |
1358 | } | |
690b86b7 | 1359 | BOOST_CHECK_EQUAL(queriesCount, 1U); |
86675669 OM |
1360 | } |
1361 | ||
42dcf516 OM |
1362 | BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) |
1363 | { | |
86675669 OM |
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(); | |
690b86b7 | 1381 | generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); |
86675669 OM |
1382 | g_luaconfs.setState(luaconfsCopy); |
1383 | ||
1384 | size_t queriesCount = 0; | |
1385 | ||
c0f8e484 | 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 */) { |
42dcf516 | 1387 | queriesCount++; |
86675669 | 1388 | |
42dcf516 OM |
1389 | if (type == QType::DS || type == QType::DNSKEY) { |
1390 | return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); | |
1391 | } | |
c0f8e484 | 1392 | { |
42dcf516 OM |
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 */ | |
308f4c43 | 1397 | return LWResult::Result::Success; |
86675669 | 1398 | } |
42dcf516 | 1399 | } |
86675669 | 1400 | |
308f4c43 | 1401 | return LWResult::Result::Timeout; |
42dcf516 | 1402 | }); |
86675669 OM |
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); | |
98307d0f | 1411 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate); |
690b86b7 | 1412 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
1413 | for (const auto& record : ret) { |
1414 | BOOST_CHECK(record.d_type == QType::A); | |
690b86b7 | 1415 | BOOST_CHECK_EQUAL(record.d_ttl, 86400U); |
86675669 | 1416 | } |
690b86b7 | 1417 | BOOST_CHECK_EQUAL(queriesCount, 1U); |
86675669 | 1418 | |
86675669 OM |
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); | |
fd870915 | 1424 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG); |
86675669 OM |
1425 | /* check that we correctly capped the TTD for a Bogus record after |
1426 | just-in-time validation */ | |
690b86b7 | 1427 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
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 | } | |
690b86b7 | 1432 | BOOST_CHECK_EQUAL(queriesCount, 3U); |
86675669 OM |
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); | |
fd870915 | 1440 | BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG); |
690b86b7 | 1441 | BOOST_REQUIRE_EQUAL(ret.size(), 1U); |
86675669 OM |
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 | } | |
690b86b7 | 1446 | BOOST_CHECK_EQUAL(queriesCount, 3U); |
86675669 OM |
1447 | } |
1448 | ||
593f56c6 RG |
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 | ||
c0f8e484 | 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 */) { |
593f56c6 RG |
1475 | queriesCount++; |
1476 | ||
1477 | if (type == QType::DS || type == QType::DNSKEY) { | |
1478 | return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false); | |
1479 | } | |
c0f8e484 | 1480 | { |
593f56c6 RG |
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); | |
308f4c43 | 1485 | return LWResult::Result::Success; |
593f56c6 | 1486 | } |
c0f8e484 | 1487 | if (domain == target && type == QType::AAAA) { |
593f56c6 RG |
1488 | setLWResult(res, 0, true, false, true); |
1489 | addRecordToLW(res, target, QType::AAAA, "2001:db8::1"); | |
1490 | addRRSIG(keys, res->d_records, DNSName("."), 300); | |
308f4c43 | 1491 | return LWResult::Result::Success; |
593f56c6 RG |
1492 | } |
1493 | } | |
1494 | ||
308f4c43 | 1495 | return LWResult::Result::Timeout; |
593f56c6 RG |
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 | } | |
7c1fe83b | 1532 | BOOST_CHECK_EQUAL(queriesCount, 3U); |
593f56c6 RG |
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 | } | |
7c1fe83b | 1544 | BOOST_CHECK_EQUAL(queriesCount, 3U); |
593f56c6 RG |
1545 | } |
1546 | ||
86675669 | 1547 | BOOST_AUTO_TEST_SUITE_END() |