trust_dns_client/client/
async_secure_client.rs

1// Copyright 2015-2019 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7#![cfg(feature = "dnssec")]
8
9use std::future::Future;
10use std::pin::Pin;
11
12use futures_util::stream::Stream;
13
14use crate::client::AsyncClient;
15use crate::proto::error::ProtoError;
16use crate::proto::rr::dnssec::TrustAnchor;
17use crate::proto::xfer::{
18    DnsExchangeBackground, DnsHandle, DnsRequest, DnsRequestSender, DnsResponse,
19};
20use crate::proto::DnssecDnsHandle;
21use crate::proto::TokioTime;
22
23/// A DNSSEC Client implemented over futures-rs.
24///
25/// This Client is generic and capable of wrapping UDP, TCP, and other underlying DNS protocol
26///  implementations.
27pub struct AsyncDnssecClient {
28    client: DnssecDnsHandle<AsyncClient>,
29}
30
31impl AsyncDnssecClient {
32    /// Returns a DNSSEC verifying client with a TrustAnchor that can be replaced
33    pub fn builder<F, S>(connect_future: F) -> AsyncSecureClientBuilder<F, S>
34    where
35        F: Future<Output = Result<S, ProtoError>> + 'static + Send + Unpin,
36        S: DnsRequestSender + 'static,
37    {
38        AsyncSecureClientBuilder {
39            connect_future,
40            trust_anchor: None,
41        }
42    }
43
44    /// Returns a DNSSEC verifying client with the default TrustAnchor
45    pub async fn connect<F, S>(
46        connect_future: F,
47    ) -> Result<(Self, DnsExchangeBackground<S, TokioTime>), ProtoError>
48    where
49        S: DnsRequestSender,
50        F: Future<Output = Result<S, ProtoError>> + 'static + Send + Unpin,
51    {
52        Self::builder(connect_future).build().await
53    }
54
55    fn from_client(client: AsyncClient, trust_anchor: TrustAnchor) -> Self {
56        Self {
57            client: DnssecDnsHandle::with_trust_anchor(client, trust_anchor),
58        }
59    }
60}
61
62impl Clone for AsyncDnssecClient {
63    fn clone(&self) -> Self {
64        Self {
65            client: self.client.clone(),
66        }
67    }
68}
69
70impl DnsHandle for AsyncDnssecClient {
71    type Response = Pin<Box<(dyn Stream<Item = Result<DnsResponse, ProtoError>> + Send + 'static)>>;
72    type Error = ProtoError;
73
74    fn send<R: Into<DnsRequest> + Unpin + Send + 'static>(&mut self, request: R) -> Self::Response {
75        self.client.send(request)
76    }
77}
78
79/// A builder to allow a custom trust to be used for validating all signed records
80#[cfg(feature = "dnssec")]
81#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
82pub struct AsyncSecureClientBuilder<F, S>
83where
84    F: Future<Output = Result<S, ProtoError>> + 'static + Send + Unpin,
85    S: DnsRequestSender + 'static,
86{
87    connect_future: F,
88    trust_anchor: Option<TrustAnchor>,
89}
90
91#[cfg(feature = "dnssec")]
92impl<F, S> AsyncSecureClientBuilder<F, S>
93where
94    F: Future<Output = Result<S, ProtoError>> + 'static + Send + Unpin,
95    S: DnsRequestSender + 'static,
96{
97    /// This variant allows for the trust_anchor to be replaced
98    ///
99    /// # Arguments
100    ///
101    /// * `trust_anchor` - the set of trusted DNSKEY public_keys, by default this only contains the
102    ///                    root public_key.
103    pub fn trust_anchor(mut self, trust_anchor: TrustAnchor) -> Self {
104        self.trust_anchor = Some(trust_anchor);
105        self
106    }
107
108    /// Construct the new client
109    pub async fn build(
110        mut self,
111    ) -> Result<(AsyncDnssecClient, DnsExchangeBackground<S, TokioTime>), ProtoError> {
112        let trust_anchor = if let Some(trust_anchor) = self.trust_anchor.take() {
113            trust_anchor
114        } else {
115            TrustAnchor::default()
116        };
117        let result = AsyncClient::connect(self.connect_future).await;
118
119        result.map(|(client, bg)| (AsyncDnssecClient::from_client(client, trust_anchor), bg))
120    }
121}