hickory_proto/rustls/
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//! DNS over TLS client implementation for Rustls
9
10use std::future::Future;
11use std::io;
12use std::net::SocketAddr;
13use std::pin::Pin;
14use std::sync::Arc;
15
16use futures_util::TryFutureExt;
17use rustls::ClientConfig;
18
19use crate::error::ProtoError;
20use crate::iocompat::AsyncIoStdAsTokio;
21use crate::iocompat::AsyncIoTokioAsStd;
22use crate::rustls::tls_stream::{tls_connect_with_bind_addr, tls_connect_with_future};
23use crate::tcp::{Connect, DnsTcpStream, TcpClientStream};
24use crate::xfer::BufDnsStreamHandle;
25
26/// Type of TlsClientStream used with Rustls
27pub type TlsClientStream<S> =
28    TcpClientStream<AsyncIoTokioAsStd<tokio_rustls::client::TlsStream<AsyncIoStdAsTokio<S>>>>;
29
30/// Creates a new TlsStream to the specified name_server
31///
32/// # Arguments
33///
34/// * `name_server` - IP and Port for the remote DNS resolver
35/// * `bind_addr` - IP and port to connect from
36/// * `dns_name` - The DNS name, Subject Public Key Info (SPKI) name, as associated to a certificate
37#[allow(clippy::type_complexity)]
38pub fn tls_client_connect<S: Connect>(
39    name_server: SocketAddr,
40    dns_name: String,
41    client_config: Arc<ClientConfig>,
42) -> (
43    Pin<Box<dyn Future<Output = Result<TlsClientStream<S>, ProtoError>> + Send + Unpin>>,
44    BufDnsStreamHandle,
45) {
46    tls_client_connect_with_bind_addr(name_server, None, dns_name, client_config)
47}
48
49/// Creates a new TlsStream to the specified name_server connecting from a specific address.
50///
51/// # Arguments
52///
53/// * `name_server` - IP and Port for the remote DNS resolver
54/// * `bind_addr` - IP and port to connect from
55/// * `dns_name` - The DNS name, Subject Public Key Info (SPKI) name, as associated to a certificate
56#[allow(clippy::type_complexity)]
57pub fn tls_client_connect_with_bind_addr<S: Connect>(
58    name_server: SocketAddr,
59    bind_addr: Option<SocketAddr>,
60    dns_name: String,
61    client_config: Arc<ClientConfig>,
62) -> (
63    Pin<Box<dyn Future<Output = Result<TlsClientStream<S>, ProtoError>> + Send + Unpin>>,
64    BufDnsStreamHandle,
65) {
66    let (stream_future, sender) =
67        tls_connect_with_bind_addr(name_server, bind_addr, dns_name, client_config);
68
69    let new_future = Box::pin(
70        stream_future
71            .map_ok(TcpClientStream::from_stream)
72            .map_err(ProtoError::from),
73    );
74
75    (new_future, sender)
76}
77
78/// Creates a new TlsStream to the specified name_server connecting from a specific address.
79///
80/// # Arguments
81///
82/// * `future` - A future producing DnsTcpStream
83/// * `dns_name` - The DNS name, Subject Public Key Info (SPKI) name, as associated to a certificate
84#[allow(clippy::type_complexity)]
85pub fn tls_client_connect_with_future<S, F>(
86    future: F,
87    socket_addr: SocketAddr,
88    dns_name: String,
89    client_config: Arc<ClientConfig>,
90) -> (
91    Pin<Box<dyn Future<Output = Result<TlsClientStream<S>, ProtoError>> + Send + Unpin>>,
92    BufDnsStreamHandle,
93)
94where
95    S: DnsTcpStream,
96    F: Future<Output = io::Result<S>> + Send + Unpin + 'static,
97{
98    let (stream_future, sender) =
99        tls_connect_with_future(future, socket_addr, dns_name, client_config);
100
101    let new_future = Box::pin(
102        stream_future
103            .map_ok(TcpClientStream::from_stream)
104            .map_err(ProtoError::from),
105    );
106
107    (new_future, sender)
108}