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:
Σrebe - Romain GERARD 2024-01-02 19:32:47 +01:00
parent 5ae552f713
commit b705484d9f
No known key found for this signature in database
GPG key ID: 7A42B4B97E0332F4
5 changed files with 59 additions and 35 deletions

View file

@ -150,6 +150,8 @@ Options:
dns://1.1.1.1 for using udp
dns+https://1.1.1.1 for using dns over HTTPS
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>
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.

View file

@ -10,7 +10,7 @@ make_release $VERSION $FORCE="":
git add Cargo.*
git commit -m 'Bump version v'$VERSION
git tag $FORCE v$VERSION -m 'version v'$VERSION
git push
git push $FORCE
git push $FORCE origin v$VERSION
@just docker_release v$VERSION

View file

@ -13,6 +13,7 @@ use futures_util::{stream, TryStreamExt};
use hickory_resolver::config::{NameServerConfig, ResolverConfig, ResolverOpts};
use hyper::header::HOST;
use hyper::http::{HeaderName, HeaderValue};
use log::{debug, warn};
use parking_lot::Mutex;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
@ -202,6 +203,8 @@ struct Server {
/// dns://1.1.1.1 for using udp
/// dns+https://1.1.1.1 for using dns over HTTPS
/// 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)]
dns_resolver: Option<Vec<Url>>,
@ -519,7 +522,7 @@ impl Debug for WsServerConfig {
}
}
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct WsClientConfig {
pub remote_addr: (Host<String>, u16),
pub socket_so_mark: Option<u32>,
@ -533,6 +536,7 @@ pub struct WsClientConfig {
pub websocket_mask_frame: bool,
pub http_proxy: Option<Url>,
cnx_pool: Option<bb8::Pool<WsClientConfig>>,
pub dns_resolver: DnsResolver,
}
impl WsClientConfig {
@ -626,6 +630,12 @@ async fn main() {
websocket_mask_frame: args.websocket_mask_frame,
http_proxy: args.http_proxy,
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()
@ -654,7 +664,7 @@ async fn main() {
remote.1,
cfg.socket_so_mark,
cfg.timeout_connect,
&DnsResolver::System,
&cfg.dns_resolver,
)
.await
};
@ -673,7 +683,7 @@ async fn main() {
let cfg = client_config.clone();
let remote = tunnel.remote.clone();
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) =
@ -690,9 +700,8 @@ async fn main() {
let connect_to_dest = |remote: (Host, u16)| {
let so_mark = cfg.socket_so_mark;
let timeout = cfg.timeout_connect;
async move {
tcp::connect(&remote.0, remote.1, so_mark, timeout, &DnsResolver::System).await
}
let dns_resolver = &cfg.dns_resolver;
async move { tcp::connect(&remote.0, remote.1, so_mark, timeout, dns_resolver).await }
};
if let Err(err) =
@ -841,14 +850,26 @@ async fn main() {
};
let dns_resolver = match args.dns_resolver {
None => DnsResolver::System,
None => {
if let Ok(resolver) = hickory_resolver::AsyncResolver::tokio_from_system_conf() {
DnsResolver::TrustDns(resolver)
} else {
warn!("Fall-backing to system dns resolver. You should consider specifying a dns resolver. To avoid performance issue");
DnsResolver::System
}
}
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(853)),
"dns+tls" => (hickory_resolver::config::Protocol::Tls, resolver.port().unwrap_or(12)),
"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() {
@ -868,6 +889,7 @@ async fn main() {
let opts = ResolverOpts::default();
DnsResolver::TrustDns(hickory_resolver::AsyncResolver::tokio(cfg, opts))
}
}
};
let server_config = WsServerConfig {
socket_so_mark: args.socket_so_mark,

View file

@ -102,11 +102,12 @@ pub async fn connect_with_http_proxy(
port: u16,
so_mark: Option<u32>,
connect_timeout: Duration,
dns_resolver: &DnsResolver,
) -> Result<TcpStream, anyhow::Error> {
let proxy_host = proxy.host().context("Cannot parse proxy host")?.to_owned();
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);
let authorization = if let Some((user, password)) = proxy.password().map(|p| (proxy.username(), p)) {

View file

@ -3,7 +3,6 @@ mod io;
pub mod server;
mod tls_reloader;
use crate::dns::DnsResolver;
use crate::{tcp, tls, LocalProtocol, LocalToRemote, WsClientConfig};
use async_trait::async_trait;
use bb8::ManageConnection;
@ -127,9 +126,9 @@ impl ManageConnection for WsClientConfig {
let timeout = self.timeout_connect;
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 {
tcp::connect(host, *port, so_mark, timeout, &DnsResolver::System).await?
tcp::connect(host, *port, so_mark, timeout, &self.dns_resolver).await?
};
match &self.tls {