diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b79b6e0..a6cf3d7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -44,40 +44,40 @@ jobs: FEATURES: default - TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac OS: ubuntu-latest - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container OS: ubuntu-latest - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested OS: ubuntu-latest - FEATURES: openssl-vendored + FEATURES: ring-cipher,wss - TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested OS: ubuntu-latest - FEATURES: openssl-vendored + FEATURES: ring-cipher,wss - TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested OS: ubuntu-latest - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested OS: ubuntu-latest - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings OS: macos-latest - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings OS: macos-latest - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: i686-pc-windows-msvc # tested on a windows machine OS: windows-2019 - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: x86_64-pc-windows-msvc # tested on a windows machine OS: windows-latest - FEATURES: ring-cipher,openssl-vendored + FEATURES: ring-cipher,wss - TARGET: mipsel-unknown-linux-musl # openwrt OS: ubuntu-latest - FEATURES: openssl-vendored,ring-cipher + FEATURES: ring-cipher,wss - TARGET: mips-unknown-linux-musl # openwrt OS: ubuntu-latest - FEATURES: openssl-vendored + FEATURES: ring-cipher,wss # needs: test runs-on: ${{ matrix.OS }} env: diff --git a/Cargo.lock b/Cargo.lock index 7d52d24..1d63b81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,6 +121,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -336,6 +342,16 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -982,22 +998,10 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "mio" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4929e1f84c5e54c3ec6141cd5d8b5a5c055f031f80cf78f2072920173cb4d880" -dependencies = [ - "hermit-abi", "libc", "log", "wasi", - "windows-sys 0.52.0", + "windows-sys 0.48.0", ] [[package]] @@ -1099,6 +1103,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "openssl-src" version = "300.1.3+3.1.2" @@ -1262,9 +1272,9 @@ dependencies = [ [[package]] name = "protobuf" -version = "3.4.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58678a64de2fced2bdec6bca052a6716a0efe692d6e3f53d1bda6a1def64cfc0" +checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" dependencies = [ "once_cell", "protobuf-support", @@ -1273,9 +1283,9 @@ dependencies = [ [[package]] name = "protobuf-codegen" -version = "3.4.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32777b0b3f6538d9d2e012b3fad85c7e4b9244b5958d04a6415f4333782b7a77" +checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901" dependencies = [ "anyhow", "once_cell", @@ -1288,9 +1298,9 @@ dependencies = [ [[package]] name = "protobuf-parse" -version = "3.4.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cb37955261126624a25b5e6bda40ae34cf3989d52a783087ca6091b29b5642" +checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -1304,9 +1314,9 @@ dependencies = [ [[package]] name = "protobuf-support" -version = "3.4.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1ed294a835b0f30810e13616b1cd34943c6d1e84a8f3b0dcfe466d256c3e7e7" +checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" dependencies = [ "thiserror", ] @@ -1510,18 +1520,104 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.198" @@ -1804,7 +1900,7 @@ dependencies = [ "backtrace", "bytes", "libc", - "mio 0.8.11", + "mio", "num_cpus", "parking_lot", "pin-project-lite", @@ -1825,6 +1921,17 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-tungstenite" version = "0.23.1" @@ -1833,7 +1940,11 @@ checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" dependencies = [ "futures-util", "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", "tokio", + "tokio-rustls", "tungstenite", ] @@ -1863,6 +1974,8 @@ dependencies = [ "httparse", "log", "rand", + "rustls", + "rustls-pki-types", "sha1", "thiserror", "utf-8", @@ -2027,7 +2140,7 @@ dependencies = [ "libsm", "log", "lz4_flex", - "mio 1.0.0", + "mio", "openssl-sys", "packet", "parking_lot", @@ -2037,6 +2150,7 @@ dependencies = [ "rand", "ring", "rsa", + "rustls", "sha2", "socket2", "spki", diff --git a/common/Cargo.toml b/common/Cargo.toml index 66d2379..80fa20b 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -33,7 +33,8 @@ port_mapping = ["vnt/port_mapping"] lz4 = ["vnt/lz4_compress"] zstd = ["vnt/zstd_compress"] upnp = ["vnt/upnp"] -websocket = ["vnt/websocket"] +ws = ["vnt/ws"] +wss = ["vnt/wss"] command = [] file_config = [] log = ["log4rs"] diff --git a/vn-link-cli/Cargo.toml b/vn-link-cli/Cargo.toml index 8b471b8..8a1d4b7 100644 --- a/vn-link-cli/Cargo.toml +++ b/vn-link-cli/Cargo.toml @@ -11,6 +11,8 @@ log = "0.4.17" [features] default = ["default-feature"] +default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4"] + openssl = ["vn-link/openssl", "common/openssl"] openssl-vendored = ["vn-link/openssl-vendored", "common/openssl-vendored"] ring-cipher = ["vn-link/ring-cipher", "common/ring-cipher"] @@ -24,9 +26,9 @@ port_mapping = ["vn-link/port_mapping", "common/port_mapping"] lz4 = ["vn-link/lz4_compress", "common/lz4"] zstd = ["vn-link/zstd_compress", "common/zstd"] upnp = ["vn-link/upnp", "common/upnp"] -websocket = ["vn-link/websocket", "common/websocket"] +ws = ["vn-link/ws", "common/ws"] +wss = ["vn-link/wss", "common/wss"] log = ["common/log"] command = ["common/command"] file_config = ["common/file_config"] -default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4"] diff --git a/vn-link/Cargo.toml b/vn-link/Cargo.toml index 7090458..5e44997 100644 --- a/vn-link/Cargo.toml +++ b/vn-link/Cargo.toml @@ -28,4 +28,5 @@ port_mapping = ["vnt/port_mapping"] lz4_compress = ["vnt/lz4_compress"] zstd_compress = ["vnt/zstd_compress"] upnp = ["vnt/upnp"] -websocket = ["vnt/websocket"] \ No newline at end of file +ws = ["vnt/ws"] +wss = ["vnt/wss"] \ No newline at end of file diff --git a/vnt-cli/Cargo.toml b/vnt-cli/Cargo.toml index 397a2b2..f4675e4 100644 --- a/vnt-cli/Cargo.toml +++ b/vnt-cli/Cargo.toml @@ -21,7 +21,7 @@ winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "win [features] default = ["default-feature"] -default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4"] +default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4", "ws"] openssl = ["vnt/openssl", "common/openssl"] openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"] @@ -36,12 +36,12 @@ port_mapping = ["vnt/port_mapping", "common/port_mapping"] lz4 = ["vnt/lz4_compress", "common/lz4"] zstd = ["vnt/zstd_compress", "common/zstd"] ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"] +upnp = ["vnt/upnp", "common/upnp"] +ws = ["vnt/ws", "common/ws"] +wss = ["vnt/wss", "common/wss"] log = ["common/log"] command = ["common/command"] file_config = ["common/file_config"] -upnp = ["common/upnp"] -websocket = ["common/websocket"] - [build-dependencies] rand = "0.8.5" chrono = "0.4.23" \ No newline at end of file diff --git a/vnt/Cargo.toml b/vnt/Cargo.toml index d6108d1..495eab0 100644 --- a/vnt/Cargo.toml +++ b/vnt/Cargo.toml @@ -17,7 +17,7 @@ parking_lot = "0.12.1" rand = "0.8.5" sha2 = { version = "0.10.6", features = ["oid"] } thiserror = "1.0.37" -protobuf = "3.2.0" +protobuf = "=3.2.0" socket2 = { version = "0.5.2", features = ["all"] } aes-gcm = { version = "0.10.2", optional = true } ring = { version = "0.17.0", optional = true } @@ -32,7 +32,7 @@ spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optio openssl-sys = { git = "https://github.com/lbl8603/rust-openssl", optional = true } libsm = { git = "https://github.com/lbl8603/libsm", optional = true } -mio = { version = "1.0.0", features = ["os-poll", "net", "os-ext"] } +mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] } crossbeam-queue = "0.3.11" anyhow = "1.0.82" dns-parser = "0.8.0" @@ -45,18 +45,19 @@ zstd = { version = "0.13.1", optional = true } fnv = "1.0.7" igd = { version = "0.12.1", optional = true } tokio-tungstenite = { version = "0.23.1", optional = true } +rustls = { version = "0.23.0", features = ["ring"], default-features = false, optional = true } futures-util = "0.3.30" [target.'cfg(target_os = "windows")'.dependencies] libloading = "0.8.0" [build-dependencies] -protobuf-codegen = "3.2.0" +protobuf-codegen = "=3.2.0" protoc-bin-vendored = "3.0.0" cfg_aliases = "0.2.1" [features] -default = ["websocket", "server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress", "integrated_tun"] +default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress", "integrated_tun"] openssl = ["openssl-sys"] # 从源码编译 openssl-vendored = ["openssl-sys/vendored"] @@ -73,4 +74,5 @@ lz4_compress = ["lz4_flex"] zstd_compress = ["zstd"] integrated_tun = ["tun"] upnp = ["igd"] -websocket = ["tokio-tungstenite"] \ No newline at end of file +ws = ["tokio-tungstenite"] +wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "rustls"] \ No newline at end of file diff --git a/vnt/src/channel/mod.rs b/vnt/src/channel/mod.rs index 1714057..3da109b 100644 --- a/vnt/src/channel/mod.rs +++ b/vnt/src/channel/mod.rs @@ -8,7 +8,7 @@ use crate::channel::handler::RecvChannelHandler; use crate::channel::sender::{AcceptSocketSender, ConnectUtil}; use crate::channel::tcp_channel::tcp_listen; use crate::channel::udp_channel::udp_listen; -#[cfg(feature = "websocket")] +#[cfg(feature = "ws")] use crate::channel::ws_channel::ws_connect_accept; use crate::util::StopManager; @@ -20,7 +20,7 @@ pub mod punch; pub mod sender; pub mod tcp_channel; pub mod udp_channel; -#[cfg(feature = "websocket")] +#[cfg(feature = "ws")] pub mod ws_channel; pub const BUFFER_SIZE: usize = 1024 * 64; @@ -308,7 +308,7 @@ where context.clone(), stop_manager.clone(), )?; - #[cfg(feature = "websocket")] + #[cfg(feature = "ws")] ws_connect_accept(_ws_connect_r, recv_handler, context.clone(), stop_manager)?; Ok((udp_socket_sender, connect_util)) diff --git a/vnt/src/channel/ws_channel.rs b/vnt/src/channel/ws_channel.rs index 09e4f95..f786262 100644 --- a/vnt/src/channel/ws_channel.rs +++ b/vnt/src/channel/ws_channel.rs @@ -8,7 +8,8 @@ use std::thread; use std::time::Duration; use tokio::net::TcpStream; use tokio::sync::mpsc::{channel, Receiver}; -use tokio_tungstenite::tungstenite::Message; +use tokio_tungstenite::tungstenite::http::StatusCode; +use tokio_tungstenite::tungstenite::{Error, Message}; use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; use crate::channel::context::ChannelContext; @@ -71,15 +72,44 @@ const WS_ADDR: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFI async fn connect_ws( data: Vec, - url: String, + mut url: String, recv_handler: H, context: ChannelContext, ) -> anyhow::Result<()> where H: RecvChannelHandler, { - let (mut ws, response) = - tokio::time::timeout(Duration::from_secs(3), connect_async(url)).await??; + let mut count = 0; + log::info!("尝试建立连接 {:?}", url); + let (mut ws, response) = loop { + count += 1; + if count > 3 { + Err(anyhow::anyhow!("发生多次重定向,链接终止"))? + } + match tokio::time::timeout(Duration::from_secs(3), connect_async(url)).await? { + Ok(rs) => break rs, + Err(e) => { + if let Error::Http(res) = &e { + if res.status() == StatusCode::MOVED_PERMANENTLY + || res.status() == StatusCode::FOUND + || res.status() == StatusCode::SEE_OTHER + || res.status() == StatusCode::TEMPORARY_REDIRECT + || res.status() == StatusCode::PERMANENT_REDIRECT + { + if let Some(v) = res.headers().get("Location") { + if let Ok(redirect) = v.to_str() { + log::info!("url重定向响应头 {:?}", res.headers()); + log::info!("url重定向地址 {}", redirect); + url = redirect.to_string(); + continue; + } + } + } + } + return Err(e)?; + } + } + }; log::info!("ws协议握手 {:?}", response); ws.send(Message::Binary(data)).await?; let (mut ws_write, ws_read) = ws.split(); diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index 74720d2..04c4a6b 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -111,16 +111,17 @@ impl Config { let mut server_address_str = server_address_str.to_lowercase(); let mut _query_dns = true; let mut protocol = ConnectProtocol::UDP; - #[cfg(feature = "websocket")] - { - if server_address_str.starts_with("ws://") { - protocol = ConnectProtocol::WS; - _query_dns = false; - } - if server_address_str.starts_with("wss://") { - protocol = ConnectProtocol::WSS; - _query_dns = false; - } + if server_address_str.starts_with("ws://") { + #[cfg(not(feature = "ws"))] + Err(anyhow!("Ws not supported"))?; + protocol = ConnectProtocol::WS; + _query_dns = false; + } + if server_address_str.starts_with("wss://") { + #[cfg(not(feature = "wss"))] + Err(anyhow!("Wss not supported"))?; + protocol = ConnectProtocol::WSS; + _query_dns = false; } let mut server_address = "0.0.0.0:0".parse().unwrap();