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