feat(dns): Use HTTP proxy if configured for Dns over HTTPS/TLS
This commit is contained in:
parent
ef1ca16e4a
commit
15db9358a0
2 changed files with 57 additions and 37 deletions
26
src/dns.rs
26
src/dns.rs
|
@ -10,6 +10,7 @@ use log::warn;
|
|||
use std::future::Future;
|
||||
use std::net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
use url::{Host, Url};
|
||||
|
@ -38,7 +39,7 @@ impl DnsResolver {
|
|||
Ok(addrs)
|
||||
}
|
||||
|
||||
pub fn new_from_urls(resolvers: &[Url], so_mark: Option<u32>) -> anyhow::Result<Self> {
|
||||
pub fn new_from_urls(resolvers: &[Url], proxy: Option<Url>, so_mark: Option<u32>) -> anyhow::Result<Self> {
|
||||
if resolvers.is_empty() {
|
||||
// no dns resolver specified, fall-back to default one
|
||||
let Ok((cfg, mut opts)) = hickory_resolver::system_conf::read_system_conf() else {
|
||||
|
@ -57,7 +58,7 @@ impl DnsResolver {
|
|||
return Ok(Self::TrustDns(AsyncResolver::new(
|
||||
cfg,
|
||||
opts,
|
||||
GenericConnector::new(TokioRuntimeProviderWithSoMark::new(so_mark)),
|
||||
GenericConnector::new(TokioRuntimeProviderWithSoMark::new(proxy, so_mark)),
|
||||
)));
|
||||
};
|
||||
|
||||
|
@ -114,7 +115,7 @@ impl DnsResolver {
|
|||
Ok(Self::TrustDns(AsyncResolver::new(
|
||||
cfg,
|
||||
opts,
|
||||
GenericConnector::new(TokioRuntimeProviderWithSoMark::new(so_mark)),
|
||||
GenericConnector::new(TokioRuntimeProviderWithSoMark::new(proxy, so_mark)),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
@ -122,14 +123,16 @@ impl DnsResolver {
|
|||
#[derive(Clone)]
|
||||
pub struct TokioRuntimeProviderWithSoMark {
|
||||
runtime: TokioRuntimeProvider,
|
||||
proxy: Option<Arc<Url>>,
|
||||
#[cfg(target_os = "linux")]
|
||||
so_mark: Option<u32>,
|
||||
}
|
||||
|
||||
impl TokioRuntimeProviderWithSoMark {
|
||||
fn new(so_mark: Option<u32>) -> Self {
|
||||
fn new(proxy: Option<Url>, so_mark: Option<u32>) -> Self {
|
||||
Self {
|
||||
runtime: TokioRuntimeProvider::default(),
|
||||
proxy: proxy.map(Arc::new),
|
||||
#[cfg(target_os = "linux")]
|
||||
so_mark,
|
||||
}
|
||||
|
@ -154,12 +157,26 @@ impl RuntimeProvider for TokioRuntimeProviderWithSoMark {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
let so_mark = self.so_mark;
|
||||
let proxy = self.proxy.clone();
|
||||
let socket = async move {
|
||||
let host = match server_addr.ip() {
|
||||
IpAddr::V4(addr) => Host::<String>::Ipv4(addr),
|
||||
IpAddr::V6(addr) => Host::<String>::Ipv6(addr),
|
||||
};
|
||||
|
||||
if let Some(proxy) = &proxy {
|
||||
tcp::connect_with_http_proxy(
|
||||
proxy,
|
||||
&host,
|
||||
server_addr.port(),
|
||||
so_mark,
|
||||
Duration::from_secs(10),
|
||||
&DnsResolver::System, // not going to be used as host is directly an ip address
|
||||
)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
|
||||
.map(|s| s.map(AsyncIoTokioAsStd))
|
||||
.await
|
||||
} else {
|
||||
tcp::connect(
|
||||
&host,
|
||||
server_addr.port(),
|
||||
|
@ -170,6 +187,7 @@ impl RuntimeProvider for TokioRuntimeProviderWithSoMark {
|
|||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
|
||||
.map(|s| s.map(AsyncIoTokioAsStd))
|
||||
.await
|
||||
}
|
||||
};
|
||||
|
||||
Box::pin(socket)
|
||||
|
|
48
src/main.rs
48
src/main.rs
|
@ -248,8 +248,9 @@ struct Client {
|
|||
/// Dns resolver to use to lookup ips of domain name. Can be specified multiple time
|
||||
/// Example:
|
||||
/// dns://1.1.1.1 for using udp
|
||||
/// dns+https://1.1.1.1?sni=loudflare-dns.com for using dns over HTTPS
|
||||
/// dns+https://1.1.1.1?sni=cloudflare-dns.com for using dns over HTTPS
|
||||
/// dns+tls://8.8.8.8?sni=dns.google for using dns over TLS
|
||||
/// For Dns over HTTPS/TLS if an HTTP proxy is configured, it will be used also
|
||||
/// To use libc resolver, use
|
||||
/// system://0.0.0.0
|
||||
///
|
||||
|
@ -286,7 +287,7 @@ struct Server {
|
|||
/// Can be specified multiple time
|
||||
/// Example:
|
||||
/// dns://1.1.1.1 for using udp
|
||||
/// dns+https://1.1.1.1?sni=loudflare-dns.com for using dns over HTTPS
|
||||
/// dns+https://1.1.1.1?sni=cloudflare-dns.com for using dns over HTTPS
|
||||
/// dns+tls://8.8.8.8?sni=dns.google for using dns over TLS
|
||||
/// To use libc resolver, use
|
||||
/// system://0.0.0.0
|
||||
|
@ -839,24 +840,7 @@ async fn main() {
|
|||
panic!("http headers file does not exists: {}", path.display());
|
||||
}
|
||||
}
|
||||
let mut client_config = WsClientConfig {
|
||||
remote_addr: TransportAddr::new(
|
||||
TransportScheme::from_str(args.remote_addr.scheme()).unwrap(),
|
||||
args.remote_addr.host().unwrap().to_owned(),
|
||||
args.remote_addr.port_or_known_default().unwrap(),
|
||||
tls,
|
||||
)
|
||||
.unwrap(),
|
||||
socket_so_mark: args.socket_so_mark,
|
||||
http_upgrade_path_prefix,
|
||||
http_upgrade_credentials: args.http_upgrade_credentials,
|
||||
http_headers: args.http_headers.into_iter().filter(|(k, _)| k != HOST).collect(),
|
||||
http_headers_file: args.http_headers_file,
|
||||
http_header_host: host_header,
|
||||
timeout_connect: Duration::from_secs(10),
|
||||
websocket_ping_frequency: args.websocket_ping_frequency_sec.unwrap_or(Duration::from_secs(30)),
|
||||
websocket_mask_frame: args.websocket_mask_frame,
|
||||
http_proxy: if let Some(proxy) = args.http_proxy {
|
||||
let http_proxy = if let Some(proxy) = args.http_proxy {
|
||||
let mut proxy = if proxy.starts_with("http://") {
|
||||
Url::parse(&proxy).expect("Invalid http proxy url")
|
||||
} else {
|
||||
|
@ -874,11 +858,29 @@ async fn main() {
|
|||
Some(proxy)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
};
|
||||
let mut client_config = WsClientConfig {
|
||||
remote_addr: TransportAddr::new(
|
||||
TransportScheme::from_str(args.remote_addr.scheme()).unwrap(),
|
||||
args.remote_addr.host().unwrap().to_owned(),
|
||||
args.remote_addr.port_or_known_default().unwrap(),
|
||||
tls,
|
||||
)
|
||||
.unwrap(),
|
||||
socket_so_mark: args.socket_so_mark,
|
||||
http_upgrade_path_prefix,
|
||||
http_upgrade_credentials: args.http_upgrade_credentials,
|
||||
http_headers: args.http_headers.into_iter().filter(|(k, _)| k != HOST).collect(),
|
||||
http_headers_file: args.http_headers_file,
|
||||
http_header_host: host_header,
|
||||
timeout_connect: Duration::from_secs(10),
|
||||
websocket_ping_frequency: args.websocket_ping_frequency_sec.unwrap_or(Duration::from_secs(30)),
|
||||
websocket_mask_frame: args.websocket_mask_frame,
|
||||
cnx_pool: None,
|
||||
tls_reloader: None,
|
||||
dns_resolver: DnsResolver::new_from_urls(&args.dns_resolver, args.socket_so_mark)
|
||||
dns_resolver: DnsResolver::new_from_urls(&args.dns_resolver, http_proxy.clone(), args.socket_so_mark)
|
||||
.expect("cannot create dns resolver"),
|
||||
http_proxy,
|
||||
};
|
||||
|
||||
let tls_reloader =
|
||||
|
@ -1296,7 +1298,7 @@ async fn main() {
|
|||
timeout_connect: Duration::from_secs(10),
|
||||
websocket_mask_frame: args.websocket_mask_frame,
|
||||
tls: tls_config,
|
||||
dns_resolver: DnsResolver::new_from_urls(&args.dns_resolver, args.socket_so_mark)
|
||||
dns_resolver: DnsResolver::new_from_urls(&args.dns_resolver, None, args.socket_so_mark)
|
||||
.expect("Cannot create DNS resolver"),
|
||||
restriction_config: args.restrict_config,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue