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