diff --git a/Cargo.lock b/Cargo.lock index 8b983fe..098913d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,9 +71,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" @@ -318,7 +318,7 @@ dependencies = [ "pin-project-lite", "rustls 0.22.4", "rustls-native-certs 0.7.1", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", "serde_derive", @@ -358,9 +358,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.6" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" dependencies = [ "jobserver", "libc", @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" dependencies = [ "clap_builder", "clap_derive", @@ -423,9 +423,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -1102,9 +1102,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -1192,9 +1192,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", @@ -1911,9 +1911,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -2073,7 +2073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "rustls-pki-types", "schannel", "security-framework", @@ -2090,9 +2090,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64 0.22.1", "rustls-pki-types", @@ -2191,18 +2191,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.204" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", @@ -3149,7 +3149,7 @@ dependencies = [ "ppp", "regex", "rustls-native-certs 0.7.1", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "scopeguard", "serde", "serde_regex", diff --git a/Cargo.toml b/Cargo.toml index 5d2af79..b9aed66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ scopeguard = "1.2.0" bb8 = { version = "0.8", features = [] } bytes = { version = "1.7.1", features = [] } -clap = { version = "4.5.13", features = ["derive", "env"] } +clap = { version = "4.5.15", features = ["derive", "env"] } fast-socks5 = { version = "0.9.6", features = [] } fastwebsockets = { version = "0.8.0", features = ["upgrade", "simd", "unstable-split"] } futures-util = { version = "0.3.30" } @@ -23,13 +23,13 @@ ppp = { version = "2.2.0", features = [] } async-channel = { version = "2.3.1", features = [] } # For config file parsing -regex = { version = "1.10.5", default-features = false, features = ["std", "perf"] } +regex = { version = "1.10.6", default-features = false, features = ["std", "perf"] } serde_regex = "1.1.0" serde_yaml = { version = "0.9.34", features = [] } ipnet = { version = "2.9.0", features = ["serde"] } hyper = { version = "1.4.1", features = ["client", "http1", "http2"] } -hyper-util = { version = "0.1.6", features = ["tokio", "server", "server-auto"] } +hyper-util = { version = "0.1.7", features = ["tokio", "server", "server-auto"] } http-body-util = { version = "0.1.2" } jsonwebtoken = { version = "9.3.0", default-features = false } log = "0.4.22" @@ -40,9 +40,9 @@ pin-project = "1" notify = { version = "6.1.1", features = [] } rustls-native-certs = { version = "0.7.1", features = [] } -rustls-pemfile = { version = "2.1.2", features = [] } +rustls-pemfile = { version = "2.1.3", features = [] } x509-parser = "0.16.0" -serde = { version = "1.0.204", features = ["derive"] } +serde = { version = "1.0.205", features = ["derive"] } socket2 = { version = "0.5.7", features = [] } tokio = { version = "1.39.2", features = ["full"] } tokio-stream = { version = "0.1.15", features = ["net"] } diff --git a/src/main.rs b/src/main.rs index bcec0a9..17bcc76 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,8 @@ use crate::tunnel::listeners::{ new_stdio_listener, HttpProxyTunnelListener, Socks5TunnelListener, TcpTunnelListener, UdpTunnelListener, }; use crate::tunnel::server::{TlsServerConfig, WsServer, WsServerConfig}; -use crate::tunnel::{to_host_port, LocalProtocol, RemoteAddr, TransportAddr, TransportScheme}; +use crate::tunnel::transport::{TransportAddr, TransportScheme}; +use crate::tunnel::{to_host_port, LocalProtocol, RemoteAddr}; use anyhow::{anyhow, Context}; use base64::Engine; use clap::Parser; diff --git a/src/protocols/tls/server.rs b/src/protocols/tls/server.rs index 13f627d..ec53883 100644 --- a/src/protocols/tls/server.rs +++ b/src/protocols/tls/server.rs @@ -10,7 +10,7 @@ use tokio_rustls::client::TlsStream; use crate::tunnel::client::WsClientConfig; use crate::tunnel::server::TlsServerConfig; -use crate::tunnel::TransportAddr; +use crate::tunnel::transport::TransportAddr; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime}; use tokio_rustls::rustls::server::WebPkiClientVerifier; diff --git a/src/tunnel/client/client.rs b/src/tunnel/client/client.rs index 54fa375..09ee545 100644 --- a/src/tunnel/client/client.rs +++ b/src/tunnel/client/client.rs @@ -5,8 +5,8 @@ use crate::tunnel::connectors::TunnelConnector; use crate::tunnel::listeners::TunnelListener; use crate::tunnel::tls_reloader::TlsReloader; use crate::tunnel::transport::io::{TunnelReader, TunnelWriter}; -use crate::tunnel::transport::jwt_token_to_tunnel; -use crate::tunnel::{RemoteAddr, TransportScheme}; +use crate::tunnel::transport::{jwt_token_to_tunnel, TransportScheme}; +use crate::tunnel::RemoteAddr; use anyhow::Context; use futures_util::pin_mut; use hyper::header::COOKIE; diff --git a/src/tunnel/client/config.rs b/src/tunnel/client/config.rs index ff3bf11..4d44c21 100644 --- a/src/tunnel/client/config.rs +++ b/src/tunnel/client/config.rs @@ -1,5 +1,5 @@ use crate::protocols::dns::DnsResolver; -use crate::tunnel::TransportAddr; +use crate::tunnel::transport::TransportAddr; use hyper::header::{HeaderName, HeaderValue}; use once_cell::sync::Lazy; use parking_lot::RwLock; @@ -29,17 +29,6 @@ pub struct WsClientConfig { } impl WsClientConfig { - pub const fn websocket_scheme(&self) -> &'static str { - match self.remote_addr.tls().is_some() { - false => "ws", - true => "wss", - } - } - - pub fn websocket_host_url(&self) -> String { - format!("{}:{}", self.remote_addr.host(), self.remote_addr.port()) - } - pub fn tls_server_name(&self) -> ServerName<'static> { static INVALID_DNS_NAME: Lazy = Lazy::new(|| DnsName::try_from("dns-name-invalid.com").unwrap()); diff --git a/src/tunnel/mod.rs b/src/tunnel/mod.rs index 1aec9ec..faa7e9c 100644 --- a/src/tunnel/mod.rs +++ b/src/tunnel/mod.rs @@ -3,14 +3,12 @@ pub mod connectors; pub mod listeners; pub mod server; mod tls_reloader; -mod transport; +pub mod transport; -use crate::TlsClientConfig; use serde::{Deserialize, Serialize}; -use std::fmt::{Debug, Display, Formatter}; +use std::fmt::Debug; use std::net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::path::PathBuf; -use std::str::FromStr; use std::time::Duration; use url::Host; @@ -72,7 +70,7 @@ impl LocalProtocol { } pub const fn is_dynamic_reverse_tunnel(&self) -> bool { - matches!(self, |Self::ReverseSocks5 { .. }| Self::ReverseHttpProxy { .. }) + matches!(self, Self::ReverseSocks5 { .. } | Self::ReverseHttpProxy { .. }) } } @@ -83,160 +81,6 @@ pub struct RemoteAddr { pub port: u16, } -#[derive(Copy, Clone, Debug)] -pub enum TransportScheme { - Ws, - Wss, - Http, - Https, -} - -impl TransportScheme { - pub const fn values() -> &'static [Self] { - &[Self::Ws, Self::Wss, Self::Http, Self::Https] - } - pub const fn to_str(self) -> &'static str { - match self { - Self::Ws => "ws", - Self::Wss => "wss", - Self::Http => "http", - Self::Https => "https", - } - } - - pub fn alpn_protocols(&self) -> Vec> { - match self { - Self::Ws => vec![], - Self::Wss => vec![b"http/1.1".to_vec()], - Self::Http => vec![], - Self::Https => vec![b"h2".to_vec()], - } - } -} -impl FromStr for TransportScheme { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "https" => Ok(Self::Https), - "http" => Ok(Self::Http), - "wss" => Ok(Self::Wss), - "ws" => Ok(Self::Ws), - _ => Err(()), - } - } -} - -impl Display for TransportScheme { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_str(self.to_str()) - } -} - -#[derive(Clone)] -pub enum TransportAddr { - Wss { - tls: TlsClientConfig, - scheme: TransportScheme, - host: Host, - port: u16, - }, - Ws { - scheme: TransportScheme, - host: Host, - port: u16, - }, - Https { - scheme: TransportScheme, - tls: TlsClientConfig, - host: Host, - port: u16, - }, - Http { - scheme: TransportScheme, - host: Host, - port: u16, - }, -} - -impl Debug for TransportAddr { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("{}://{}:{}", self.scheme(), self.host(), self.port())) - } -} - -impl TransportAddr { - pub fn new(scheme: TransportScheme, host: Host, port: u16, tls: Option) -> Option { - match scheme { - TransportScheme::Https => Some(Self::Https { - scheme: TransportScheme::Https, - tls: tls?, - host, - port, - }), - TransportScheme::Http => Some(Self::Http { - scheme: TransportScheme::Http, - host, - port, - }), - TransportScheme::Wss => Some(Self::Wss { - scheme: TransportScheme::Wss, - tls: tls?, - host, - port, - }), - TransportScheme::Ws => Some(Self::Ws { - scheme: TransportScheme::Ws, - host, - port, - }), - } - } - pub const fn is_websocket(&self) -> bool { - matches!(self, Self::Ws { .. } | Self::Wss { .. }) - } - - pub const fn is_http2(&self) -> bool { - matches!(self, Self::Http { .. } | Self::Https { .. }) - } - - pub const fn tls(&self) -> Option<&TlsClientConfig> { - match self { - Self::Wss { tls, .. } => Some(tls), - Self::Https { tls, .. } => Some(tls), - Self::Ws { .. } => None, - Self::Http { .. } => None, - } - } - - pub const fn host(&self) -> &Host { - match self { - Self::Wss { host, .. } => host, - Self::Ws { host, .. } => host, - Self::Https { host, .. } => host, - Self::Http { host, .. } => host, - } - } - - pub const fn port(&self) -> u16 { - match self { - Self::Wss { port, .. } => *port, - Self::Ws { port, .. } => *port, - Self::Https { port, .. } => *port, - Self::Http { port, .. } => *port, - } - } - - pub const fn scheme(&self) -> &TransportScheme { - match self { - Self::Wss { scheme, .. } => scheme, - Self::Ws { scheme, .. } => scheme, - Self::Https { scheme, .. } => scheme, - Self::Http { scheme, .. } => scheme, - } - } -} - pub fn to_host_port(addr: SocketAddr) -> (Host, u16) { match addr.ip() { IpAddr::V4(ip) => (Host::Ipv4(ip), addr.port()), diff --git a/src/tunnel/server/reverse_tunnel.rs b/src/tunnel/server/reverse_tunnel.rs index 0f60ec5..c77eaa2 100644 --- a/src/tunnel/server/reverse_tunnel.rs +++ b/src/tunnel/server/reverse_tunnel.rs @@ -1,6 +1,6 @@ use crate::tunnel::listeners::TunnelListener; use crate::tunnel::RemoteAddr; -use ahash::{HashMap, HashMapExt}; +use ahash::{AHashMap}; use anyhow::anyhow; use futures_util::{pin_mut, StreamExt}; use log::warn; @@ -29,13 +29,13 @@ impl Clone for ReverseTunnelItem { } pub struct ReverseTunnelServer { - servers: Arc>>>, + servers: Arc>>>, } impl ReverseTunnelServer { pub fn new() -> Self { Self { - servers: Arc::new(Mutex::new(HashMap::with_capacity(1))), + servers: Arc::new(Mutex::new(AHashMap::with_capacity(1))), } } diff --git a/src/tunnel/transport/http2.rs b/src/tunnel/transport/http2.rs index c1cc713..8d51e4e 100644 --- a/src/tunnel/transport/http2.rs +++ b/src/tunnel/transport/http2.rs @@ -1,8 +1,8 @@ use super::io::{TunnelRead, TunnelWrite, MAX_PACKET_LENGTH}; use crate::tunnel::client::WsClient; -use crate::tunnel::transport::headers_from_file; use crate::tunnel::transport::jwt::tunnel_to_jwt_token; -use crate::tunnel::{RemoteAddr, TransportScheme}; +use crate::tunnel::transport::{headers_from_file, TransportScheme}; +use crate::tunnel::RemoteAddr; use anyhow::{anyhow, Context}; use bytes::{Bytes, BytesMut}; use http_body_util::{BodyExt, BodyStream, StreamBody}; diff --git a/src/tunnel/transport/mod.rs b/src/tunnel/transport/mod.rs index 059e696..b4f4bec 100644 --- a/src/tunnel/transport/mod.rs +++ b/src/tunnel/transport/mod.rs @@ -9,11 +9,15 @@ use tracing::error; pub mod http2; pub mod io; mod jwt; +mod types; pub mod websocket; + pub use jwt::jwt_token_to_tunnel; pub use jwt::tunnel_to_jwt_token; pub use jwt::JwtTunnelConfig; pub use jwt::JWT_HEADER_PREFIX; +pub use types::TransportAddr; +pub use types::TransportScheme; #[allow(clippy::type_complexity)] #[inline] diff --git a/src/tunnel/transport/types.rs b/src/tunnel/transport/types.rs new file mode 100644 index 0000000..468d4ca --- /dev/null +++ b/src/tunnel/transport/types.rs @@ -0,0 +1,151 @@ +use crate::tunnel::client::TlsClientConfig; +use std::fmt::{Debug, Display, Formatter}; +use std::str::FromStr; +use url::Host; + +#[derive(Copy, Clone, Debug)] +pub enum TransportScheme { + Ws, + Wss, + Http, + Https, +} + +impl TransportScheme { + pub const fn values() -> &'static [Self] { + &[Self::Ws, Self::Wss, Self::Http, Self::Https] + } + pub const fn to_str(self) -> &'static str { + match self { + Self::Ws => "ws", + Self::Wss => "wss", + Self::Http => "http", + Self::Https => "https", + } + } + + pub fn alpn_protocols(&self) -> Vec> { + match self { + Self::Ws => vec![], + Self::Wss => vec![b"http/1.1".to_vec()], + Self::Http => vec![], + Self::Https => vec![b"h2".to_vec()], + } + } +} +impl FromStr for TransportScheme { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "https" => Ok(Self::Https), + "http" => Ok(Self::Http), + "wss" => Ok(Self::Wss), + "ws" => Ok(Self::Ws), + _ => Err(()), + } + } +} + +impl Display for TransportScheme { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(self.to_str()) + } +} + +#[derive(Clone)] +pub enum TransportAddr { + Wss { + tls: TlsClientConfig, + scheme: TransportScheme, + host: Host, + port: u16, + }, + Ws { + scheme: TransportScheme, + host: Host, + port: u16, + }, + Https { + scheme: TransportScheme, + tls: TlsClientConfig, + host: Host, + port: u16, + }, + Http { + scheme: TransportScheme, + host: Host, + port: u16, + }, +} + +impl Debug for TransportAddr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}://{}:{}", self.scheme(), self.host(), self.port())) + } +} + +impl TransportAddr { + pub fn new(scheme: TransportScheme, host: Host, port: u16, tls: Option) -> Option { + match scheme { + TransportScheme::Https => Some(Self::Https { + scheme: TransportScheme::Https, + tls: tls?, + host, + port, + }), + TransportScheme::Http => Some(Self::Http { + scheme: TransportScheme::Http, + host, + port, + }), + TransportScheme::Wss => Some(Self::Wss { + scheme: TransportScheme::Wss, + tls: tls?, + host, + port, + }), + TransportScheme::Ws => Some(Self::Ws { + scheme: TransportScheme::Ws, + host, + port, + }), + } + } + + pub const fn tls(&self) -> Option<&TlsClientConfig> { + match self { + Self::Wss { tls, .. } => Some(tls), + Self::Https { tls, .. } => Some(tls), + Self::Ws { .. } => None, + Self::Http { .. } => None, + } + } + + pub const fn host(&self) -> &Host { + match self { + Self::Wss { host, .. } => host, + Self::Ws { host, .. } => host, + Self::Https { host, .. } => host, + Self::Http { host, .. } => host, + } + } + + pub const fn port(&self) -> u16 { + match self { + Self::Wss { port, .. } => *port, + Self::Ws { port, .. } => *port, + Self::Https { port, .. } => *port, + Self::Http { port, .. } => *port, + } + } + + pub const fn scheme(&self) -> &TransportScheme { + match self { + Self::Wss { scheme, .. } => scheme, + Self::Ws { scheme, .. } => scheme, + Self::Https { scheme, .. } => scheme, + Self::Http { scheme, .. } => scheme, + } + } +}