1#[cfg(feature = "http-proxy")]
2use super::try_http_proxy_connect;
3use super::{try_http2_connect, try_tcp_connect, try_tls_connect};
4#[cfg(feature = "socks5")]
5use super::{try_socks5_connect, try_socks5h_connect};
6use crate::DohResult;
7use bytes::Bytes;
8use h2::client::SendRequest;
9use std::fmt::{Display, Formatter, Result};
10use std::sync::Arc;
11use tokio_rustls::rustls::ClientConfig;
12
13pub enum Host {
14 Direct(String, u16),
15 #[cfg(feature = "socks5")]
16 Socks5(
17 String,
18 u16,
19 Option<(String, String)>,
20 Vec<std::net::SocketAddr>,
21 ),
22 #[cfg(feature = "socks5")]
23 Socks5h(String, u16, Option<(String, String)>, String, u16),
24 #[cfg(feature = "http-proxy")]
25 HttpProxy(String, u16, Option<(String, String)>, String, u16),
26 #[cfg(feature = "http-proxy")]
27 HttpsProxy(
28 String,
29 u16,
30 Option<(String, String)>,
31 String,
32 u16,
33 Arc<ClientConfig>,
34 String,
35 ),
36}
37
38impl Host {
39 pub(super) async fn connect(
40 &mut self,
41 client_config: &Arc<ClientConfig>,
42 domain: &str,
43 ) -> DohResult<SendRequest<Bytes>> {
44 match self {
45 Host::Direct(remote_host, remote_port) => {
46 let tcp_connection = try_tcp_connect(remote_host, *remote_port).await?;
47 let tls_connection = try_tls_connect(tcp_connection, client_config, domain).await?;
48 let http2_connection = try_http2_connect(tls_connection).await?;
49 Ok(http2_connection)
50 }
51 #[cfg(feature = "socks5")]
52 Host::Socks5(proxy_host, proxy_port, credentials, remote_addrs) => {
53 let tcp_connection =
54 try_socks5_connect(proxy_host, *proxy_port, remote_addrs, credentials).await?;
55 let tls_connection = try_tls_connect(tcp_connection, client_config, domain).await?;
56 let http2_connection = try_http2_connect(tls_connection).await?;
57 Ok(http2_connection)
58 }
59 #[cfg(feature = "socks5")]
60 Host::Socks5h(proxy_host, proxy_port, credentials, remote_host, remote_port) => {
61 let tcp_connection = try_socks5h_connect(
62 proxy_host,
63 *proxy_port,
64 remote_host,
65 *remote_port,
66 credentials,
67 )
68 .await?;
69 let tls_connection = try_tls_connect(tcp_connection, client_config, domain).await?;
70 let http2_connection = try_http2_connect(tls_connection).await?;
71 Ok(http2_connection)
72 }
73 #[cfg(feature = "http-proxy")]
74 Host::HttpProxy(proxy_host, proxy_port, credentials, remote_host, remote_port) => {
75 let mut tcp_connection = try_tcp_connect(proxy_host, *proxy_port).await?;
76 try_http_proxy_connect(&mut tcp_connection, remote_host, *remote_port, credentials)
77 .await?;
78 let tls_connection = try_tls_connect(tcp_connection, client_config, domain).await?;
79 let http2_connection = try_http2_connect(tls_connection).await?;
80 Ok(http2_connection)
81 }
82 #[cfg(feature = "http-proxy")]
83 Host::HttpsProxy(
84 proxy_host,
85 proxy_port,
86 credentials,
87 remote_host,
88 remote_port,
89 https_client_config,
90 https_domain,
91 ) => {
92 let tcp_connection = try_tcp_connect(proxy_host, *proxy_port).await?;
93 let mut tls_connection =
94 try_tls_connect(tcp_connection, https_client_config, https_domain).await?;
95 try_http_proxy_connect(&mut tls_connection, remote_host, *remote_port, credentials)
96 .await?;
97 let tls_connection = try_tls_connect(tls_connection, client_config, domain).await?;
98 let http2_connection = try_http2_connect(tls_connection).await?;
99 Ok(http2_connection)
100 }
101 }
102 }
103}
104
105impl Display for Host {
106 fn fmt(&self, f: &mut Formatter) -> Result {
107 match self {
108 Host::Direct(remote_host, remote_port) => write!(f, "{}:{}", remote_host, remote_port),
109 #[cfg(feature = "socks5")]
110 Host::Socks5(proxy_host, proxy_port, _, remote_addrs) => {
111 write!(
112 f,
113 "{}:{} via socks5 {:?}",
114 proxy_host, proxy_port, remote_addrs
115 )
116 }
117 #[cfg(feature = "socks5")]
118 Host::Socks5h(proxy_host, proxy_port, _, remote_host, remote_port) => {
119 write!(
120 f,
121 "{}:{} via socks5h {}:{}",
122 proxy_host, proxy_port, remote_host, remote_port
123 )
124 }
125 #[cfg(feature = "http-proxy")]
126 Host::HttpProxy(proxy_host, proxy_port, _, remote_host, remote_port) => {
127 write!(
128 f,
129 "{}:{} via http {}:{}",
130 proxy_host, proxy_port, remote_host, remote_port
131 )
132 }
133 #[cfg(feature = "http-proxy")]
134 Host::HttpsProxy(proxy_host, proxy_port, _, remote_host, remote_port, _, _) => {
135 write!(
136 f,
137 "{}:{} via https {}:{}",
138 proxy_host, proxy_port, remote_host, remote_port
139 )
140 }
141 }
142 }
143}