1use std::{clone::Clone, collections::HashSet, error::Error, pin::Pin, sync::Arc};
11
12use futures_util::{
13 future::{self, Future, FutureExt, TryFutureExt},
14 stream::{self, Stream, TryStreamExt},
15};
16use tracing::{debug, trace};
17
18use crate::{
19 error::{ProtoError, ProtoErrorKind, ProtoResult},
20 op::{Edns, OpCode, Query},
21 rr::{
22 dnssec::{
23 rdata::{DNSSECRData, DNSKEY, RRSIG},
24 Algorithm, SupportedAlgorithms, TrustAnchor,
25 },
26 rdata::opt::EdnsOption,
27 DNSClass, Name, RData, Record, RecordData, RecordType,
28 },
29 xfer::{dns_handle::DnsHandle, DnsRequest, DnsRequestOptions, DnsResponse, FirstAnswer},
30};
31
32#[cfg(feature = "dnssec")]
33use crate::rr::dnssec::Verifier;
34
35#[derive(Debug)]
36struct Rrset {
37 pub(crate) name: Name,
38 pub(crate) record_type: RecordType,
39 pub(crate) record_class: DNSClass,
40 pub(crate) records: Vec<Record>,
41}
42
43#[derive(Clone)]
49#[must_use = "queries can only be sent through a DnsHandle"]
50pub struct DnssecDnsHandle<H>
51where
52 H: DnsHandle + Unpin + 'static,
53{
54 handle: H,
55 trust_anchor: Arc<TrustAnchor>,
56 request_depth: usize,
57 minimum_key_len: usize,
58 minimum_algorithm: Algorithm, }
60
61impl<H> DnssecDnsHandle<H>
62where
63 H: DnsHandle + Unpin + 'static,
64{
65 pub fn new(handle: H) -> Self {
72 Self::with_trust_anchor(handle, TrustAnchor::default())
73 }
74
75 pub fn with_trust_anchor(handle: H, trust_anchor: TrustAnchor) -> Self {
83 Self {
84 handle,
85 trust_anchor: Arc::new(trust_anchor),
86 request_depth: 0,
87 minimum_key_len: 0,
88 minimum_algorithm: Algorithm::RSASHA256,
89 }
90 }
91
92 fn clone_with_context(&self) -> Self {
96 Self {
97 handle: self.handle.clone(),
98 trust_anchor: Arc::clone(&self.trust_anchor),
99 request_depth: self.request_depth + 1,
100 minimum_key_len: self.minimum_key_len,
101 minimum_algorithm: self.minimum_algorithm,
102 }
103 }
104}
105
106impl<H> DnsHandle for DnssecDnsHandle<H>
107where
108 H: DnsHandle + Sync + Unpin,
109{
110 type Response = Pin<Box<dyn Stream<Item = Result<DnsResponse, Self::Error>> + Send>>;
111 type Error = <H as DnsHandle>::Error;
112
113 fn is_verifying_dnssec(&self) -> bool {
114 true
116 }
117
118 fn send<R: Into<DnsRequest>>(&self, request: R) -> Self::Response {
119 let mut request = request.into();
120
121 if self.request_depth > request.options().max_request_depth {
123 return Box::pin(stream::once(future::err(Self::Error::from(
124 ProtoError::from("exceeded max validation depth"),
125 ))));
126 }
127
128 if let OpCode::Query = request.op_code() {
130 let query = request
133 .queries()
134 .first()
135 .cloned()
136 .expect("no queries in request");
137 let handle: Self = self.clone_with_context();
138
139 #[cfg(feature = "dnssec")]
141 {
142 let edns = request.extensions_mut().get_or_insert_with(Edns::new);
143 edns.set_dnssec_ok(true);
144
145 let mut algorithms = SupportedAlgorithms::new();
147 #[cfg(feature = "ring")]
148 {
149 algorithms.set(Algorithm::ED25519);
150 }
151 algorithms.set(Algorithm::ECDSAP256SHA256);
152 algorithms.set(Algorithm::ECDSAP384SHA384);
153 algorithms.set(Algorithm::RSASHA256);
154
155 let dau = EdnsOption::DAU(algorithms);
156 let dhu = EdnsOption::DHU(algorithms);
157
158 edns.options_mut().insert(dau);
159 edns.options_mut().insert(dhu);
160 }
161
162 request.set_authentic_data(true);
163 request.set_checking_disabled(false);
164 let dns_class = request
165 .queries()
166 .first()
167 .map_or(DNSClass::IN, Query::query_class);
168 let options = *request.options();
169
170 return Box::pin(
171 self.handle
172 .send(request)
173 .and_then(move |message_response| {
174 debug!(
177 "validating message_response: {}, with {} trust_anchors",
178 message_response.id(),
179 handle.trust_anchor.len(),
180 );
181 verify_rrsets(handle.clone(), message_response, dns_class, options)
182 })
183 .and_then(move |verified_message| {
184 if verified_message.answers().is_empty() {
188 let soa_name = if let Some(soa_name) = verified_message
190 .name_servers()
191 .iter()
192 .find(|rr| rr.record_type() == RecordType::SOA)
194 .map(Record::name)
195 {
196 soa_name
197 } else {
198 return future::err(Self::Error::from(ProtoError::from(
199 "could not validate negative response missing SOA",
200 )));
201 };
202
203 let nsecs = verified_message
204 .name_servers()
205 .iter()
206 .filter(|rr| is_dnssec(rr, RecordType::NSEC))
207 .collect::<Vec<_>>();
208
209 if !verify_nsec(&query, soa_name, nsecs.as_slice()) {
210 return future::err(Self::Error::from(ProtoError::from(
212 "could not validate negative response with NSEC",
213 )));
214 }
215 }
216
217 future::ok(verified_message)
218 }),
219 );
220 }
221
222 Box::pin(self.handle.send(request))
223 }
224}
225
226#[allow(clippy::type_complexity)]
229async fn verify_rrsets<H, E>(
230 handle: DnssecDnsHandle<H>,
231 message_result: DnsResponse,
232 dns_class: DNSClass,
233 options: DnsRequestOptions,
234) -> Result<DnsResponse, E>
235where
236 H: DnsHandle<Error = E> + Sync + Unpin,
237 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
238{
239 let mut rrset_types: HashSet<(Name, RecordType)> = HashSet::new();
240 for rrset in message_result
241 .answers()
242 .iter()
243 .chain(message_result.name_servers())
244 .filter(|rr| {
245 !is_dnssec(rr, RecordType::RRSIG) &&
246 (handle.request_depth <= 1 ||
251 is_dnssec(rr, RecordType::DNSKEY) ||
252 is_dnssec(rr, RecordType::DS))
253 })
254 .map(|rr| (rr.name().clone(), rr.record_type()))
255 {
256 rrset_types.insert(rrset);
257 }
258
259 if rrset_types.is_empty() {
261 let mut message_result = message_result.into_message();
262
263 message_result.take_answers();
265 message_result.take_name_servers();
266 message_result.take_additionals();
267
268 return Err(E::from(ProtoError::from(ProtoErrorKind::Message(
269 "no results to verify",
270 ))));
271 }
272
273 let mut rrsets_to_verify = Vec::with_capacity(rrset_types.len());
276 for (name, record_type) in rrset_types {
277 let records: Vec<Record> = message_result
279 .answers()
280 .iter()
281 .chain(message_result.name_servers())
282 .chain(message_result.additionals())
283 .filter(|rr| rr.record_type() == record_type && rr.name() == &name)
284 .cloned()
285 .collect();
286
287 let rrsigs: Vec<Record<RRSIG>> = message_result
288 .answers()
289 .iter()
290 .chain(message_result.name_servers())
291 .chain(message_result.additionals())
292 .filter(|rr| is_dnssec(rr, RecordType::RRSIG))
293 .filter(|rr| {
294 if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref rrsig))) = rr.data() {
295 rrsig.type_covered() == record_type
296 } else {
297 false
298 }
299 })
300 .cloned()
301 .map(|rr| Record::<RRSIG>::try_from(rr).expect("the record type was checked above"))
302 .collect();
303
304 let rrset = Rrset {
307 name,
308 record_type,
309 record_class: dns_class,
310 records,
311 };
312
313 debug!(
315 "verifying: {}, record_type: {:?}, rrsigs: {}",
316 rrset.name,
317 record_type,
318 rrsigs.len()
319 );
320 rrsets_to_verify
321 .push(verify_rrset(handle.clone_with_context(), rrset, rrsigs, options).boxed());
322 }
323
324 verify_all_rrsets(message_result, rrsets_to_verify).await
326}
327
328fn is_dnssec<D: RecordData>(rr: &Record<D>, dnssec_type: RecordType) -> bool {
330 rr.record_type().is_dnssec() && dnssec_type.is_dnssec() && rr.record_type() == dnssec_type
331}
332
333async fn verify_all_rrsets<F, E>(
334 message_result: DnsResponse,
335 rrsets: Vec<F>,
336) -> Result<DnsResponse, E>
337where
338 F: Future<Output = Result<Rrset, E>> + Send + Unpin,
339 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
340{
341 let mut verified_rrsets: HashSet<(Name, RecordType)> = HashSet::new();
342 let mut rrsets = future::select_all(rrsets);
343 let mut last_validation_err: Option<E> = None;
344
345 loop {
348 let (rrset, _, remaining) = rrsets.await;
349 match rrset {
350 Ok(rrset) => {
351 debug!(
352 "an rrset was verified: {}, {:?}",
353 rrset.name, rrset.record_type
354 );
355 verified_rrsets.insert((rrset.name, rrset.record_type));
356 }
357 Err(e) => {
361 if tracing::enabled!(tracing::Level::DEBUG) {
362 let mut query = message_result
363 .queries()
364 .iter()
365 .map(|q| q.to_string())
366 .fold(String::new(), |s, q| format!("{q},{s}"));
367
368 query.truncate(query.len() - 1);
369 debug!("an rrset failed to verify ({}): {:?}", query, e);
370 }
371
372 last_validation_err = Some(e);
373 }
374 };
375
376 if !remaining.is_empty() {
377 rrsets = future::select_all(remaining);
379 } else {
380 break;
381 }
382 }
383
384 if verified_rrsets.is_empty() {
386 if let Some(last_validation_err) = last_validation_err {
387 return Err(last_validation_err);
388 }
389 }
390
391 let (mut message_result, message_buffer) = message_result.into_parts();
393
394 let answers = message_result
399 .take_answers()
400 .into_iter()
401 .chain(message_result.take_additionals().into_iter())
402 .filter(|record| verified_rrsets.contains(&(record.name().clone(), record.record_type())))
403 .collect::<Vec<Record>>();
404
405 let name_servers = message_result
406 .take_name_servers()
407 .into_iter()
408 .filter(|record| verified_rrsets.contains(&(record.name().clone(), record.record_type())))
409 .collect::<Vec<Record>>();
410
411 let additionals = message_result
412 .take_additionals()
413 .into_iter()
414 .filter(|record| verified_rrsets.contains(&(record.name().clone(), record.record_type())))
415 .collect::<Vec<Record>>();
416
417 message_result.insert_answers(answers);
419 message_result.insert_name_servers(name_servers);
420 message_result.insert_additionals(additionals);
421
422 Ok(DnsResponse::new(message_result, message_buffer))
424}
425
426async fn verify_rrset<H, E>(
432 handle: DnssecDnsHandle<H>,
433 rrset: Rrset,
434 rrsigs: Vec<Record<RRSIG>>,
435 options: DnsRequestOptions,
436) -> Result<Rrset, E>
437where
438 H: DnsHandle<Error = E> + Sync + Unpin,
439 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
440{
441 match rrset.record_type {
442 RecordType::DNSKEY => verify_dnskey_rrset(handle, rrset, rrsigs, options).await,
443 _ => verify_default_rrset(&handle.clone_with_context(), rrset, rrsigs, options).await,
444 }
445}
446
447async fn verify_dnskey_rrset<H, E>(
453 handle: DnssecDnsHandle<H>,
454 rrset: Rrset,
455 rrsigs: Vec<Record<RRSIG>>,
456 options: DnsRequestOptions,
457) -> Result<Rrset, E>
458where
459 H: DnsHandle<Error = E> + Sync + Unpin,
460 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
461{
462 trace!(
463 "dnskey validation {}, record_type: {:?}",
464 rrset.name,
465 rrset.record_type
466 );
467
468 {
470 let anchored_keys = rrset
471 .records
472 .iter()
473 .enumerate()
474 .filter(|&(_, rr)| is_dnssec(rr, RecordType::DNSKEY))
475 .filter_map(|(i, rr)| rr.data().map(|rr| (i, rr)))
476 .filter_map(|(i, rr)| DNSKEY::try_borrow(rr).map(|rr| (i, rr)))
477 .filter_map(|(i, rdata)| {
478 if handle
479 .trust_anchor
480 .contains_dnskey_bytes(rdata.public_key())
481 {
482 debug!(
483 "validated dnskey with trust_anchor: {}, {}",
484 rrset.name, rdata
485 );
486
487 Some(i)
488 } else {
489 None
490 }
491 })
492 .collect::<Vec<usize>>();
493
494 for dnskey_index in anchored_keys.iter().copied() {
496 let dnskey_record = &rrset.records[dnskey_index];
497 let Some(RData::DNSSEC(DNSSECRData::DNSKEY(dnskey))) = dnskey_record.data() else {
498 continue;
499 };
500 for rrsig_record in rrsigs.iter() {
501 let Some(rrsig) = rrsig_record.data() else {
502 continue;
503 };
504 let verify_result = verify_rrset_with_dnskey(&rrset.name, dnskey, rrsig, &rrset);
505 if verify_result.is_ok() {
506 return Ok(rrset);
507 }
508 }
509 }
510
511 if anchored_keys.len() == rrset.records.len() {
512 return Ok(rrset);
515 }
516 }
517
518 let ds_message = handle
520 .lookup(Query::query(rrset.name.clone(), RecordType::DS), options)
521 .first_answer()
522 .await?;
523 let valid_keys = rrset
524 .records
525 .iter()
526 .enumerate()
527 .filter(|&(_, rr)| is_dnssec(rr, RecordType::DNSKEY))
528 .filter_map(|(i, rr)| {
529 if let Some(RData::DNSSEC(DNSSECRData::DNSKEY(ref rdata))) = rr.data() {
530 Some((i, rdata))
531 } else {
532 None
533 }
534 })
535 .filter(|&(_, key_rdata)| {
536 ds_message
537 .answers()
538 .iter()
539 .filter(|ds| is_dnssec(ds, RecordType::DS))
540 .filter_map(|ds| {
541 if let Some(RData::DNSSEC(DNSSECRData::DS(ref ds_rdata))) = ds.data() {
542 Some((ds.name(), ds_rdata))
543 } else {
544 None
545 }
546 })
547 .any(|(ds_name, ds_rdata)| {
549 if ds_rdata.covers(&rrset.name, key_rdata).unwrap_or(false) {
550 debug!(
551 "validated dnskey ({}, {}) with {} {}",
552 rrset.name, key_rdata, ds_name, ds_rdata
553 );
554
555 true
556 } else {
557 false
558 }
559 })
560 })
561 .map(|(i, _)| i)
562 .collect::<Vec<usize>>();
563
564 if !valid_keys.is_empty() {
565 trace!("validated dnskey: {}", rrset.name);
566 }
567
568 for dnskey_index in valid_keys {
569 let dnskey_record = &rrset.records[dnskey_index];
570 let Some(RData::DNSSEC(DNSSECRData::DNSKEY(dnskey))) = dnskey_record.data() else {
571 continue;
572 };
573 for rrsig_record in rrsigs.iter() {
574 let Some(rrsig) = rrsig_record.data() else {
575 continue;
576 };
577 let verify_result = verify_rrset_with_dnskey(&rrset.name, dnskey, rrsig, &rrset);
578 if verify_result.is_ok() {
579 return Ok(rrset);
580 }
581 }
582 }
583
584 Err(E::from(ProtoError::from(ProtoErrorKind::Message(
585 "Could not validate all DNSKEYs",
586 ))))
587}
588
589#[allow(clippy::blocks_in_conditions)]
595async fn verify_default_rrset<H, E>(
596 handle: &DnssecDnsHandle<H>,
597 rrset: Rrset,
598 rrsigs: Vec<Record<RRSIG>>,
599 options: DnsRequestOptions,
600) -> Result<Rrset, E>
601where
602 H: DnsHandle<Error = E> + Sync + Unpin,
603 E: From<ProtoError> + Error + Clone + Send + Unpin + 'static,
604{
605 let rrset = Arc::new(rrset);
607 trace!(
608 "default validation {}, record_type: {:?}",
609 rrset.name,
610 rrset.record_type
611 );
612
613 let verifications = rrsigs.into_iter()
623 .filter(|rrsig| is_dnssec(rrsig, RecordType::RRSIG))
625 .filter_map(|rrsig|rrsig.into_data())
626 .map(|sig| {
627 let rrset = Arc::clone(&rrset);
628 let handle = handle.clone_with_context();
629
630 handle
631 .lookup(
632 Query::query(sig.signer_name().clone(), RecordType::DNSKEY),
633 options,
634 )
635 .first_answer()
636 .and_then(move |message|
637 future::ready(message
639 .answers()
640 .iter()
641 .filter(|r| is_dnssec(r, RecordType::DNSKEY))
642 .filter_map(|r| r.data().map(|data| (r.name(), data)))
643 .filter_map(|(dnskey_name, data)|
644 DNSKEY::try_borrow(data).map(|data| (dnskey_name, data)))
645 .find(|(dnskey_name, dnskey)|
646 verify_rrset_with_dnskey(dnskey_name, dnskey, &sig, &rrset).is_ok()
647 )
648 .map(|_| ())
649 .ok_or_else(|| E::from(ProtoError::from(ProtoErrorKind::Message("validation failed")))))
650 )
651 })
652 .collect::<Vec<_>>();
653
654 if verifications.is_empty() {
656 return Err(E::from(ProtoError::from(
657 ProtoErrorKind::RrsigsNotPresent {
658 name: rrset.name.clone(),
659 record_type: rrset.record_type,
660 },
661 )));
662 }
663
664 let select = future::select_ok(verifications)
666 .map_ok(move |((), rest)| {
668 drop(rest); Arc::try_unwrap(rrset).expect("unable to unwrap Arc")
670 });
671
672 select.await
673}
674
675#[cfg(feature = "dnssec")]
677fn verify_rrset_with_dnskey(
678 dnskey_name: &Name,
679 dnskey: &DNSKEY,
680 sig: &RRSIG,
681 rrset: &Rrset,
682) -> ProtoResult<()> {
683 if dnskey.revoke() {
684 debug!("revoked");
685 return Err(ProtoErrorKind::Message("revoked").into());
686 } if !dnskey.zone_key() {
688 return Err(ProtoErrorKind::Message("is not a zone key").into());
689 }
690 if dnskey.algorithm() != sig.algorithm() {
691 return Err(ProtoErrorKind::Message("mismatched algorithm").into());
692 }
693
694 dnskey
695 .verify_rrsig(&rrset.name, rrset.record_class, sig, &rrset.records)
696 .map(|r| {
697 debug!(
698 "validated ({}, {:?}) with ({}, {})",
699 rrset.name, rrset.record_type, dnskey_name, dnskey
700 );
701 r
702 })
703 .map_err(Into::into)
704 .map_err(|e| {
705 debug!(
706 "failed validation of ({}, {:?}) with ({}, {})",
707 rrset.name, rrset.record_type, dnskey_name, dnskey
708 );
709 e
710 })
711}
712
713#[cfg(not(feature = "dnssec"))]
715fn verify_rrset_with_dnskey(_: &DNSKEY, _: &RRSIG, _: &Rrset) -> ProtoResult<()> {
716 Err(ProtoErrorKind::Message("openssl or ring feature(s) not enabled").into())
717}
718
719#[allow(clippy::blocks_in_conditions)]
772#[doc(hidden)]
773pub fn verify_nsec(query: &Query, soa_name: &Name, nsecs: &[&Record]) -> bool {
774 if let Some(nsec) = nsecs.iter().find(|nsec| query.name() == nsec.name()) {
781 return nsec
782 .data()
783 .and_then(RData::as_dnssec)
784 .and_then(DNSSECRData::as_nsec)
785 .is_some_and(|rdata| {
786 !rdata.type_bit_maps().contains(&query.query_type())
788 });
789 }
790
791 let verify_nsec_coverage = |name: &Name| -> bool {
792 nsecs.iter().any(|nsec| {
793 name >= nsec.name() && {
795 nsec.data()
796 .and_then(RData::as_dnssec)
797 .and_then(DNSSECRData::as_nsec)
798 .is_some_and(|rdata| {
799 name < rdata.next_domain_name() || rdata.next_domain_name() < nsec.name()
802 })
803 }
804 })
805 };
806
807 if !verify_nsec_coverage(query.name()) {
808 return false;
810 }
811
812 let wildcard = query.name().base_name();
816 let wildcard = if soa_name.zone_of(&wildcard) {
817 wildcard
818 } else {
819 soa_name.clone()
820 };
821
822 if wildcard == *query.name() {
824 true
826 } else {
827 verify_nsec_coverage(&wildcard)
830 }
831}