Dont use libc dns resolver by default
+ By default libc dns resolution is blocking. Which force async runtime to spawn blocking thread for it which lead to heavy memory usage
This commit is contained in:
parent
5ae552f713
commit
b705484d9f
5 changed files with 59 additions and 35 deletions
|
@ -150,6 +150,8 @@ Options:
|
||||||
dns://1.1.1.1 for using udp
|
dns://1.1.1.1 for using udp
|
||||||
dns+https://1.1.1.1 for using dns over HTTPS
|
dns+https://1.1.1.1 for using dns over HTTPS
|
||||||
dns+tls://8.8.8.8 for using dns over TLS
|
dns+tls://8.8.8.8 for using dns over TLS
|
||||||
|
To use libc resolver, use
|
||||||
|
system://0.0.0.0
|
||||||
-r, --restrict-http-upgrade-path-prefix <RESTRICT_HTTP_UPGRADE_PATH_PREFIX>
|
-r, --restrict-http-upgrade-path-prefix <RESTRICT_HTTP_UPGRADE_PATH_PREFIX>
|
||||||
Server will only accept connection from if this specific path prefix is used during websocket upgrade.
|
Server will only accept connection from if this specific path prefix is used during websocket upgrade.
|
||||||
Useful if you specify in the client a custom path prefix and you want the server to only allow this one.
|
Useful if you specify in the client a custom path prefix and you want the server to only allow this one.
|
||||||
|
|
2
justfile
2
justfile
|
@ -10,7 +10,7 @@ make_release $VERSION $FORCE="":
|
||||||
git add Cargo.*
|
git add Cargo.*
|
||||||
git commit -m 'Bump version v'$VERSION
|
git commit -m 'Bump version v'$VERSION
|
||||||
git tag $FORCE v$VERSION -m 'version v'$VERSION
|
git tag $FORCE v$VERSION -m 'version v'$VERSION
|
||||||
git push
|
git push $FORCE
|
||||||
git push $FORCE origin v$VERSION
|
git push $FORCE origin v$VERSION
|
||||||
@just docker_release v$VERSION
|
@just docker_release v$VERSION
|
||||||
|
|
||||||
|
|
82
src/main.rs
82
src/main.rs
|
@ -13,6 +13,7 @@ use futures_util::{stream, TryStreamExt};
|
||||||
use hickory_resolver::config::{NameServerConfig, ResolverConfig, ResolverOpts};
|
use hickory_resolver::config::{NameServerConfig, ResolverConfig, ResolverOpts};
|
||||||
use hyper::header::HOST;
|
use hyper::header::HOST;
|
||||||
use hyper::http::{HeaderName, HeaderValue};
|
use hyper::http::{HeaderName, HeaderValue};
|
||||||
|
use log::{debug, warn};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
@ -202,6 +203,8 @@ struct Server {
|
||||||
/// dns://1.1.1.1 for using udp
|
/// dns://1.1.1.1 for using udp
|
||||||
/// dns+https://1.1.1.1 for using dns over HTTPS
|
/// dns+https://1.1.1.1 for using dns over HTTPS
|
||||||
/// dns+tls://8.8.8.8 for using dns over TLS
|
/// dns+tls://8.8.8.8 for using dns over TLS
|
||||||
|
/// To use libc resolver, use
|
||||||
|
/// system://0.0.0.0
|
||||||
#[arg(long, verbatim_doc_comment)]
|
#[arg(long, verbatim_doc_comment)]
|
||||||
dns_resolver: Option<Vec<Url>>,
|
dns_resolver: Option<Vec<Url>>,
|
||||||
|
|
||||||
|
@ -519,7 +522,7 @@ impl Debug for WsServerConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct WsClientConfig {
|
pub struct WsClientConfig {
|
||||||
pub remote_addr: (Host<String>, u16),
|
pub remote_addr: (Host<String>, u16),
|
||||||
pub socket_so_mark: Option<u32>,
|
pub socket_so_mark: Option<u32>,
|
||||||
|
@ -533,6 +536,7 @@ pub struct WsClientConfig {
|
||||||
pub websocket_mask_frame: bool,
|
pub websocket_mask_frame: bool,
|
||||||
pub http_proxy: Option<Url>,
|
pub http_proxy: Option<Url>,
|
||||||
cnx_pool: Option<bb8::Pool<WsClientConfig>>,
|
cnx_pool: Option<bb8::Pool<WsClientConfig>>,
|
||||||
|
pub dns_resolver: DnsResolver,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsClientConfig {
|
impl WsClientConfig {
|
||||||
|
@ -626,6 +630,12 @@ async fn main() {
|
||||||
websocket_mask_frame: args.websocket_mask_frame,
|
websocket_mask_frame: args.websocket_mask_frame,
|
||||||
http_proxy: args.http_proxy,
|
http_proxy: args.http_proxy,
|
||||||
cnx_pool: None,
|
cnx_pool: None,
|
||||||
|
dns_resolver: if let Ok(resolver) = hickory_resolver::AsyncResolver::tokio_from_system_conf() {
|
||||||
|
DnsResolver::TrustDns(resolver)
|
||||||
|
} else {
|
||||||
|
debug!("Fall-backing to system dns resolver");
|
||||||
|
DnsResolver::System
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let pool = bb8::Pool::builder()
|
let pool = bb8::Pool::builder()
|
||||||
|
@ -654,7 +664,7 @@ async fn main() {
|
||||||
remote.1,
|
remote.1,
|
||||||
cfg.socket_so_mark,
|
cfg.socket_so_mark,
|
||||||
cfg.timeout_connect,
|
cfg.timeout_connect,
|
||||||
&DnsResolver::System,
|
&cfg.dns_resolver,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
|
@ -673,7 +683,7 @@ async fn main() {
|
||||||
let cfg = client_config.clone();
|
let cfg = client_config.clone();
|
||||||
let remote = tunnel.remote.clone();
|
let remote = tunnel.remote.clone();
|
||||||
let connect_to_dest = |_| async {
|
let connect_to_dest = |_| async {
|
||||||
udp::connect(&remote.0, remote.1, cfg.timeout_connect, &DnsResolver::System).await
|
udp::connect(&remote.0, remote.1, cfg.timeout_connect, &cfg.dns_resolver).await
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
|
@ -690,9 +700,8 @@ async fn main() {
|
||||||
let connect_to_dest = |remote: (Host, u16)| {
|
let connect_to_dest = |remote: (Host, u16)| {
|
||||||
let so_mark = cfg.socket_so_mark;
|
let so_mark = cfg.socket_so_mark;
|
||||||
let timeout = cfg.timeout_connect;
|
let timeout = cfg.timeout_connect;
|
||||||
async move {
|
let dns_resolver = &cfg.dns_resolver;
|
||||||
tcp::connect(&remote.0, remote.1, so_mark, timeout, &DnsResolver::System).await
|
async move { tcp::connect(&remote.0, remote.1, so_mark, timeout, dns_resolver).await }
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
|
@ -841,32 +850,45 @@ async fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let dns_resolver = match args.dns_resolver {
|
let dns_resolver = match args.dns_resolver {
|
||||||
None => DnsResolver::System,
|
None => {
|
||||||
Some(resolvers) => {
|
if let Ok(resolver) = hickory_resolver::AsyncResolver::tokio_from_system_conf() {
|
||||||
let mut cfg = ResolverConfig::new();
|
DnsResolver::TrustDns(resolver)
|
||||||
for resolver in resolvers {
|
} else {
|
||||||
let (protocol, port) = match resolver.scheme() {
|
warn!("Fall-backing to system dns resolver. You should consider specifying a dns resolver. To avoid performance issue");
|
||||||
"dns" => (hickory_resolver::config::Protocol::Udp, resolver.port().unwrap_or(53)),
|
DnsResolver::System
|
||||||
"dns+https" => (hickory_resolver::config::Protocol::Https, resolver.port().unwrap_or(853)),
|
|
||||||
"dns+tls" => (hickory_resolver::config::Protocol::Tls, resolver.port().unwrap_or(12)),
|
|
||||||
_ => panic!("invalid protocol for dns resolver"),
|
|
||||||
};
|
|
||||||
let sock = match resolver.host().unwrap() {
|
|
||||||
Host::Domain(host) => match Host::parse(host) {
|
|
||||||
Ok(Host::Ipv4(ip)) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
|
|
||||||
Ok(Host::Ipv6(ip)) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
|
|
||||||
Ok(Host::Domain(_)) | Err(_) => {
|
|
||||||
panic!("Dns resolver must be an ip address, got {}", host)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Host::Ipv4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
|
|
||||||
Host::Ipv6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
|
|
||||||
};
|
|
||||||
cfg.add_name_server(NameServerConfig::new(sock, protocol))
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Some(resolvers) => {
|
||||||
|
if resolvers.iter().any(|r| r.scheme() == "system") {
|
||||||
|
DnsResolver::System
|
||||||
|
} else {
|
||||||
|
let mut cfg = ResolverConfig::new();
|
||||||
|
for resolver in resolvers {
|
||||||
|
let (protocol, port) = match resolver.scheme() {
|
||||||
|
"dns" => (hickory_resolver::config::Protocol::Udp, resolver.port().unwrap_or(53)),
|
||||||
|
"dns+https" => {
|
||||||
|
(hickory_resolver::config::Protocol::Https, resolver.port().unwrap_or(443))
|
||||||
|
}
|
||||||
|
"dns+tls" => (hickory_resolver::config::Protocol::Tls, resolver.port().unwrap_or(853)),
|
||||||
|
_ => panic!("invalid protocol for dns resolver"),
|
||||||
|
};
|
||||||
|
let sock = match resolver.host().unwrap() {
|
||||||
|
Host::Domain(host) => match Host::parse(host) {
|
||||||
|
Ok(Host::Ipv4(ip)) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
|
||||||
|
Ok(Host::Ipv6(ip)) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
|
||||||
|
Ok(Host::Domain(_)) | Err(_) => {
|
||||||
|
panic!("Dns resolver must be an ip address, got {}", host)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Host::Ipv4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
|
||||||
|
Host::Ipv6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
|
||||||
|
};
|
||||||
|
cfg.add_name_server(NameServerConfig::new(sock, protocol))
|
||||||
|
}
|
||||||
|
|
||||||
let opts = ResolverOpts::default();
|
let opts = ResolverOpts::default();
|
||||||
DnsResolver::TrustDns(hickory_resolver::AsyncResolver::tokio(cfg, opts))
|
DnsResolver::TrustDns(hickory_resolver::AsyncResolver::tokio(cfg, opts))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let server_config = WsServerConfig {
|
let server_config = WsServerConfig {
|
||||||
|
|
|
@ -102,11 +102,12 @@ pub async fn connect_with_http_proxy(
|
||||||
port: u16,
|
port: u16,
|
||||||
so_mark: Option<u32>,
|
so_mark: Option<u32>,
|
||||||
connect_timeout: Duration,
|
connect_timeout: Duration,
|
||||||
|
dns_resolver: &DnsResolver,
|
||||||
) -> Result<TcpStream, anyhow::Error> {
|
) -> Result<TcpStream, anyhow::Error> {
|
||||||
let proxy_host = proxy.host().context("Cannot parse proxy host")?.to_owned();
|
let proxy_host = proxy.host().context("Cannot parse proxy host")?.to_owned();
|
||||||
let proxy_port = proxy.port_or_known_default().unwrap_or(80);
|
let proxy_port = proxy.port_or_known_default().unwrap_or(80);
|
||||||
|
|
||||||
let mut socket = connect(&proxy_host, proxy_port, so_mark, connect_timeout, &DnsResolver::System).await?;
|
let mut socket = connect(&proxy_host, proxy_port, so_mark, connect_timeout, dns_resolver).await?;
|
||||||
info!("Connected to http proxy {}:{}", proxy_host, proxy_port);
|
info!("Connected to http proxy {}:{}", proxy_host, proxy_port);
|
||||||
|
|
||||||
let authorization = if let Some((user, password)) = proxy.password().map(|p| (proxy.username(), p)) {
|
let authorization = if let Some((user, password)) = proxy.password().map(|p| (proxy.username(), p)) {
|
||||||
|
|
|
@ -3,7 +3,6 @@ mod io;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
mod tls_reloader;
|
mod tls_reloader;
|
||||||
|
|
||||||
use crate::dns::DnsResolver;
|
|
||||||
use crate::{tcp, tls, LocalProtocol, LocalToRemote, WsClientConfig};
|
use crate::{tcp, tls, LocalProtocol, LocalToRemote, WsClientConfig};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bb8::ManageConnection;
|
use bb8::ManageConnection;
|
||||||
|
@ -127,9 +126,9 @@ impl ManageConnection for WsClientConfig {
|
||||||
let timeout = self.timeout_connect;
|
let timeout = self.timeout_connect;
|
||||||
|
|
||||||
let tcp_stream = if let Some(http_proxy) = &self.http_proxy {
|
let tcp_stream = if let Some(http_proxy) = &self.http_proxy {
|
||||||
tcp::connect_with_http_proxy(http_proxy, host, *port, so_mark, timeout).await?
|
tcp::connect_with_http_proxy(http_proxy, host, *port, so_mark, timeout, &self.dns_resolver).await?
|
||||||
} else {
|
} else {
|
||||||
tcp::connect(host, *port, so_mark, timeout, &DnsResolver::System).await?
|
tcp::connect(host, *port, so_mark, timeout, &self.dns_resolver).await?
|
||||||
};
|
};
|
||||||
|
|
||||||
match &self.tls {
|
match &self.tls {
|
||||||
|
|
Loading…
Reference in a new issue