Add support for custom dns resolver on server
This commit is contained in:
parent
d1de41646f
commit
d456c67f19
8 changed files with 354 additions and 26 deletions
240
Cargo.lock
generated
240
Cargo.lock
generated
|
@ -349,6 +349,12 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.10"
|
||||
|
@ -369,6 +375,24 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-as-inner"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.41",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fast-socks5"
|
||||
version = "0.9.2"
|
||||
|
@ -535,6 +559,31 @@ version = "0.28.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 0.2.11",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
|
@ -553,6 +602,59 @@ version = "0.4.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hickory-proto"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "091a6fbccf4860009355e3efc52ff4acf37a63489aad7435372d44ceeb6fbbcf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"cfg-if",
|
||||
"data-encoding",
|
||||
"enum-as-inner",
|
||||
"futures-channel",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.11",
|
||||
"idna 0.4.0",
|
||||
"ipnet",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"rustls",
|
||||
"rustls-pemfile 1.0.4",
|
||||
"thiserror",
|
||||
"tinyvec",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hickory-resolver"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35b8f021164e6a984c9030023544c57789c51760065cd510572fedcfb04164e8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"hickory-proto",
|
||||
"ipconfig",
|
||||
"lru-cache",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"resolv-conf",
|
||||
"rustls",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
|
@ -562,6 +664,28 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"match_cfg",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.0.0"
|
||||
|
@ -580,7 +704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -591,7 +715,7 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
|
|||
dependencies = [
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
@ -617,7 +741,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
|
@ -636,7 +760,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http 1.0.0",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"pin-project-lite",
|
||||
|
@ -653,6 +777,16 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
|
@ -663,6 +797,34 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipconfig"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
|
||||
dependencies = [
|
||||
"socket2",
|
||||
"widestring",
|
||||
"windows-sys 0.48.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.10"
|
||||
|
@ -703,6 +865,12 @@ version = "0.2.151"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.11"
|
||||
|
@ -719,6 +887,21 @@ version = "0.4.20"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "lru-cache"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "match_cfg"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
|
@ -914,6 +1097,12 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
|
@ -1006,6 +1195,16 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "resolv-conf"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
|
||||
dependencies = [
|
||||
"hostname",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.7"
|
||||
|
@ -1045,12 +1244,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pemfile",
|
||||
"rustls-pemfile 2.0.0",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.0.0"
|
||||
|
@ -1481,6 +1689,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1620,7 +1829,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"idna 0.5.0",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
|
@ -1734,6 +1943,12 @@ version = "0.2.89"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -1888,6 +2103,16 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wstunnel"
|
||||
version = "8.3.0"
|
||||
|
@ -1903,6 +2128,7 @@ dependencies = [
|
|||
"fast-socks5",
|
||||
"fastwebsockets",
|
||||
"futures-util",
|
||||
"hickory-resolver",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
|
@ -1913,7 +2139,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"pin-project",
|
||||
"rustls-native-certs",
|
||||
"rustls-pemfile",
|
||||
"rustls-pemfile 2.0.0",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
"socket2",
|
||||
|
|
|
@ -17,6 +17,7 @@ clap = { version = "4.4.11", features = ["derive"] }
|
|||
fast-socks5 = { version = "0.9.2", features = [] }
|
||||
fastwebsockets = { version = "0.6.0", features = ["upgrade", "simd", "unstable-split"] }
|
||||
futures-util = { version = "0.3.29" }
|
||||
hickory-resolver = { version = "0.24.0", features = ["tokio", "dns-over-https-rustls", "dns-over-rustls"] }
|
||||
|
||||
hyper = { version = "1.0.1", features = ["client", "http1"] }
|
||||
hyper-util = { version = "0.1.0", features = ["tokio"] }
|
||||
|
|
32
src/dns.rs
Normal file
32
src/dns.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use anyhow::Context;
|
||||
use hickory_resolver::TokioAsyncResolver;
|
||||
use std::net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum DnsResolver {
|
||||
System,
|
||||
TrustDns(TokioAsyncResolver),
|
||||
}
|
||||
|
||||
impl DnsResolver {
|
||||
pub async fn lookup_host(&self, domain: &str, port: u16) -> anyhow::Result<Vec<SocketAddr>> {
|
||||
let addrs: Vec<SocketAddr> = match self {
|
||||
DnsResolver::System => tokio::net::lookup_host(format!("{}:{}", domain, port))
|
||||
.await
|
||||
.with_context(|| format!("cannot resolve domain: {}", domain))?
|
||||
.collect(),
|
||||
DnsResolver::TrustDns(dns_resolver) => dns_resolver
|
||||
.lookup_ip(domain)
|
||||
.await
|
||||
.with_context(|| format!("cannot resolve domain: {}", domain))?
|
||||
.into_iter()
|
||||
.map(|ip| match ip {
|
||||
IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
|
||||
IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
Ok(addrs)
|
||||
}
|
||||
}
|
58
src/main.rs
58
src/main.rs
|
@ -1,3 +1,4 @@
|
|||
mod dns;
|
||||
mod embedded_certificate;
|
||||
mod socks5;
|
||||
mod stdio;
|
||||
|
@ -9,13 +10,14 @@ mod udp;
|
|||
use base64::Engine;
|
||||
use clap::Parser;
|
||||
use futures_util::{stream, TryStreamExt};
|
||||
use hickory_resolver::config::{NameServerConfig, ResolverConfig, ResolverOpts};
|
||||
use hyper::header::HOST;
|
||||
use hyper::http::{HeaderName, HeaderValue};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io::ErrorKind;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
@ -27,6 +29,7 @@ use tokio_rustls::rustls::{Certificate, PrivateKey, ServerName};
|
|||
|
||||
use tracing::{error, info, Level};
|
||||
|
||||
use crate::dns::DnsResolver;
|
||||
use crate::tunnel::to_host_port;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use url::{Host, Url};
|
||||
|
@ -157,6 +160,16 @@ struct Server {
|
|||
#[arg(long, value_name = "DEST:PORT", verbatim_doc_comment)]
|
||||
restrict_to: Option<Vec<String>>,
|
||||
|
||||
/// Dns resolver to use to lookup ips of domain name
|
||||
/// This option is not going to work if you use transparent proxy
|
||||
/// Can be specified multiple time
|
||||
/// Example:
|
||||
/// 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
|
||||
#[arg(long, verbatim_doc_comment)]
|
||||
dns_resolver: Option<Vec<Url>>,
|
||||
|
||||
/// 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.
|
||||
/// The path prefix act as a secret to authenticate clients
|
||||
|
@ -445,6 +458,7 @@ pub struct WsServerConfig {
|
|||
pub timeout_connect: Duration,
|
||||
pub websocket_mask_frame: bool,
|
||||
pub tls: Option<TlsServerConfig>,
|
||||
pub dns_resolver: DnsResolver,
|
||||
}
|
||||
|
||||
impl Debug for WsServerConfig {
|
||||
|
@ -592,7 +606,14 @@ async fn main() {
|
|||
let remote = tunnel.remote.clone();
|
||||
let cfg = client_config.clone();
|
||||
let connect_to_dest = |_| async {
|
||||
tcp::connect(&remote.0, remote.1, cfg.socket_so_mark, cfg.timeout_connect).await
|
||||
tcp::connect(
|
||||
&remote.0,
|
||||
remote.1,
|
||||
cfg.socket_so_mark,
|
||||
cfg.timeout_connect,
|
||||
&DnsResolver::System,
|
||||
)
|
||||
.await
|
||||
};
|
||||
|
||||
if let Err(err) =
|
||||
|
@ -608,8 +629,9 @@ async fn main() {
|
|||
tokio::spawn(async move {
|
||||
let cfg = client_config.clone();
|
||||
let remote = tunnel.remote.clone();
|
||||
let connect_to_dest =
|
||||
|_| async { udp::connect(&remote.0, remote.1, cfg.timeout_connect).await };
|
||||
let connect_to_dest = |_| async {
|
||||
udp::connect(&remote.0, remote.1, cfg.timeout_connect, &DnsResolver::System).await
|
||||
};
|
||||
|
||||
if let Err(err) =
|
||||
tunnel::client::run_reverse_tunnel(client_config, tunnel, connect_to_dest).await
|
||||
|
@ -625,7 +647,9 @@ 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).await }
|
||||
async move {
|
||||
tcp::connect(&remote.0, remote.1, so_mark, timeout, &DnsResolver::System).await
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) =
|
||||
|
@ -770,6 +794,29 @@ async fn main() {
|
|||
None
|
||||
};
|
||||
|
||||
let dns_resolver = match args.dns_resolver {
|
||||
None => DnsResolver::System,
|
||||
Some(resolvers) => {
|
||||
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)),
|
||||
_ => panic!("invalid protocol for dns resolver"),
|
||||
};
|
||||
let sock = match resolver.host().unwrap() {
|
||||
Host::Domain(_) => panic!("Dns resolver must be an ip address"),
|
||||
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();
|
||||
DnsResolver::TrustDns(hickory_resolver::AsyncResolver::tokio(cfg, opts))
|
||||
}
|
||||
};
|
||||
let server_config = WsServerConfig {
|
||||
socket_so_mark: args.socket_so_mark,
|
||||
bind: args.remote_addr.socket_addrs(|| Some(8080)).unwrap()[0],
|
||||
|
@ -779,6 +826,7 @@ async fn main() {
|
|||
timeout_connect: Duration::from_secs(10),
|
||||
websocket_mask_frame: args.websocket_mask_frame,
|
||||
tls: tls_config,
|
||||
dns_resolver,
|
||||
};
|
||||
|
||||
info!(
|
||||
|
|
10
src/tcp.rs
10
src/tcp.rs
|
@ -1,6 +1,7 @@
|
|||
use anyhow::{anyhow, Context};
|
||||
use std::{io, vec};
|
||||
|
||||
use crate::dns::DnsResolver;
|
||||
use base64::Engine;
|
||||
use bytes::BytesMut;
|
||||
use log::warn;
|
||||
|
@ -41,14 +42,15 @@ pub async fn connect(
|
|||
port: u16,
|
||||
so_mark: Option<u32>,
|
||||
connect_timeout: Duration,
|
||||
dns_resolver: &DnsResolver,
|
||||
) -> Result<TcpStream, anyhow::Error> {
|
||||
info!("Opening TCP connection to {}:{}", host, port);
|
||||
|
||||
let socket_addrs: Vec<SocketAddr> = match host {
|
||||
Host::Domain(domain) => tokio::net::lookup_host(format!("{}:{}", domain, port))
|
||||
Host::Domain(domain) => dns_resolver
|
||||
.lookup_host(domain.as_str(), port)
|
||||
.await
|
||||
.with_context(|| format!("cannot resolve domain: {}", domain))?
|
||||
.collect(),
|
||||
.with_context(|| format!("cannot resolve domain: {}", domain))?,
|
||||
Host::Ipv4(ip) => vec![SocketAddr::V4(SocketAddrV4::new(*ip, port))],
|
||||
Host::Ipv6(ip) => vec![SocketAddr::V6(SocketAddrV6::new(*ip, port, 0, 0))],
|
||||
};
|
||||
|
@ -104,7 +106,7 @@ pub async fn connect_with_http_proxy(
|
|||
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).await?;
|
||||
let mut socket = connect(&proxy_host, proxy_port, so_mark, connect_timeout, &DnsResolver::System).await?;
|
||||
info!("Connected to http proxy {}:{}", proxy_host, proxy_port);
|
||||
|
||||
let authorization = if let Some((user, password)) = proxy.password().map(|p| (proxy.username(), p)) {
|
||||
|
|
|
@ -2,6 +2,7 @@ pub mod client;
|
|||
mod io;
|
||||
pub mod server;
|
||||
|
||||
use crate::dns::DnsResolver;
|
||||
use crate::{tcp, tls, LocalProtocol, LocalToRemote, WsClientConfig};
|
||||
use async_trait::async_trait;
|
||||
use bb8::ManageConnection;
|
||||
|
@ -126,7 +127,7 @@ impl ManageConnection for WsClientConfig {
|
|||
let tcp_stream = if let Some(http_proxy) = &self.http_proxy {
|
||||
tcp::connect_with_http_proxy(http_proxy, host, *port, so_mark, timeout).await?
|
||||
} else {
|
||||
tcp::connect(host, *port, so_mark, timeout).await?
|
||||
tcp::connect(host, *port, so_mark, timeout, &DnsResolver::System).await?
|
||||
};
|
||||
|
||||
match &self.tls {
|
||||
|
|
|
@ -67,7 +67,13 @@ async fn from_query(
|
|||
match jwt.claims.p {
|
||||
LocalProtocol::Udp { timeout, .. } => {
|
||||
let host = Host::parse(&jwt.claims.r)?;
|
||||
let cnx = udp::connect(&host, jwt.claims.rp, timeout.unwrap_or(Duration::from_secs(10))).await?;
|
||||
let cnx = udp::connect(
|
||||
&host,
|
||||
jwt.claims.rp,
|
||||
timeout.unwrap_or(Duration::from_secs(10)),
|
||||
&server_config.dns_resolver,
|
||||
)
|
||||
.await?;
|
||||
Ok((
|
||||
LocalProtocol::Udp { timeout: None },
|
||||
host,
|
||||
|
@ -79,9 +85,15 @@ async fn from_query(
|
|||
LocalProtocol::Tcp => {
|
||||
let host = Host::parse(&jwt.claims.r)?;
|
||||
let port = jwt.claims.rp;
|
||||
let (rx, tx) = tcp::connect(&host, port, server_config.socket_so_mark, Duration::from_secs(10))
|
||||
.await?
|
||||
.into_split();
|
||||
let (rx, tx) = tcp::connect(
|
||||
&host,
|
||||
port,
|
||||
server_config.socket_so_mark,
|
||||
Duration::from_secs(10),
|
||||
&server_config.dns_resolver,
|
||||
)
|
||||
.await?
|
||||
.into_split();
|
||||
|
||||
Ok((jwt.claims.p, host, port, Box::pin(rx), Box::pin(tx)))
|
||||
}
|
||||
|
|
16
src/udp.rs
16
src/udp.rs
|
@ -18,6 +18,7 @@ use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
|||
use tokio::net::UdpSocket;
|
||||
use tokio::sync::futures::Notified;
|
||||
|
||||
use crate::dns::DnsResolver;
|
||||
use tokio::sync::Notify;
|
||||
use tokio::time::{timeout, Interval};
|
||||
use tracing::{debug, error, info};
|
||||
|
@ -295,16 +296,21 @@ impl AsyncWrite for MyUdpSocket {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn connect(host: &Host<String>, port: u16, connect_timeout: Duration) -> anyhow::Result<MyUdpSocket> {
|
||||
pub async fn connect(
|
||||
host: &Host<String>,
|
||||
port: u16,
|
||||
connect_timeout: Duration,
|
||||
dns_resolver: &DnsResolver,
|
||||
) -> anyhow::Result<MyUdpSocket> {
|
||||
info!("Opening UDP connection to {}:{}", host, port);
|
||||
|
||||
let socket_addrs: Vec<SocketAddr> = match host {
|
||||
Host::Domain(domain) => timeout(connect_timeout, tokio::net::lookup_host(format!("{}:{}", domain, port)))
|
||||
.await
|
||||
.with_context(|| format!("cannot resolve domain: {}", domain))??
|
||||
.collect(),
|
||||
Host::Ipv4(ip) => vec![SocketAddr::V4(SocketAddrV4::new(*ip, port))],
|
||||
Host::Ipv6(ip) => vec![SocketAddr::V6(SocketAddrV6::new(*ip, port, 0, 0))],
|
||||
Host::Domain(domain) => dns_resolver
|
||||
.lookup_host(domain.as_str(), port)
|
||||
.await
|
||||
.with_context(|| format!("cannot resolve domain: {}", domain))?,
|
||||
};
|
||||
|
||||
let mut cnx = None;
|
||||
|
|
Loading…
Reference in a new issue