hickory_proto/native_tls/
tls_client_stream.rs

1// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! TlsClientStream for DNS over TLS
9
10use std::future::Future;
11use std::net::SocketAddr;
12use std::pin::Pin;
13
14use futures_util::TryFutureExt;
15use native_tls::Certificate;
16use tokio_native_tls::TlsStream as TokioTlsStream;
17
18use crate::error::ProtoError;
19use crate::iocompat::AsyncIoStdAsTokio;
20use crate::iocompat::AsyncIoTokioAsStd;
21use crate::native_tls::TlsStreamBuilder;
22use crate::tcp::{Connect, DnsTcpStream, TcpClientStream};
23use crate::xfer::BufDnsStreamHandle;
24
25/// TlsClientStream secure DNS over TCP stream
26///
27/// See TlsClientStreamBuilder::new()
28pub type TlsClientStream<S> =
29    TcpClientStream<AsyncIoTokioAsStd<TokioTlsStream<AsyncIoStdAsTokio<S>>>>;
30
31/// Builder for TlsClientStream
32pub struct TlsClientStreamBuilder<S>(TlsStreamBuilder<S>);
33
34impl<S: DnsTcpStream> TlsClientStreamBuilder<S> {
35    /// Creates a builder fo the construction of a TlsClientStream
36    pub fn new() -> Self {
37        Self(TlsStreamBuilder::new())
38    }
39
40    /// Add a custom trusted peer certificate or certificate authority.
41    ///
42    /// If this is the 'client' then the 'server' must have it associated as it's `identity`, or have had the `identity` signed by this certificate.
43    pub fn add_ca(&mut self, ca: Certificate) {
44        self.0.add_ca(ca);
45    }
46
47    /// Sets the address to connect from.
48    pub fn bind_addr(&mut self, bind_addr: SocketAddr) {
49        self.0.bind_addr(bind_addr);
50    }
51
52    /// Creates a new TlsStream to the specified name_server with stream future.
53    ///
54    /// # Arguments
55    ///
56    /// * 'future` - future of TCP stream
57    /// * `name_server` - IP and Port for the remote DNS resolver
58    /// * `dns_name` - The DNS name, Subject Public Key Info (SPKI) name, as associated to a certificate
59    #[allow(clippy::type_complexity)]
60    pub fn build_with_future<F>(
61        self,
62        future: F,
63        name_server: SocketAddr,
64        dns_name: String,
65    ) -> (
66        Pin<Box<dyn Future<Output = Result<TlsClientStream<S>, ProtoError>> + Send>>,
67        BufDnsStreamHandle,
68    )
69    where
70        F: Future<Output = std::io::Result<S>> + Send + Unpin + 'static,
71    {
72        let (stream_future, sender) = self.0.build_with_future(future, name_server, dns_name);
73
74        let new_future = Box::pin(
75            stream_future
76                .map_ok(TcpClientStream::from_stream)
77                .map_err(ProtoError::from),
78        );
79
80        (new_future, sender)
81    }
82}
83
84impl<S: Connect> TlsClientStreamBuilder<S> {
85    /// Creates a new TlsStream to the specified name_server
86    ///
87    /// # Arguments
88    ///
89    /// * `name_server` - IP and Port for the remote DNS resolver
90    /// * `dns_name` - The DNS name, Subject Public Key Info (SPKI) name, as associated to a certificate
91    #[allow(clippy::type_complexity)]
92    pub fn build(
93        self,
94        name_server: SocketAddr,
95        dns_name: String,
96    ) -> (
97        Pin<Box<dyn Future<Output = Result<TlsClientStream<S>, ProtoError>> + Send>>,
98        BufDnsStreamHandle,
99    ) {
100        let (stream_future, sender) = self.0.build(name_server, dns_name);
101
102        let new_future = Box::pin(
103            stream_future
104                .map_ok(TcpClientStream::from_stream)
105                .map_err(ProtoError::from),
106        );
107
108        (new_future, sender)
109    }
110}
111
112impl<S: DnsTcpStream> Default for TlsClientStreamBuilder<S> {
113    fn default() -> Self {
114        Self::new()
115    }
116}