From 49bec2d6aacb50958875a7a73b98d0043b22bc2e Mon Sep 17 00:00:00 2001 From: lubeilin <1791778603@qq.com> Date: Mon, 6 May 2024 20:02:40 +0800 Subject: [PATCH 01/22] =?UTF-8?q?=E4=BD=BF=E7=94=A8anyhow=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=E9=83=A8=E5=88=86=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/channel/mod.rs | 47 +++++++++++++++++----------------- vnt/src/core/conn.rs | 3 +-- vnt/src/util/mod.rs | 2 -- vnt/src/util/result_convert.rs | 10 -------- 4 files changed, 24 insertions(+), 38 deletions(-) delete mode 100644 vnt/src/util/result_convert.rs diff --git a/vnt/src/channel/mod.rs b/vnt/src/channel/mod.rs index 2cb84af5..5373f485 100644 --- a/vnt/src/channel/mod.rs +++ b/vnt/src/channel/mod.rs @@ -1,4 +1,4 @@ -use std::io; +use anyhow::Context; use std::net::{SocketAddr, UdpSocket}; use std::str::FromStr; @@ -7,7 +7,7 @@ use crate::channel::handler::RecvChannelHandler; use crate::channel::sender::AcceptSocketSender; use crate::channel::tcp_channel::tcp_listen; use crate::channel::udp_channel::udp_listen; -use crate::util::{io_convert, StopManager}; +use crate::util::StopManager; pub mod context; pub mod handler; @@ -145,7 +145,7 @@ pub fn init_context( is_tcp: bool, packet_loss_rate: Option, packet_delay: u32, -) -> io::Result<(ChannelContext, mio::net::TcpListener)> { +) -> anyhow::Result<(ChannelContext, mio::net::TcpListener)> { assert!(!ports.is_empty(), "not channel"); let mut udps = Vec::with_capacity(ports.len()); //检查系统是否支持ipv6 @@ -161,9 +161,9 @@ pub fn init_context( let (socket, address) = if use_ipv6 { let address: SocketAddr = format!("[::]:{}", port).parse().unwrap(); let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::DGRAM, None)?; - io_convert(socket.set_only_v6(false), |_| { - format!("set_only_v6 failed: {}", &address) - })?; + socket + .set_only_v6(false) + .with_context(|| format!("set_only_v6 failed: {}", &address))?; (socket, address) } else { let address: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap(); @@ -172,16 +172,15 @@ pub fn init_context( address, ) }; - - io_convert(socket.set_send_buffer_size(2 * 1024 * 1024), |_| { - format!("set_send_buffer_size failed: {}", &address) - })?; - io_convert(socket.set_recv_buffer_size(2 * 1024 * 1024), |_| { - format!("set_recv_buffer_size failed: {}", &address) - })?; - io_convert(socket.bind(&address.into()), |_| { - format!("bind failed: {}", &address) - })?; + if let Err(e) = socket.set_send_buffer_size(2 * 1024 * 1024) { + log::warn!("set_send_buffer_size {:?}", e); + } + if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) { + log::warn!("set_send_buffer_size {:?}", e); + } + socket + .bind(&address.into()) + .with_context(|| format!("bind failed: {}", &address))?; let main_channel: UdpSocket = socket.into(); udps.push(main_channel); } @@ -200,9 +199,9 @@ pub fn init_context( let (socket, address) = if use_ipv6 { let address: SocketAddr = format!("[::]:{}", port).parse().unwrap(); let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?; - io_convert(socket.set_only_v6(false), |_| { - format!("set_only_v6 failed: {}", &address) - })?; + socket + .set_only_v6(false) + .with_context(|| format!("set_only_v6 failed: {}", &address))?; (socket, address) } else { let address: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap(); @@ -219,12 +218,12 @@ pub fn init_context( } else { format!("0.0.0.0:{}", port).parse().unwrap() }; - io_convert(socket.bind(&address.into()), |_| { - format!("bind failed: {}", &address) - })?; + socket + .bind(&address.into()) + .with_context(|| format!("bind failed: {}", &address))?; } else { //手动指定的ip,直接报错 - io_convert(Err(e), |_| format!("bind failed: {}", &address))?; + Err(anyhow::anyhow!("{:?},bind failed: {}", e, address))?; } } socket.listen(128)?; @@ -239,7 +238,7 @@ pub fn init_channel( context: ChannelContext, stop_manager: StopManager, recv_handler: H, -) -> io::Result<( +) -> anyhow::Result<( AcceptSocketSender>>, AcceptSocketSender<(mio::net::TcpStream, SocketAddr, Option>)>, )> diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index ef666ed1..9bd965c4 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::io; use std::net::Ipv4Addr; use std::sync::Arc; use std::time::Duration; @@ -48,7 +47,7 @@ pub struct Vnt { } impl Vnt { - pub fn new(config: Config, callback: Call) -> io::Result { + pub fn new(config: Config, callback: Call) -> anyhow::Result { log::info!("config:{:?}", config); //服务端非对称加密 #[cfg(feature = "server_encrypt")] diff --git a/vnt/src/util/mod.rs b/vnt/src/util/mod.rs index c0f668a4..9fae45b9 100644 --- a/vnt/src/util/mod.rs +++ b/vnt/src/util/mod.rs @@ -1,6 +1,4 @@ mod notify; -mod result_convert; -pub use result_convert::io_convert; mod scheduler; pub use notify::StopManager; pub use scheduler::Scheduler; diff --git a/vnt/src/util/result_convert.rs b/vnt/src/util/result_convert.rs deleted file mode 100644 index 981d8c29..00000000 --- a/vnt/src/util/result_convert.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::fmt::Display; -use std::io; - -#[inline] -pub fn io_convert R>( - rs: io::Result, - f: F, -) -> io::Result { - rs.map_err(|e| io::Error::new(e.kind(), format!("{},internal error:{:?}", f(&e), e))) -} From ff389647c0642a358765cbaf642fc2fbd0c211a9 Mon Sep 17 00:00:00 2001 From: lubeilin <1791778603@qq.com> Date: Mon, 6 May 2024 21:00:12 +0800 Subject: [PATCH 02/22] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B8=AE=E5=8A=A9?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-cli/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs index d7608762..7b42ef39 100644 --- a/vnt-cli/src/main.rs +++ b/vnt-cli/src/main.rs @@ -412,7 +412,7 @@ fn print_usage(program: &str, _opts: Options) { println!(" -n 给设备一个名字,便于区分不同设备,默认使用系统版本"); println!(" -d 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复"); println!(" -s 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录"); - println!(" -e stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2"); + println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.qq.com -e stun1.l.google.com"); println!(" -a 使用tap模式,默认使用tun模式"); println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); println!(" 并转发到10.26.0.3,可指定多个网段"); From b771b6c07479580034c21f9eb48279e9c71246e0 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Wed, 8 May 2024 20:16:36 +0800 Subject: [PATCH 03/22] =?UTF-8?q?=E5=A2=9E=E5=8A=A0set=5Fttl=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/packet/src/ip/ipv4/packet.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vnt/packet/src/ip/ipv4/packet.rs b/vnt/packet/src/ip/ipv4/packet.rs index ab1ca746..5a41021f 100644 --- a/vnt/packet/src/ip/ipv4/packet.rs +++ b/vnt/packet/src/ip/ipv4/packet.rs @@ -81,6 +81,9 @@ impl + AsMut<[u8]>> IpV4Packet { pub fn set_flags(&mut self, flags: u8) { self.buffer.as_mut()[6] = (self.buffer.as_ref()[6] & 0b11100000) | (flags << 5) } + pub fn set_ttl(&mut self, ttl: u8) { + self.buffer.as_mut()[8] = ttl + } fn set_checksum(&mut self, value: u16) { self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes()) } From ff2bbdd8372f013249692191d471210fd8207ecc Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Wed, 8 May 2024 20:19:33 +0800 Subject: [PATCH 04/22] =?UTF-8?q?=E6=94=B9=E5=9B=9E=E7=94=A8tokio=E5=A4=84?= =?UTF-8?q?=E7=90=86=E4=BB=A3=E7=90=86=EF=BC=8C=E7=AE=80=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 122 ++++++++++ vnt/Cargo.toml | 36 +-- vnt/src/ip_proxy/icmp_proxy.rs | 161 +++++-------- vnt/src/ip_proxy/mod.rs | 40 ++- vnt/src/ip_proxy/tcp_proxy.rs | 428 +++++---------------------------- vnt/src/ip_proxy/udp_proxy.rs | 325 +++++++------------------ 6 files changed, 380 insertions(+), 732 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18f0a8dc..8a797cb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.5.2" @@ -79,6 +94,21 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64ct" version = "1.6.0" @@ -422,6 +452,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "hashbrown" version = "0.12.3" @@ -434,6 +470,12 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "home" version = "0.5.9" @@ -656,6 +698,15 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.11" @@ -726,6 +777,25 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -817,6 +887,12 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + [[package]] name = "pkcs1" version = "0.7.5" @@ -1096,6 +1172,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" version = "0.38.32" @@ -1195,6 +1277,15 @@ dependencies = [ "digest", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "2.2.0" @@ -1343,6 +1434,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "tun" version = "0.1.0" @@ -1468,6 +1589,7 @@ dependencies = [ "spki", "stun-format", "thiserror", + "tokio", "tun", ] diff --git a/vnt/Cargo.toml b/vnt/Cargo.toml index a1e91c28..2ff46558 100644 --- a/vnt/Cargo.toml +++ b/vnt/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tun= {path = "tun"} +tun = { path = "tun" } packet = { path = "./packet" } bytes = "1.5.0" log = "0.4.17" @@ -19,22 +19,25 @@ sha2 = { version = "0.10.6", features = ["oid"] } thiserror = "1.0.37" protobuf = "3.2.0" socket2 = { version = "0.5.2", features = ["all"] } -aes-gcm = { version = "0.10.2",optional = true } +aes-gcm = { version = "0.10.2", optional = true } ring = { version = "0.17.0", optional = true } -cbc = {version = "0.1.2",optional = true} -ecb = {version = "0.1.2",optional = true} +cbc = { version = "0.1.2", optional = true } +ecb = { version = "0.1.2", optional = true } aes = "0.8.3" stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] } -rsa = { version = "0.9.2", features = [] ,optional = true} -spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64"] ,optional = true} -openssl-sys = { git = "https://github.com/lbl8603/rust-openssl" ,optional = true} -libsm = {git="https://github.com/lbl8603/libsm" ,optional = true} +rsa = { version = "0.9.2", features = [], optional = true } +spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optional = true } +openssl-sys = { git = "https://github.com/lbl8603/rust-openssl", optional = true } +libsm = { git = "https://github.com/lbl8603/libsm", optional = true } -mio = {version = "0.8.10",features = ["os-poll","net"]} +mio = { version = "0.8.10", features = ["os-poll", "net"] } crossbeam-queue = "0.3.11" anyhow = "1.0.82" dns-parser = "0.8.0" +tokio = { version = "1.37.0", features = ["full"], optional = true } + + [target.'cfg(target_os = "windows")'.dependencies] libloading = "0.8.0" @@ -44,14 +47,15 @@ protobuf-codegen = "3.2.0" protoc-bin-vendored = "3.0.0" [features] -default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc","ip_proxy"] +default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping"] openssl = ["openssl-sys"] # 从源码编译 openssl-vendored = ["openssl-sys/vendored"] ring-cipher = ["ring"] -aes_cbc=["cbc"] -aes_ecb=["ecb"] -sm4_cbc=["libsm"] -aes_gcm=["aes-gcm"] -server_encrypt =["aes-gcm","rsa","spki"] -ip_proxy=[] +aes_cbc = ["cbc"] +aes_ecb = ["ecb"] +sm4_cbc = ["libsm"] +aes_gcm = ["aes-gcm"] +server_encrypt = ["aes-gcm", "rsa", "spki"] +ip_proxy = ["tokio"] +port_mapping = ["tokio"] diff --git a/vnt/src/ip_proxy/icmp_proxy.rs b/vnt/src/ip_proxy/icmp_proxy.rs index d24dbd49..7c4f68fa 100644 --- a/vnt/src/ip_proxy/icmp_proxy.rs +++ b/vnt/src/ip_proxy/icmp_proxy.rs @@ -1,12 +1,12 @@ +use anyhow::Context; use std::collections::HashMap; +use std::io; use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::Arc; -use std::{io, thread}; use crossbeam_utils::atomic::AtomicCell; -use mio::net::UdpSocket; -use mio::{Events, Interest, Poll, Token, Waker}; use parking_lot::Mutex; +use tokio::net::UdpSocket; use packet::icmp::icmp; use packet::icmp::icmp::HeaderOther; @@ -18,7 +18,6 @@ use crate::handle::CurrentDeviceInfo; use crate::ip_proxy::ProxyHandler; use crate::protocol; use crate::protocol::{NetPacket, MAX_TTL}; -use crate::util::StopManager; #[derive(Clone)] pub struct IcmpProxy { icmp_socket: Arc, @@ -27,48 +26,50 @@ pub struct IcmpProxy { } impl IcmpProxy { - pub fn new( + pub async fn new( context: ChannelContext, - stop_manager: StopManager, current_device: Arc>, client_cipher: Cipher, - ) -> io::Result { + ) -> anyhow::Result { #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] let icmp_socket = socket2::Socket::new( socket2::Domain::IPV4, socket2::Type::RAW, Some(socket2::Protocol::ICMPV4), - )?; + ) + .context("new Socket RAW ICMPV4 failed")?; #[cfg(target_os = "android")] let icmp_socket = socket2::Socket::new( socket2::Domain::IPV4, socket2::Type::DGRAM, Some(socket2::Protocol::ICMPV4), - )?; + ) + .context("new Socket DGRAM ICMPV4 failed")?; let addr: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0); - icmp_socket.bind(&socket2::SockAddr::from(addr))?; + icmp_socket + .bind(&socket2::SockAddr::from(addr)) + .context("bind Socket ICMPV4 failed")?; icmp_socket.set_nonblocking(true)?; let std_socket: std::net::UdpSocket = icmp_socket.into(); - let mio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?); + + let tokio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?)?; let nat_map: Arc>> = Arc::new(Mutex::new(HashMap::with_capacity(16))); { let nat_map = nat_map.clone(); - thread::Builder::new() - .name("icmpProxy".into()) - .spawn(move || { - if let Err(e) = icmp_proxy( - mio_icmp_socket, - nat_map, - context, - stop_manager, - current_device, - client_cipher, - ) { - log::warn!("icmp_proxy:{:?}", e); - } - }) - .expect("icmpProxy"); + tokio::spawn(async { + if let Err(e) = icmp_proxy( + tokio_icmp_socket, + nat_map, + context, + current_device, + client_cipher, + ) + .await + { + log::warn!("icmp_proxy:{:?}", e); + } + }); } Ok(Self { icmp_socket: Arc::new(std_socket), @@ -77,105 +78,51 @@ impl IcmpProxy { } } -const SERVER_VAL: usize = 0; -const SERVER: Token = Token(SERVER_VAL); -const NOTIFY_VAL: usize = 1; -const NOTIFY: Token = Token(NOTIFY_VAL); - -fn icmp_proxy( - mut icmp_socket: UdpSocket, +async fn icmp_proxy( + icmp_socket: UdpSocket, // 对端-> 真实来源 nat_map: Arc>>, context: ChannelContext, - stop_manager: StopManager, current_device: Arc>, client_cipher: Cipher, ) -> io::Result<()> { - let mut poll = Poll::new()?; - poll.registry() - .register(&mut icmp_socket, SERVER, Interest::READABLE)?; - let mut events = Events::with_capacity(32); - let stop = Arc::new(Waker::new(poll.registry(), NOTIFY)?); - let _stop = stop.clone(); - let _worker = stop_manager.add_listener("icmp_proxy".into(), move || { - if let Err(e) = stop.wake() { - log::warn!("stop icmp_proxy:{:?}", e); - } - })?; let mut buf = [0u8; 65535 - 20 - 8]; loop { - poll.poll(&mut events, None)?; - if stop_manager.is_stop() { - return Ok(()); - } - for event in events.iter() { - match event.token() { - SERVER => readable_handle( - &icmp_socket, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + let start = 12; + #[cfg(target_os = "android")] + let start = 12 + 20; + loop { + let (len, addr) = icmp_socket.recv_from(&mut buf[start..]).await?; + if let IpAddr::V4(peer_ip) = addr.ip() { + #[cfg(target_os = "android")] + { + let buf = &mut buf[12..]; + // ipv4 头部20字节 + buf[0] = 0b0100_0110; + //写入总长度 + buf[2..4].copy_from_slice(&((20 + len) as u16).to_be_bytes()); + + let mut ipv4 = IpV4Packet::unchecked(buf); + ipv4.set_flags(2); + ipv4.set_ttl(1); + ipv4.set_protocol(packet::ip::ipv4::protocol::Protocol::Icmp); + ipv4.set_source_ip(peer_ip); + } + recv_handle( &mut buf, + start + len, + peer_ip, &nat_map, &context, ¤t_device, &client_cipher, - ), - NOTIFY => { - return Ok(()); - } - _ => {} + ); } } } } -fn readable_handle( - icmp_socket: &UdpSocket, - buf: &mut [u8], - nat_map: &Mutex>, - context: &ChannelContext, - current_device: &AtomicCell, - client_cipher: &Cipher, -) { - #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] - let start = 12; - #[cfg(target_os = "android")] - let start = 12 + 20; - loop { - let (len, addr) = match icmp_socket.recv_from(&mut buf[start..]) { - Ok(rs) => rs, - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - break; - } - log::warn!("icmp_socket {:?}", e); - return; - } - }; - if let IpAddr::V4(peer_ip) = addr.ip() { - #[cfg(target_os = "android")] - { - let buf = &mut buf[12..]; - // ipv4 头部20字节 - buf[0] = 0b0100_0110; - //写入总长度 - buf[2..4].copy_from_slice(&((20 + len) as u16).to_be_bytes()); - let mut ipv4 = IpV4Packet::unchecked(buf); - ipv4.set_flags(2); - ipv4.set_ttl(1); - ipv4.set_protocol(packet::ip::ipv4::protocol::Protocol::Icmp); - ipv4.set_source_ip(peer_ip); - } - recv_handle( - buf, - start + len, - peer_ip, - &nat_map, - &context, - ¤t_device, - &client_cipher, - ); - } - } -} fn recv_handle( buf: &mut [u8], data_len: usize, diff --git a/vnt/src/ip_proxy/mod.rs b/vnt/src/ip_proxy/mod.rs index 54a97c59..2387aef7 100644 --- a/vnt/src/ip_proxy/mod.rs +++ b/vnt/src/ip_proxy/mod.rs @@ -1,6 +1,6 @@ -use std::io; use std::net::Ipv4Addr; use std::sync::Arc; +use std::{io, thread}; use crossbeam_utils::atomic::AtomicCell; @@ -13,7 +13,7 @@ use crate::handle::CurrentDeviceInfo; use crate::ip_proxy::icmp_proxy::IcmpProxy; use crate::ip_proxy::tcp_proxy::TcpProxy; use crate::ip_proxy::udp_proxy::UdpProxy; -use crate::util::{Scheduler, StopManager}; +use crate::util::StopManager; pub mod icmp_proxy; pub mod tcp_proxy; @@ -38,14 +38,40 @@ pub struct IpProxyMap { pub fn init_proxy( context: ChannelContext, - scheduler: Scheduler, stop_manager: StopManager, current_device: Arc>, client_cipher: Cipher, -) -> io::Result { - let icmp_proxy = IcmpProxy::new(context, stop_manager.clone(), current_device, client_cipher)?; - let tcp_proxy = TcpProxy::new(stop_manager.clone())?; - let udp_proxy = UdpProxy::new(scheduler, stop_manager)?; +) -> anyhow::Result { + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .thread_name("ipProxy") + .build()?; + let proxy_map = runtime.block_on(init_proxy0(context, current_device, client_cipher))?; + let (sender, receiver) = tokio::sync::oneshot::channel::<()>(); + let worker = stop_manager.add_listener("ipProxy".into(), move || { + let _ = sender.send(()); + })?; + thread::Builder::new() + .name("ipProxy".into()) + .spawn(move || { + runtime.block_on(async { + let _ = receiver.await; + }); + runtime.shutdown_background(); + drop(worker); + })?; + + return Ok(proxy_map); +} + +async fn init_proxy0( + context: ChannelContext, + current_device: Arc>, + client_cipher: Cipher, +) -> anyhow::Result { + let icmp_proxy = IcmpProxy::new(context, current_device, client_cipher).await?; + let tcp_proxy = TcpProxy::new().await?; + let udp_proxy = UdpProxy::new().await?; Ok(IpProxyMap { icmp_proxy, diff --git a/vnt/src/ip_proxy/tcp_proxy.rs b/vnt/src/ip_proxy/tcp_proxy.rs index 5c460e28..0e0c1233 100644 --- a/vnt/src/ip_proxy/tcp_proxy.rs +++ b/vnt/src/ip_proxy/tcp_proxy.rs @@ -1,28 +1,16 @@ -use std::io::{Read, Write}; -use std::net::{Ipv4Addr, Shutdown, SocketAddrV4}; -#[cfg(unix)] -use std::os::fd::AsRawFd; -#[cfg(windows)] -use std::os::windows::io::AsRawSocket; +use anyhow::Context; +use std::net::{Ipv4Addr, SocketAddrV4}; use std::sync::Arc; use std::time::Duration; -use std::{collections::HashMap, io, net::SocketAddr, thread}; +use std::{collections::HashMap, io, net::SocketAddr}; -use bytes::{BufMut, BytesMut}; -use mio::net::TcpStream; -use mio::{net::TcpListener, Events, Interest, Poll, Registry, Token, Waker}; use parking_lot::Mutex; +use tokio::net::{TcpListener, TcpSocket, TcpStream}; use packet::ip::ipv4::packet::IpV4Packet; use packet::tcp::tcp::TcpPacket; use crate::ip_proxy::ProxyHandler; -use crate::util::StopManager; - -const SERVER_VAL: usize = 0; -const SERVER: Token = Token(SERVER_VAL); -const NOTIFY_VAL: usize = 1; -const NOTIFY: Token = Token(NOTIFY_VAL); #[derive(Clone)] pub struct TcpProxy { @@ -31,21 +19,16 @@ pub struct TcpProxy { } impl TcpProxy { - pub fn new(stop_manager: StopManager) -> io::Result { + pub async fn new() -> anyhow::Result { let nat_map: Arc>> = Arc::new(Mutex::new(HashMap::with_capacity(16))); - let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0).parse().unwrap())?; + let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0)) + .await + .context("TcpProxy bind failed")?; let port = tcp_listener.local_addr()?.port(); { let nat_map = nat_map.clone(); - thread::Builder::new() - .name("tcpProxy".into()) - .spawn(move || { - if let Err(e) = tcp_proxy(tcp_listener, nat_map, stop_manager) { - log::warn!("tcp_proxy:{:?}", e); - } - }) - .expect("tcpProxy"); + tokio::spawn(tcp_proxy(tcp_listener, nat_map)); } Ok(Self { port, nat_map }) } @@ -93,365 +76,74 @@ impl ProxyHandler for TcpProxy { } } -fn tcp_proxy( - mut tcp_listener: TcpListener, +async fn tcp_proxy( + tcp_listener: TcpListener, nat_map: Arc>>, - stop_manager: StopManager, -) -> io::Result<()> { - let mut poll = Poll::new()?; - poll.registry() - .register(&mut tcp_listener, SERVER, Interest::READABLE)?; - let mut events = Events::with_capacity(32); - let mut tcp_map: HashMap = HashMap::with_capacity(16); - let mut mapping: HashMap = HashMap::with_capacity(16); - let stop = Arc::new(Waker::new(poll.registry(), NOTIFY)?); - let _stop = stop.clone(); - let _worker = stop_manager.add_listener("tcp_proxy".into(), move || { - if let Err(e) = stop.wake() { - log::warn!("stop tcp_proxy:{:?}", e); - } - })?; - loop { - poll.poll(&mut events, None)?; - if stop_manager.is_stop() { - return Ok(()); - } - for event in events.iter() { - match event.token() { - SERVER => { - accept_handle( - poll.registry(), - &tcp_listener, - &nat_map, - &mut tcp_map, - &mut mapping, - ); - } - NOTIFY => { - return Ok(()); - } - Token(index) => { - let (val, src_index) = if let Some(v) = tcp_map.get_mut(&index) { - (v, index) - } else { - if let Some(dest_index) = mapping.get(&index) { - if let Some(v) = tcp_map.get_mut(dest_index) { - (v, *dest_index) - } else { - continue; - } - } else { - continue; - } - }; - let (stream1, stream2, buf1, buf2, state1, state2) = val.as_mut(index); - if event.is_readable() { - if let Err(_) = readable_handle(stream1, stream2, buf1, state2) { - *state1 |= READ_CLOSED; - } - } - if event.is_writable() { - let read = buf2.len() >= BUF_LEN; - if let Err(_) = writable_handle(stream1, buf2) { - *state1 |= WRITE_CLOSED; - } else if read { - if readable_handle(stream2, stream1, buf2, state1).is_err() { - *state2 |= READ_CLOSED; - } - } - } - if event.is_read_closed() || event.is_error() { - *state1 |= READ_CLOSED; - } - if event.is_write_closed() || event.is_error() { - *state1 |= WRITE_CLOSED; - } - if is_write_closed(*state1) { - let _ = stream1.shutdown(Shutdown::Write); - let _ = stream2.shutdown(Shutdown::Read); - } - if is_read_closed(*state1) { - let _ = stream1.shutdown(Shutdown::Read); - if buf1.is_empty() { - let _ = stream2.shutdown(Shutdown::Write); - } - } - if (is_both_closed(*state1) && buf1.is_empty()) - || (is_both_closed(*state2) && buf2.is_empty()) - || (is_write_closed(*state1) && is_write_closed(*state2) - || (is_read_closed(*state1) - && is_read_closed(*state2) - && buf1.is_empty() - && buf2.is_empty())) - { - close(src_index, &mut tcp_map, &mut mapping); - } - } - } - } - } -} - -fn accept_handle( - registry: &Registry, - tcp_listener: &TcpListener, - nat_map: &Mutex>, - tcp_map: &mut HashMap, - mapping: &mut HashMap, ) { loop { - match tcp_listener.accept() { - Ok((mut src_stream, addr)) => { - #[cfg(windows)] - let src_fd = src_stream.as_raw_socket() as usize; - #[cfg(unix)] - let src_fd = src_stream.as_raw_fd() as usize; - if src_fd == SERVER_VAL || src_fd == NOTIFY_VAL { - log::error!("fd错误:{:?}", src_fd); - continue; - } - let addr = match addr { - SocketAddr::V4(addr) => addr, - SocketAddr::V6(_) => { - // 忽略ipv6 - continue; - } - }; - let _ = src_stream.set_nodelay(false); - if let Some(dest_addr) = nat_map.lock().get(&addr).cloned() { - match tcp_connect(addr.port(), dest_addr.into()) { - Ok(mut dest_stream) => { - #[cfg(windows)] - let dest_fd = dest_stream.as_raw_socket() as usize; - #[cfg(unix)] - let dest_fd = dest_stream.as_raw_fd() as usize; - if dest_fd == SERVER_VAL || dest_fd == NOTIFY_VAL { - log::error!("fd错误:{:?}", dest_fd); - continue; - } - if let Err(e) = registry.register( - &mut src_stream, - Token(src_fd), - Interest::READABLE.add(Interest::WRITABLE), - ) { - log::error!("register src_stream:{:?}", e); - continue; - } - if let Err(e) = registry.register( - &mut dest_stream, - Token(dest_fd), - Interest::READABLE.add(Interest::WRITABLE), - ) { - log::error!("register dest_stream:{:?}", e); - continue; - } - tcp_map.insert( - src_fd, - ProxyValue::new(src_stream, dest_stream, src_fd, dest_fd), - ); - mapping.insert(dest_fd, src_fd); - } - Err(e) => { - log::error!("connect:{:?} {}->{}", e, addr, dest_addr); - } + match tcp_listener.accept().await { + Ok((tcp_stream, sender_addr)) => match sender_addr { + SocketAddr::V4(sender_addr) => { + if let Some(dest_addr) = nat_map.lock().get(&sender_addr).cloned() { + tokio::spawn(async move { + let peer_tcp_stream = + match tcp_connect(sender_addr.port(), dest_addr.into()).await { + Ok(peer_tcp_stream) => peer_tcp_stream, + Err(e) => { + log::warn!( + "tcp代理异常:{:?},来源:{},目标:{}", + e, + sender_addr, + dest_addr + ); + return; + } + }; + proxy(sender_addr, dest_addr, tcp_stream, peer_tcp_stream).await + }); + } else { + log::warn!("tcp代理异常: 来源:{},未找到目标", sender_addr); } } - } + SocketAddr::V6(_) => {} + }, Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - break; - } - log::error!("accept:{:?}", e); + log::warn!("tcp代理监听:{:?}", e); } } } } - -fn tcp_connect(src_port: u16, addr: SocketAddr) -> io::Result { - let socket = socket2::Socket::new( - socket2::Domain::IPV4, - socket2::Type::STREAM, - Some(socket2::Protocol::TCP), - )?; +/// 优先使用来源端口建立tcp连接 +async fn tcp_connect(src_port: u16, addr: SocketAddr) -> anyhow::Result { + let socket = TcpSocket::new_v4()?; if socket - .bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into()) + .bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into()) .is_err() { - socket.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?; - } - if let Err(e) = socket.set_tcp_keepalive( - &socket2::TcpKeepalive::new() - .with_time(Duration::from_secs(120)) - .with_interval(Duration::from_secs(10)), - ) { - log::warn!("set_tcp_keepalive err {:?}", e); + socket.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?; } let _ = socket.set_nodelay(false); - socket.connect_timeout(&addr.into(), Duration::from_secs(3))?; - socket.set_nonblocking(true)?; - Ok(TcpStream::from_std(socket.into())) -} - -#[derive(Debug)] -struct ProxyValue { - src_stream: TcpStream, - dest_stream: TcpStream, - src_fd: usize, - dest_fd: usize, - src_buf: BytesMut, - dest_buf: BytesMut, - src_state: u8, - dest_state: u8, -} - -const BUF_LEN: usize = 65536; - -impl ProxyValue { - fn new(src_stream: TcpStream, dest_stream: TcpStream, src_fd: usize, dest_fd: usize) -> Self { - Self { - src_stream, - dest_stream, - src_fd, - dest_fd, - src_buf: BytesMut::with_capacity(BUF_LEN), - dest_buf: BytesMut::with_capacity(BUF_LEN), - src_state: NORMAL, - dest_state: NORMAL, - } - } - fn as_mut( - &mut self, - index: usize, - ) -> ( - &mut TcpStream, - &mut TcpStream, - &mut BytesMut, - &mut BytesMut, - &mut u8, - &mut u8, - ) { - if index == self.src_fd { - ( - &mut self.src_stream, - &mut self.dest_stream, - &mut self.src_buf, - &mut self.dest_buf, - &mut self.src_state, - &mut self.dest_state, - ) - } else { - ( - &mut self.dest_stream, - &mut self.src_stream, - &mut self.dest_buf, - &mut self.src_buf, - &mut self.dest_state, - &mut self.src_state, - ) - } - } -} - -fn readable_handle( - stream1: &mut TcpStream, - stream2: &mut TcpStream, - mid_buf: &mut BytesMut, - state2: &mut u8, -) -> io::Result<()> { - let mut buf = [0; BUF_LEN]; - - loop { - if mid_buf.len() >= BUF_LEN { - // 达到上限不再继续读取 - return Ok(()); - } - match stream1.read(&mut buf) { - Ok(len) => { - if len == 0 { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof)); - } - let mut buf = &buf[..len]; - if mid_buf.is_empty() { - // 直接写入,避免在buf中过渡 - while !buf.is_empty() { - match stream2.write(buf) { - Ok(end) => { - if end == 0 { - *state2 |= WRITE_CLOSED; - return Err(io::Error::from(io::ErrorKind::WriteZero)); - } - buf = &buf[end..]; - } - Err(e) => { - if e.kind() != io::ErrorKind::WouldBlock { - *state2 |= WRITE_CLOSED; - return Err(e); - } - break; - } - } - } - if buf.is_empty() { - continue; - } - } - mid_buf.reserve(buf.len()); - mid_buf.put_slice(buf); - } - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - break; - } - return Err(e); - } - } - } - Ok(()) -} - -fn writable_handle(stream: &mut TcpStream, mid_buf: &mut BytesMut) -> io::Result<()> { - while !mid_buf.is_empty() { - match stream.write(&mid_buf) { - Ok(len) => { - let _ = mid_buf.split_to(len); - } - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - break; - } - return Err(e); - } - } - } - Ok(()) + let tcp_stream = tokio::time::timeout(Duration::from_secs(5), socket.connect(addr)) + .await + .with_context(|| format!("TCP connection timeout {}", addr))? + .with_context(|| format!("TCP connection target failed {}", addr))?; + Ok(tcp_stream) } -fn close( - index: usize, - tcp_map: &mut HashMap, - mapping: &mut HashMap, +async fn proxy( + sender_addr: SocketAddrV4, + dest_addr: SocketAddrV4, + client: TcpStream, + server: TcpStream, ) { - if let Some(val) = tcp_map.remove(&index) { - let _ = val.src_stream.shutdown(Shutdown::Both); - let _ = val.dest_stream.shutdown(Shutdown::Both); - mapping.remove(&val.src_fd); - mapping.remove(&val.dest_fd); + let (mut client_read, mut client_write) = client.into_split(); + let (mut server_read, mut server_write) = server.into_split(); + tokio::spawn(async move { + if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await { + log::warn!("client tcp proxy {}->{},{:?}", sender_addr, dest_addr, e); + } + }); + if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await { + log::warn!("server tcp proxy {}->{},{:?}", sender_addr, dest_addr, e); } } - -const NORMAL: u8 = 0b00; -const READ_CLOSED: u8 = 0b01; -const WRITE_CLOSED: u8 = 0b10; -const BOTH_CLOSED: u8 = 0b11; - -fn is_read_closed(state: u8) -> bool { - (state & READ_CLOSED == READ_CLOSED) || is_both_closed(state) -} - -fn is_write_closed(state: u8) -> bool { - (state & WRITE_CLOSED == WRITE_CLOSED) || is_both_closed(state) -} - -fn is_both_closed(state: u8) -> bool { - state & BOTH_CLOSED == BOTH_CLOSED -} diff --git a/vnt/src/ip_proxy/udp_proxy.rs b/vnt/src/ip_proxy/udp_proxy.rs index e416aee6..08377490 100644 --- a/vnt/src/ip_proxy/udp_proxy.rs +++ b/vnt/src/ip_proxy/udp_proxy.rs @@ -1,30 +1,17 @@ +use anyhow::Context; +use crossbeam_utils::atomic::AtomicCell; use std::net::{Ipv4Addr, SocketAddrV4}; -#[cfg(unix)] -use std::os::fd::AsRawFd; -#[cfg(windows)] -use std::os::windows::io::AsRawSocket; use std::sync::Arc; use std::time::{Duration, Instant}; -use std::{collections::HashMap, io, net::SocketAddr, rc::Rc, thread}; +use std::{collections::HashMap, io, net::SocketAddr}; -use mio::{net::UdpSocket, Events, Interest, Poll, Token}; -use mio::{Registry, Waker}; use parking_lot::Mutex; +use tokio::net::UdpSocket; use packet::ip::ipv4::packet::IpV4Packet; use packet::udp::udp::UdpPacket; use crate::ip_proxy::ProxyHandler; -use crate::util::{Scheduler, StopManager}; - -const SERVER_VAL: usize = 0; -const SERVER: Token = Token(SERVER_VAL); -const NOTIFY_VAL: usize = 1; -const NOTIFY: Token = Token(NOTIFY_VAL); -// 开了ip代理后使用mstsc,mstsc会误以为在真实局域网,从而不维护udp心跳,导致断连,所以这里尽量长一点过期时间 -const NAT_TIMEOUT: Duration = Duration::from_secs(20 * 60); -const NAT_FAST_TIMEOUT: Duration = Duration::from_secs(5 * 60); -const NAT_MAX: usize = 5_000; #[derive(Clone)] pub struct UdpProxy { @@ -33,21 +20,20 @@ pub struct UdpProxy { } impl UdpProxy { - pub fn new(scheduler: Scheduler, stop_manager: StopManager) -> io::Result { + pub async fn new() -> anyhow::Result { let nat_map: Arc>> = Arc::new(Mutex::new(HashMap::with_capacity(16))); - let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0).parse().unwrap())?; + let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0)) + .await + .context("UdpProxy bind failed")?; let port = udp.local_addr()?.port(); { let nat_map = nat_map.clone(); - thread::Builder::new() - .name("udpProxy".into()) - .spawn(move || { - if let Err(e) = udp_proxy(udp, nat_map, scheduler, stop_manager) { - log::warn!("udp_proxy:{:?}", e); - } - }) - .expect("udpProxy"); + tokio::spawn(async { + if let Err(e) = udp_proxy(udp, nat_map).await { + log::warn!("udp_proxy:{:?}", e); + } + }); } Ok(Self { port, nat_map }) } @@ -95,230 +81,101 @@ impl ProxyHandler for UdpProxy { } } -fn udp_proxy( - mut udp: UdpSocket, +async fn udp_proxy( + udp: UdpSocket, nat_map: Arc>>, - scheduler: Scheduler, - stop_manager: StopManager, ) -> io::Result<()> { - let mut poll = Poll::new()?; + let mut buf = [0u8; 65536]; - poll.registry() - .register(&mut udp, SERVER, Interest::READABLE)?; - let mut events = Events::with_capacity(32); - let mut buf = [0; 65536]; - let mut token_map: HashMap, SocketAddrV4, Instant)> = - HashMap::with_capacity(64); - let mut udp_map: HashMap, Instant)> = HashMap::with_capacity(64); - let mut timeout = false; - let waker = Arc::new(Waker::new(poll.registry(), NOTIFY)?); - let stop = waker.clone(); - let _worker = stop_manager.add_listener("udp_proxy".into(), move || { - if let Err(e) = stop.wake() { - log::warn!("stop udp_proxy:{:?}", e); - } - })?; + let inner_map: Arc, Arc>)>>> = + Arc::new(Mutex::new(HashMap::with_capacity(64))); + let udp_socket = Arc::new(udp); loop { - let mut check = false; - if token_map.is_empty() { - poll.poll(&mut events, None)?; - } else { - //所有事件 50分钟超时 - if let Err(e) = poll.poll(&mut events, Some(Duration::from_secs(50 * 60))) { - if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock { - log::warn!( - "超时清理所有udp映射 {},token_map={},udp_map={}", - e, - token_map.len(), - udp_map.len() - ); - token_map.clear(); - udp_map.clear(); - continue; - } - return Err(e); - } - } - if stop_manager.is_stop() { - return Ok(()); - } - for event in events.iter() { - match event.token() { - SERVER => server_handle( - poll.registry(), - &udp, - &nat_map, - &mut token_map, - &mut udp_map, - &mut buf, - ), - NOTIFY => { - check = true; - } - token => { - if let Err(e) = readable_handle(&udp, &mut token_map, &token, &mut buf) { - log::error!("发送目标失败:{:?}", e); - if let Some((_, src_addr, _)) = token_map.remove(&token) { - udp_map.remove(&src_addr); - } + match udp_socket.recv_from(&mut buf).await { + Ok((len, sender_addr)) => match sender_addr { + SocketAddr::V4(sender_addr) => { + if let Err(e) = + udp_proxy0(&buf[..len], sender_addr, &inner_map, &nat_map, &udp_socket) + .await + { + log::warn!("udp proxy {} {:?}", sender_addr, e); } } - } - } - if check { - //超时校验 - if token_map.len() > NAT_MAX / 2 { - check_handle(&mut token_map, &mut udp_map, NAT_FAST_TIMEOUT) - } else { - check_handle(&mut token_map, &mut udp_map, NAT_TIMEOUT) - } - timeout = false; - } - if !token_map.is_empty() && !timeout { - //注册超时监听 - timeout = true; - let waker = waker.clone(); - scheduler.timeout(NAT_FAST_TIMEOUT, move |_| { - let _ = waker.wake(); - }); - } - } -} - -fn check_handle( - token_map: &mut HashMap, SocketAddrV4, Instant)>, - udp_map: &mut HashMap, Instant)>, - timeout: Duration, -) { - let mut remove_list = Vec::new(); - for (token, (_, addr, time)) in token_map.iter() { - if time.elapsed() > timeout { - if let Some((_, time)) = udp_map.get(addr) { - if time.elapsed() > timeout { - //映射超时,需要移除 - remove_list.push(*token); - } - } - } - } - for token in remove_list { - if let Some((_, src_addr, _)) = token_map.remove(&token) { - udp_map.remove(&src_addr); - log::warn!( - "超时清理udp映射 {},token_map={},udp_map={}", - src_addr, - token_map.len(), - udp_map.len() - ); - } - } -} - -fn server_handle( - registry: &Registry, - udp: &UdpSocket, - nat_map: &Mutex>, - token_map: &mut HashMap, SocketAddrV4, Instant)>, - udp_map: &mut HashMap, Instant)>, - buf: &mut [u8], -) { - loop { - let (len, src_addr) = match udp.recv_from(buf) { - Ok((len, src_addr)) => match src_addr { - SocketAddr::V4(addr) => (len, addr), - SocketAddr::V6(_) => { - continue; - } + SocketAddr::V6(_) => {} }, Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - break; - } - log::error!("接收数据失败:{:?}", e); - break; - } - }; - if let Some((dest_udp, time)) = udp_map.get_mut(&src_addr) { - //发送失败就当丢包了 - let _ = dest_udp.send(&buf[..len]); - *time = Instant::now(); - } else if let Some(dest_addr) = nat_map.lock().get(&src_addr).cloned() { - if token_map.len() >= NAT_MAX { - log::error!( - "UDP NAT_MAX:src_addr={:?},dest_addr={:?}", - src_addr, - dest_addr - ); - continue; + log::warn!("udp代理异常:{:?}", e); } - match udp_connect(src_addr.port(), dest_addr.into()) { - Ok((token_val, mut dest_udp)) => { - let token = Token(token_val); - if let Err(e) = registry.register(&mut dest_udp, token, Interest::READABLE) { - log::error!("register失败:{:?},addr={:?}", e, dest_addr); - continue; - } - let _ = dest_udp.send(&buf[..len]); - let dest_udp = Rc::new(dest_udp); - token_map.insert(token, (dest_udp.clone(), src_addr, Instant::now())); - udp_map.insert(src_addr, (dest_udp, Instant::now())); - } - Err(e) => { - log::error!("绑定目标地址失败:{:?}", e); - continue; - } - }; - } - } -} - -/// 得到一个 fd不为SERVER_VAL或者NOTYFY_VAL的socket -fn udp_connect(src_port: u16, addr: SocketAddr) -> io::Result<(usize, UdpSocket)> { - loop { - let udp = if let Ok(udp) = - UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into()) - { - udp - } else { - UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())? }; - #[cfg(windows)] - let fd = udp.as_raw_socket() as usize; - #[cfg(unix)] - let fd = udp.as_raw_fd() as usize; - if fd == SERVER_VAL || fd == NOTIFY_VAL { - continue; - } - // 只接收目标的数据 - udp.connect(addr)?; - return Ok((fd, udp)); } } -fn readable_handle( - udp: &UdpSocket, - token_map: &mut HashMap, SocketAddrV4, Instant)>, - token: &Token, - buf: &mut [u8], +async fn udp_proxy0( + buf: &[u8], + sender_addr: SocketAddrV4, + inner_map: &Arc, Arc>)>>>, + map: &Arc>>, + udp_socket: &Arc, ) -> io::Result<()> { - if let Some((dest_udp, src_addr, time)) = token_map.get_mut(&token) { - loop { - let len = match dest_udp.recv(buf) { - Ok(rs) => rs, - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - break; + let option = inner_map.lock().get(&sender_addr).cloned(); + if let Some((udp, time)) = option { + time.store(Instant::now()); + udp.send(buf).await?; + } else { + let option = map.lock().get(&sender_addr).cloned(); + if let Some(dest_addr) = option { + //先使用相同的端口,冲突了再随机端口 + let peer_udp_socket = + match UdpSocket::bind(format!("0.0.0.0:{}", sender_addr.port())).await { + Ok(udp) => udp, + Err(_) => UdpSocket::bind("0.0.0.0:0").await?, + }; + peer_udp_socket.connect(dest_addr).await?; + peer_udp_socket.send(buf).await?; + let peer_udp_socket = Arc::new(peer_udp_socket); + let inner_map = inner_map.clone(); + let time = Arc::new(AtomicCell::new(Instant::now())); + inner_map + .lock() + .insert(sender_addr, (peer_udp_socket.clone(), time.clone())); + let udp_socket = udp_socket.clone(); + let map = map.clone(); + tokio::spawn(async move { + let mut buf = [0u8; 65536]; + loop { + match tokio::time::timeout( + Duration::from_secs(600), + peer_udp_socket.recv(&mut buf), + ) + .await + { + Ok(rs) => match rs { + Ok(len) => match udp_socket.send_to(&buf[..len], sender_addr).await { + Ok(_) => {} + Err(e) => { + log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e); + break; + } + }, + Err(e) => { + log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e); + + break; + } + }, + Err(_) => { + if time.load().elapsed() > Duration::from_secs(580) { + //超时关闭 + log::warn!("udp proxy timeout {}->{}", sender_addr, dest_addr); + break; + } + } } - return Err(e); } - }; - if len == 0 { - return Err(io::Error::from(io::ErrorKind::UnexpectedEof)); - } - - let _ = udp.send_to(&buf[..len], (*src_addr).into()); + inner_map.lock().remove(&sender_addr); + map.lock().remove(&sender_addr); + }); } - *time = Instant::now(); } Ok(()) } From d3dce7a3cc233253fba6ee82f7ea1fcbf54aa2f5 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Wed, 8 May 2024 20:20:09 +0800 Subject: [PATCH 05/22] =?UTF-8?q?=E8=B0=83=E6=95=B4stun=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/nat/mod.rs | 5 ++- vnt/src/nat/stun.rs | 98 +++++++++++++++++++++------------------------ 2 files changed, 48 insertions(+), 55 deletions(-) diff --git a/vnt/src/nat/mod.rs b/vnt/src/nat/mod.rs index ddecc75b..ca28b053 100644 --- a/vnt/src/nat/mod.rs +++ b/vnt/src/nat/mod.rs @@ -89,8 +89,9 @@ impl NatTest { udp_ports: Vec, tcp_port: u16, ) -> NatTest { - let server = stun_server[0].clone(); - stun_server.resize(3, server); + if stun_server.len() > 5 { + stun_server.truncate(5); + } let ports = vec![0; udp_ports.len()]; let nat_info = NatInfo::new( Vec::new(), diff --git a/vnt/src/nat/stun.rs b/vnt/src/nat/stun.rs index fc6cf7f4..08b5cba6 100644 --- a/vnt/src/nat/stun.rs +++ b/vnt/src/nat/stun.rs @@ -1,11 +1,12 @@ use std::collections::HashSet; use std::io; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::time::Duration; use crate::channel::punch::NatType; use std::net::UdpSocket; use stun_format::Attr; + pub fn stun_test_nat(stun_servers: Vec) -> io::Result<(NatType, Vec, u16)> { let mut th = Vec::new(); for _ in 0..2 { @@ -36,26 +37,19 @@ pub fn stun_test_nat(stun_servers: Vec) -> io::Result<(NatType, Vec) -> io::Result<(NatType, Vec, u16)> { let udp = UdpSocket::bind("0.0.0.0:0")?; udp.set_read_timeout(Some(Duration::from_millis(500)))?; let mut nat_type = NatType::Cone; - let mut port_range = 0; + let mut min_port = u16::MAX; + let mut max_port = 0; let mut hash_set = HashSet::new(); let mut pub_addrs = HashSet::new(); for x in &stun_servers { match test_nat(&udp, x) { - Ok((addr, nat_type_t, ip_list_t, port_range_t)) => { - if nat_type_t == NatType::Symmetric { - nat_type = NatType::Symmetric; - } - for x in ip_list_t { - hash_set.insert(x); - } - if port_range < port_range_t { - port_range = port_range_t; - } - pub_addrs.insert(addr); + Ok(addr) => { + pub_addrs.extend(addr); } Err(e) => { log::warn!("stun {} error {:?} ", x, e); @@ -65,57 +59,55 @@ pub fn stun_test_nat0(stun_servers: Vec) -> io::Result<(NatType, Vec 1 { nat_type = NatType::Symmetric; } - Ok((nat_type, hash_set.into_iter().collect(), port_range)) + for addr in &pub_addrs { + if let SocketAddr::V4(addr) = addr { + hash_set.insert(*addr.ip()); + if min_port > addr.port() { + min_port = addr.port() + } + if max_port < addr.port() { + max_port = addr.port() + } + } + } + Ok(( + nat_type, + hash_set.into_iter().collect(), + max_port - min_port, + )) } -fn test_nat( - udp: &UdpSocket, - stun_server: &String, -) -> io::Result<(SocketAddr, NatType, Vec, u16)> { +fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result> { udp.connect(stun_server)?; - let mut port_range = 0; - let mut hash_set = HashSet::new(); - let mut nat_type = NatType::Cone; // 随便搞个当id let tid = stun_server.as_ptr() as u128; + let mut addr = HashSet::new(); let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?; - match mapped_addr1.ip() { - IpAddr::V4(ip) => { - hash_set.insert(ip); - } - IpAddr::V6(_) => {} + if mapped_addr1.is_ipv4() { + addr.insert(mapped_addr1); } - if udp.connect(changed_addr1).is_ok() { - match test_nat_(&udp, false, false, tid + 1) { - Ok((mapped_addr2, _)) => { - match mapped_addr2.ip() { - IpAddr::V4(ip) => { - hash_set.insert(ip); - if mapped_addr1 != mapped_addr2 { - nat_type = NatType::Symmetric; - } + if let Some(changed_addr1) = changed_addr1 { + if udp.connect(changed_addr1).is_ok() { + match test_nat_(&udp, false, false, tid + 1) { + Ok((mapped_addr2, _)) => { + if mapped_addr2.is_ipv4() { + addr.insert(mapped_addr1); } - IpAddr::V6(_) => {} } - port_range = mapped_addr2.port().abs_diff(mapped_addr1.port()); - } - Err(e) => { - log::warn!("stun {} error {:?} ", stun_server, e); + Err(e) => { + log::warn!("stun {} error {:?} ", stun_server, e); + } } } } - log::warn!( - "stun {} mapped_addr {:?} nat_type {:?}", + log::info!( + "stun {} mapped_addr {:?} changed_addr {:?}", stun_server, - mapped_addr1, - nat_type + addr, + changed_addr1, ); - Ok(( - mapped_addr1, - nat_type, - hash_set.into_iter().collect(), - port_range, - )) + + Ok(addr) } fn test_nat_( @@ -123,7 +115,7 @@ fn test_nat_( change_ip: bool, change_port: bool, tid: u128, -) -> io::Result<(SocketAddr, SocketAddr)> { +) -> io::Result<(SocketAddr, Option)> { for _ in 0..2 { let mut buf = [0u8; 28]; let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice()); @@ -166,11 +158,11 @@ fn test_nat_( _ => {} } if changed_addr.is_some() && mapped_addr.is_some() { - return Ok((mapped_addr.unwrap(), changed_addr.unwrap())); + return Ok((mapped_addr.unwrap(), changed_addr)); } } if let Some(addr) = mapped_addr { - return Ok((addr, changed_addr.unwrap_or(addr))); + return Ok((addr, changed_addr)); } } Err(io::Error::new(io::ErrorKind::Other, "stun response err")) From 607c8c2e9f52fb48d0642bbb6875cd80a3deb64f Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Wed, 8 May 2024 21:31:21 +0800 Subject: [PATCH 06/22] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-cli/Cargo.toml | 17 +-- vnt-cli/README.md | 27 ++++- vnt-cli/src/config/mod.rs | 8 +- vnt-cli/src/main.rs | 19 +++- .../java/top/wherewego/vnt/jni/Config.java | 11 ++ vnt-jni/src/config.rs | 4 +- vnt/src/core/conn.rs | 16 ++- vnt/src/core/mod.rs | 9 ++ vnt/src/lib.rs | 2 + vnt/src/port_mapping/mod.rs | 97 ++++++++++++++++ vnt/src/port_mapping/tcp_mapping.rs | 49 ++++++++ vnt/src/port_mapping/udp_mapping.rs | 107 ++++++++++++++++++ 12 files changed, 342 insertions(+), 24 deletions(-) create mode 100644 vnt/src/port_mapping/mod.rs create mode 100644 vnt/src/port_mapping/tcp_mapping.rs create mode 100644 vnt/src/port_mapping/udp_mapping.rs diff --git a/vnt-cli/Cargo.toml b/vnt-cli/Cargo.toml index e6d11932..80eede16 100644 --- a/vnt-cli/Cargo.toml +++ b/vnt-cli/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -vnt = { path = "../vnt", package = "vnt",default-features = false } +vnt = { path = "../vnt", package = "vnt", default-features = false } common = { path = "../common" } getopts = "0.2.21" console = "0.15.2" @@ -28,16 +28,17 @@ sudo = "0.6.0" winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] } [features] -default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc","ip_proxy"] +default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping"] openssl = ["vnt/openssl"] openssl-vendored = ["vnt/openssl-vendored"] ring-cipher = ["vnt/ring-cipher"] -aes_cbc=["vnt/aes_cbc"] -aes_ecb=["vnt/aes_ecb"] -sm4_cbc=["vnt/sm4_cbc"] -aes_gcm=["vnt/aes_gcm"] -server_encrypt=["vnt/server_encrypt"] -ip_proxy=["vnt/ip_proxy"] +aes_cbc = ["vnt/aes_cbc"] +aes_ecb = ["vnt/aes_ecb"] +sm4_cbc = ["vnt/sm4_cbc"] +aes_gcm = ["vnt/aes_gcm"] +server_encrypt = ["vnt/server_encrypt"] +ip_proxy = ["vnt/ip_proxy"] +port_mapping = ["vnt/port_mapping"] [build-dependencies] embed-manifest = "1.4.0" rand = "0.8.5" diff --git a/vnt-cli/README.md b/vnt-cli/README.md index 026bac95..52da0e00 100644 --- a/vnt-cli/README.md +++ b/vnt-cli/README.md @@ -10,7 +10,7 @@ ### -c 关闭控制台交互式命令,后台运行时可以加此参数 ### -s `` -注册和中继服务器地址,注册和转发数据 +注册和中继服务器地址,注册和转发数据,以'TXT:'开头表示解析TXT记录,TXT记录内容必须是'host:port'形式的服务器地址 ### -e `` 使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略 ### -a @@ -72,9 +72,9 @@ 注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数 ### --punch `` -取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两则都会使用 +取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两者都会使用 ### --ports `` -指定本地监听的端口组,多个端口使用逗号分隔,多个端口可以分摊流量,增加并发,tcp会监听端口组的第一个端口,用于tcp直连 +指定本地监听的端口组,多个端口使用逗号分隔,多个端口可以分摊流量,增加并发、减缓流量限制,tcp会监听端口组的第一个端口,用于tcp直连 - 例1:‘--ports 12345,12346,12347’ 表示udp监听12345、12346、12347这三个端口,tcp监听12345端口 - 例2:‘--ports 0,0’ 表示udp监听两个未使用的端口,tcp监听一个未使用的端口 @@ -85,6 +85,14 @@ ### --no-proxy 关闭内置的ip代理,内置的代理较为简单,而且一般来说直接使用网卡NAT转发性能会更高, 有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/lbl8603/vnt#%E7%BC%96%E8%AF%91) +### --dns `<223.5.5.5>` +设置域名解析服务器地址,可以设置多个。如果使用TXT记录的域名,则dns默认使用223.5.5.5和114.114.114.114,端口省略值为53 + +当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果 + +### --mapping `10.26.0.10:80>` +端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.11:81' +表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口 ### -f `` 指定配置文件 配置文件采用yaml格式,可参考: @@ -111,7 +119,7 @@ server_encrypt: true #服务端加密 parallel: 1 #任务并行度 cipher_model: aes_gcm #客户端加密算法 finger: false #关闭数据指纹 -punch_model: ipv4 #打洞模式 +punch_model: ipv4 #打洞模式,表示只使用ipv4地址打洞,默认会同时使用v6和v4 ports: - 0 #使用随机端口,tcp监听此端口 - 0 @@ -122,7 +130,12 @@ device_name: vnt-tun #网卡名称 packet_loss: 0 #指定丢包率 取值0~1之间的数 用于模拟弱网 packet_delay: 0 #指定延迟 单位毫秒 用于模拟弱网 dns: - - 8.8.8.8:53 + - 223.5.5.5 # 首选dns + - 8.8.8.8 # 备选dns +mapping: + - udp:0.0.0.0:80->10.26.0.10:80 # 映射udp数据 + - tcp:0.0.0.0:80->10.26.0.10:81 # 映射tcp数据 + - tcp:0.0.0.0:82->localhost:83 # 映射tcp数据 ``` 或者需要哪个配置就加哪个,当然token是必须的 @@ -134,7 +147,9 @@ token: xxx #组网token - relay:仅中继模式,会禁止打洞/p2p直连,只使用服务器转发 - p2p:仅直连模式,会禁止网络数据从服务器/客户端转发,只会使用服务器转发控制包 ### --packet-loss `<0>` -模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境会有帮助。 +模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境时会有帮助。 +### --packet-delay `<0>` +模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网 ### --list 在后台运行时,查看其他设备列表 diff --git a/vnt-cli/src/config/mod.rs b/vnt-cli/src/config/mod.rs index 4c426952..3d9dfff1 100644 --- a/vnt-cli/src/config/mod.rs +++ b/vnt-cli/src/config/mod.rs @@ -40,6 +40,8 @@ pub struct FileConfig { pub device_name: Option, pub packet_loss: Option, pub packet_delay: u32, + #[cfg(feature = "port_mapping")] + pub mapping: Vec, } impl Default for FileConfig { @@ -54,7 +56,7 @@ impl Default for FileConfig { stun_server: vec![ "stun1.l.google.com:19302".to_string(), "stun2.l.google.com:19302".to_string(), - "stun.qq.com:3478".to_string(), + "stun.miwifi.com:3478".to_string(), ], dns: vec![], in_ips: vec![], @@ -77,6 +79,8 @@ impl Default for FileConfig { device_name: None, packet_loss: None, packet_delay: 0, + #[cfg(feature = "port_mapping")] + mapping: vec![], } } } @@ -157,6 +161,8 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { use_channel_type, file_conf.packet_loss, file_conf.packet_delay, + #[cfg(feature = "port_mapping")] + file_conf.mapping, ) .unwrap(); Ok((config, file_conf.cmd)) diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs index 7b42ef39..3f1c0c44 100644 --- a/vnt-cli/src/main.rs +++ b/vnt-cli/src/main.rs @@ -73,6 +73,7 @@ fn main() { opts.optopt("", "packet-loss", "丢包率", ""); opts.optopt("", "packet-delay", "延迟", ""); opts.optmulti("", "dns", "dns", ""); + opts.optmulti("", "mapping", "mapping", ""); opts.optopt("f", "", "配置文件", ""); //"后台运行时,查看其他设备列表" opts.optflag("", "list", "后台运行时,查看其他设备列表"); @@ -156,7 +157,7 @@ fn main() { if stun_server.is_empty() { stun_server.push("stun1.l.google.com:19302".to_string()); stun_server.push("stun2.l.google.com:19302".to_string()); - stun_server.push("stun.qq.com:3478".to_string()); + stun_server.push("stun.miwifi.com:3478".to_string()); } let dns = matches.opt_strs("dns"); let in_ip = matches.opt_strs("i"); @@ -287,6 +288,8 @@ fn main() { .opt_get::("packet-delay") .expect("--packet-delay") .unwrap_or(0); + #[cfg(feature = "port_mapping")] + let port_mapping_list = matches.opt_strs("mapping"); let config = match Config::new( #[cfg(any(target_os = "windows", target_os = "linux"))] tap, @@ -315,6 +318,8 @@ fn main() { use_channel_type, packet_loss, packet_delay, + #[cfg(feature = "port_mapping")] + port_mapping_list, ) { Ok(config) => config, Err(e) => { @@ -338,6 +343,14 @@ fn main() { mod callback; fn main0(config: Config, show_cmd: bool) { + #[cfg(feature = "port_mapping")] + for (is_tcp, addr, dest) in config.port_mapping_list.iter() { + if *is_tcp { + println!("TCP port mapping {}->{}", addr, dest) + } else { + println!("UDP port mapping {}->{}", addr, dest) + } + } let vnt_util = Vnt::new(config, callback::VntHandler {}).unwrap(); let vnt_c = vnt_util.clone(); thread::Builder::new() @@ -412,7 +425,7 @@ fn print_usage(program: &str, _opts: Options) { println!(" -n 给设备一个名字,便于区分不同设备,默认使用系统版本"); println!(" -d 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复"); println!(" -s 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录"); - println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.qq.com -e stun1.l.google.com"); + println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com"); println!(" -a 使用tap模式,默认使用tun模式"); println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); println!(" 并转发到10.26.0.3,可指定多个网段"); @@ -475,6 +488,8 @@ fn print_usage(program: &str, _opts: Options) { " --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网" ); println!(" --dns DNS服务器地址,可使用多个dns,不指定时使用系统解析"); + #[cfg(feature = "port_mapping")] + println!(" --mapping 端口映射,例如 --mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.10:80"); println!(); println!( diff --git a/vnt-jni/java/top/wherewego/vnt/jni/Config.java b/vnt-jni/java/top/wherewego/vnt/jni/Config.java index 4fd3abc4..342127dc 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/Config.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/Config.java @@ -54,6 +54,10 @@ public class Config { * dns地址 */ private String[] dns; + /** + * 端口映射 + */ + private String[] portMapping; /** * stun服务地址 */ @@ -201,6 +205,13 @@ public String[] getDns() { public void setDns(String[] dns) { this.dns = dns; } + public String[] getPortMapping() { + return portMapping; + } + + public void setPortMapping(String[] portMapping) { + this.portMapping = portMapping; + } public String[] getStunServer() { return stunServer; diff --git a/vnt-jni/src/config.rs b/vnt-jni/src/config.rs index 3afd5fee..eb1db2d7 100644 --- a/vnt-jni/src/config.rs +++ b/vnt-jni/src/config.rs @@ -21,6 +21,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { let server_address_str = to_string_not_null(env, &config, "server")?; let stun_server = to_string_array_not_null(env, &config, "stunServer")?; let dns = to_string_array(env, &config, "dns")?.unwrap_or_else(|| vec![]); + let port_mapping = to_string_array(env, &config, "portMapping")?.unwrap_or_else(|| vec![]); let cipher_model = to_string_not_null(env, &config, "cipherModel")?; let punch_model = to_string(env, &config, "punchModel")?; let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32); @@ -116,12 +117,13 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(), packet_loss_rate, packet_delay, + port_mapping, ) { Ok(config) => config, Err(e) => { env.throw_new( "java/lang/RuntimeException", - format!("vnt start error {}", e), + format!("vnt start error {:?}", e), ) .expect("throw"); return Err(Error::JavaException); diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 9bd965c4..e51600ab 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -93,6 +93,16 @@ impl Vnt { config.server_address_str.clone(), config.name_servers.clone(), ); + // 服务停止管理器 + let stop_manager = { + let callback = callback.clone(); + StopManager::new(move || callback.stop()) + }; + #[cfg(feature = "port_mapping")] + crate::port_mapping::start_port_mapping( + stop_manager.clone(), + config.port_mapping_list.clone(), + )?; let ports = config.ports.as_ref().map_or(vec![0, 0], |v| { if v.is_empty() { vec![0, 0] @@ -131,11 +141,6 @@ impl Vnt { callback.create_tun(tun_info); device }; - // 服务停止管理器 - let stop_manager = { - let callback = callback.clone(); - StopManager::new(move || callback.stop()) - }; // 定时器 let scheduler = Scheduler::new(stop_manager.clone())?; let external_route = ExternalRoute::new(config.in_ips.clone()); @@ -145,7 +150,6 @@ impl Vnt { let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy { Some(crate::ip_proxy::init_proxy( context.clone(), - scheduler.clone(), stop_manager.clone(), current_device.clone(), client_cipher.clone(), diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index d45e446f..39598979 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -43,6 +43,9 @@ pub struct Config { //控制丢包率 pub packet_loss_rate: Option, pub packet_delay: u32, + // 端口映射 + #[cfg(feature = "port_mapping")] + pub port_mapping_list: Vec<(bool, SocketAddr, String)>, } impl Config { @@ -72,6 +75,8 @@ impl Config { use_channel_type: UseChannelType, packet_loss_rate: Option, packet_delay: u32, + // 例如 [udp:127.0.0.1:80->10.26.0.10:8080,tcp:127.0.0.1:80->10.26.0.10:8080] + #[cfg(feature = "port_mapping")] port_mapping_list: Vec, ) -> anyhow::Result { for x in stun_server.iter_mut() { if !x.contains(":") { @@ -96,6 +101,8 @@ impl Config { } let server_address = address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?; + #[cfg(feature = "port_mapping")] + let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?; Ok(Self { #[cfg(any(target_os = "windows", target_os = "linux"))] tap, @@ -126,6 +133,8 @@ impl Config { use_channel_type, packet_loss_rate, packet_delay, + #[cfg(feature = "port_mapping")] + port_mapping_list, }) } } diff --git a/vnt/src/lib.rs b/vnt/src/lib.rs index 92ae669a..a159e14b 100644 --- a/vnt/src/lib.rs +++ b/vnt/src/lib.rs @@ -8,6 +8,8 @@ pub mod handle; #[cfg(feature = "ip_proxy")] pub mod ip_proxy; pub mod nat; +#[cfg(feature = "port_mapping")] +pub mod port_mapping; pub mod proto; pub mod protocol; pub mod tun_tap_device; diff --git a/vnt/src/port_mapping/mod.rs b/vnt/src/port_mapping/mod.rs new file mode 100644 index 00000000..9573311c --- /dev/null +++ b/vnt/src/port_mapping/mod.rs @@ -0,0 +1,97 @@ +use std::net::SocketAddr; +use std::str::FromStr; +use std::thread; + +use anyhow::Context; + +use crate::util::StopManager; + +mod tcp_mapping; + +mod udp_mapping; + +pub fn convert(vec: Vec) -> anyhow::Result> { + let mut rs = Vec::with_capacity(vec.len()); + for x in vec { + let string = x.trim().to_lowercase(); + if let Some(udp_mapping) = string.strip_prefix("udp:") { + let mut split = udp_mapping.split("->"); + let bind_addr = split.next().with_context(|| { + format!( + "udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080", + x + ) + })?; + let bind_addr = SocketAddr::from_str(bind_addr) + .with_context(|| format!("udp_mapping error {}", bind_addr))?; + let dest = split.next().with_context(|| { + format!( + "udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080", + x + ) + })?; + rs.push((false, bind_addr, dest.to_string())); + continue; + } + if let Some(tcp_mapping) = string.strip_prefix("tcp:") { + let mut split = tcp_mapping.split("->"); + let bind_addr = split.next().with_context(|| { + format!( + "tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080", + x + ) + })?; + let bind_addr = SocketAddr::from_str(bind_addr) + .with_context(|| format!("udp_mapping error {}", bind_addr))?; + let dest = split.next().with_context(|| { + format!( + "tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080", + x + ) + })?; + rs.push((true, bind_addr, dest.to_string())); + continue; + } + Err(anyhow::anyhow!( + "port_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080", + x + ))?; + } + Ok(rs) +} +pub fn start_port_mapping( + stop_manager: StopManager, + vec: Vec<(bool, SocketAddr, String)>, +) -> anyhow::Result<()> { + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .thread_name("portMapping") + .build()?; + runtime.block_on(start_port_mapping0(vec))?; + let (sender, receiver) = tokio::sync::oneshot::channel::<()>(); + let worker = stop_manager.add_listener("portMapping".into(), move || { + let _ = sender.send(()); + })?; + thread::Builder::new() + .name("portMapping".into()) + .spawn(move || { + runtime.block_on(async { + let _ = receiver.await; + }); + runtime.shutdown_background(); + drop(worker); + })?; + + Ok(()) +} + +async fn start_port_mapping0(vec: Vec<(bool, SocketAddr, String)>) -> anyhow::Result<()> { + for (is_tcp, bind_addr, destination) in vec { + if is_tcp { + tcp_mapping::tcp_mapping(bind_addr, destination).await?; + } else { + udp_mapping::udp_mapping(bind_addr, destination).await?; + } + } + Ok(()) +} diff --git a/vnt/src/port_mapping/tcp_mapping.rs b/vnt/src/port_mapping/tcp_mapping.rs new file mode 100644 index 00000000..32a717b6 --- /dev/null +++ b/vnt/src/port_mapping/tcp_mapping.rs @@ -0,0 +1,49 @@ +use anyhow::Context; +use std::net::SocketAddr; +use tokio::net::{TcpListener, TcpStream}; + +pub async fn tcp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> { + let tcp_listener = TcpListener::bind(bind_addr) + .await + .with_context(|| format!("TCP binding {:?} failed", bind_addr))?; + tokio::spawn(tcp_mapping_(bind_addr, tcp_listener, destination)); + Ok(()) +} + +async fn tcp_mapping_( + bind_addr: SocketAddr, + tcp_listener: TcpListener, + destination: String, +) -> anyhow::Result<()> { + loop { + let (tcp_stream, _) = tcp_listener.accept().await?; + + let destination = destination.clone(); + tokio::spawn(async move { + if let Err(e) = copy(tcp_stream, &destination).await { + log::warn!("tcp port mapping {}->{} {:?}", bind_addr, destination, e); + } + }); + } +} + +async fn copy(source_tcp: TcpStream, destination: &String) -> anyhow::Result<()> { + let dest_tcp = TcpStream::connect(destination) + .await + .with_context(|| format!("TCP connection target failed {:?}", destination))?; + let _ = source_tcp.set_nodelay(true); + let _ = dest_tcp.set_nodelay(true); + + let destination = dest_tcp.peer_addr()?; + let (mut client_read, mut client_write) = source_tcp.into_split(); + let (mut server_read, mut server_write) = dest_tcp.into_split(); + tokio::spawn(async move { + if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await { + log::warn!("client tcp proxy ->{:},{:?}", destination, e); + } + }); + if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await { + log::warn!("server tcp proxy ->{:?},{:?}", destination, e); + } + Ok(()) +} diff --git a/vnt/src/port_mapping/udp_mapping.rs b/vnt/src/port_mapping/udp_mapping.rs new file mode 100644 index 00000000..56d88930 --- /dev/null +++ b/vnt/src/port_mapping/udp_mapping.rs @@ -0,0 +1,107 @@ +use anyhow::Context; +use crossbeam_utils::atomic::AtomicCell; +use parking_lot::Mutex; +use std::collections::HashMap; +use std::net::SocketAddr; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use tokio::net::UdpSocket; + +pub async fn udp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> { + let udp = UdpSocket::bind(bind_addr) + .await + .with_context(|| format!("port proxy UDP binding {:?} failed", bind_addr))?; + let udp = Arc::new(udp); + + let inner_map: Arc, Arc>)>>> = + Arc::new(Mutex::new(HashMap::with_capacity(64))); + + tokio::spawn(async move { + let mut buf = [0; 65536]; + loop { + match udp.recv_from(&mut buf).await { + Ok((len, src_addr)) => { + if let Err(e) = + udp_mapping0(&buf[..len], src_addr, &inner_map, &udp, &destination).await + { + log::warn!("udp port mapping {}->{} {:?}", src_addr, destination, e); + } + } + Err(e) => { + log::warn!("port proxy UDP {:?}", e); + } + } + } + }); + Ok(()) +} + +async fn udp_mapping0( + buf: &[u8], + src_addr: SocketAddr, + inner_map: &Arc, Arc>)>>>, + udp_socket: &Arc, + destination: &String, +) -> anyhow::Result<()> { + let option = inner_map.lock().get(&src_addr).cloned(); + if let Some((udp, time)) = option { + time.store(Instant::now()); + udp.send(buf).await?; + } else { + let dest_udp = UdpSocket::bind("0.0.0.0:0").await?; + dest_udp.connect(destination).await?; + dest_udp.send(buf).await?; + let destination_addr = dest_udp.peer_addr()?; + let udp_socket = udp_socket.clone(); + let inner_map = inner_map.clone(); + let dest_udp = Arc::new(dest_udp); + let time = Arc::new(AtomicCell::new(Instant::now())); + inner_map + .lock() + .insert(src_addr, (dest_udp.clone(), time.clone())); + tokio::spawn(async move { + let mut buf = [0u8; 65536]; + loop { + match tokio::time::timeout(Duration::from_secs(600), dest_udp.recv(&mut buf)).await + { + Ok(rs) => match rs { + Ok(len) => match udp_socket.send_to(&buf[..len], src_addr).await { + Ok(_) => {} + Err(e) => { + log::warn!( + "udp port mapping {}->{} {:?}", + src_addr, + destination_addr, + e + ); + break; + } + }, + Err(e) => { + log::warn!( + "udp port mapping {}->{} {:?}", + src_addr, + destination_addr, + e + ); + break; + } + }, + Err(_) => { + if time.load().elapsed() > Duration::from_secs(580) { + //超时关闭 + log::warn!( + "udp port mapping timeout {}->{} ", + src_addr, + destination_addr + ); + break; + } + } + } + } + inner_map.lock().remove(&src_addr); + }); + } + Ok(()) +} From be767ae300b8efc85ea959d82960bcc798f6b5a5 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Wed, 8 May 2024 23:58:03 +0800 Subject: [PATCH 07/22] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/src/args_parse.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common/src/args_parse.rs b/common/src/args_parse.rs index fe62350c..9f3ff017 100644 --- a/common/src/args_parse.rs +++ b/common/src/args_parse.rs @@ -7,33 +7,33 @@ pub fn ips_parse(ips: &Vec) -> Result, String> let net = if let Some(net) = split.next() { net } else { - return Err("ipv4/mask,ipv4".to_string()); + return Err(format!("ipv4/mask,ipv4 {:?}", x)); }; let ip = if let Some(ip) = split.next() { ip } else { - return Err("ipv4/mask,ipv4".to_string()); + return Err(format!("ipv4/mask,ipv4 {:?}", x)); }; let ip = if let Ok(ip) = ip.parse::() { ip } else { - return Err("not ipv4".to_string()); + return Err(format!("not ipv4 {:?}", ip)); }; let mut split = net.split("/"); let dest = if let Some(dest) = split.next() { dest } else { - return Err("no ipv4/mask".to_string()); + return Err(format!("no ipv4/mask {:?}", net)); }; let mask = if let Some(mask) = split.next() { mask } else { - return Err("no netmask".to_string()); + return Err(format!("no netmask {:?}", net)); }; let dest = if let Ok(dest) = dest.parse::() { dest } else { - return Err("not ipv4".to_string()); + return Err(format!("not ipv4 {:?}", dest)); }; let mask = to_ip(mask)?; in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip)); @@ -48,17 +48,17 @@ pub fn out_ips_parse(ips: &Vec) -> Result, String> { let dest = if let Some(dest) = split.next() { dest } else { - return Err("no ipv4/mask".to_string()); + return Err(format!("no ipv4/mask {:?}", x)); }; let mask = if let Some(mask) = split.next() { mask } else { - return Err("no netmask".to_string()); + return Err(format!("no netmask {:?}", x)); }; let dest = if let Ok(dest) = dest.parse::() { dest } else { - return Err("not ipv4".to_string()); + return Err(format!("not ipv4 {:?}", dest)); }; let mask = to_ip(mask)?; in_ips_c.push((u32::from_be_bytes(dest.octets()), mask)); From b57a38e81e776a207f6265cda7a38d2c8fdc7e80 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Wed, 8 May 2024 23:58:38 +0800 Subject: [PATCH 08/22] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B6=85=E6=97=B6?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-jni/java/top/wherewego/vnt/jni/Vnt.java | 8 +++++++- vnt-jni/src/vnt.rs | 13 ++++++++++++- vnt/src/core/conn.rs | 3 +++ vnt/src/handle/tun_tap/tun_handler.rs | 7 +++++-- vnt/src/util/notify.rs | 16 ++++++++++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java b/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java index a2bd45ac..e931a562 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java @@ -11,7 +11,7 @@ public class Vnt implements Closeable { private final long raw; - public Vnt(Config config, CallBack callBack) throws Exception{ + public Vnt(Config config, CallBack callBack) throws Exception { this.raw = new0(config, callBack); if (this.raw == 0) { throw new RuntimeException(); @@ -26,6 +26,10 @@ public void await() { wait0(raw); } + public boolean awaitTimeout(long ms) { + return waitTimeout0(raw, ms); + } + public PeerRouteInfo[] list() { return list0(raw); } @@ -36,6 +40,8 @@ public PeerRouteInfo[] list() { private native void wait0(long raw); + private native boolean waitTimeout0(long raw, long ms); + private native void drop0(long raw); private native PeerRouteInfo[] list0(long raw); diff --git a/vnt-jni/src/vnt.rs b/vnt-jni/src/vnt.rs index d1a01961..03fe4c5f 100644 --- a/vnt-jni/src/vnt.rs +++ b/vnt-jni/src/vnt.rs @@ -1,8 +1,9 @@ use std::ptr; +use std::time::Duration; use jni::errors::Error; use jni::objects::{JClass, JObject, JValue}; -use jni::sys::{jint, jlong, jobject, jobjectArray, jsize}; +use jni::sys::{jboolean, jint, jlong, jobject, jobjectArray, jsize}; use jni::JNIEnv; use vnt::channel::Route; @@ -74,6 +75,16 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0( let vnt = raw_vnt as *mut Vnt; let _ = (&*vnt).wait(); } +#[no_mangle] +pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitTimeout0( + _env: JNIEnv, + _class: JClass, + raw_vnt: jlong, + time: jlong, +) -> jboolean { + let vnt = raw_vnt as *mut Vnt; + (&*vnt).wait_timeout(Duration::from_millis(time as _)) as _ +} #[no_mangle] pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0( diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index e51600ab..6feb6b38 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -412,4 +412,7 @@ impl Vnt { pub fn wait(&self) { self.stop_manager.wait() } + pub fn wait_timeout(&self, dur: Duration) -> bool { + self.stop_manager.wait_timeout(dur) + } } diff --git a/vnt/src/handle/tun_tap/tun_handler.rs b/vnt/src/handle/tun_tap/tun_handler.rs index c918b011..bfa18b92 100644 --- a/vnt/src/handle/tun_tap/tun_handler.rs +++ b/vnt/src/handle/tun_tap/tun_handler.rs @@ -86,15 +86,16 @@ pub fn start( mut up_counter: SingleU64Adder, device_list: Arc)>>, ) -> io::Result<()> { + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] let worker = { - #[cfg(any(target_os = "macos", target_os = "android"))] + #[cfg(target_os = "macos")] let current_device = current_device.clone(); let device = device.clone(); stop_manager.add_listener("tun_device".into(), move || { if let Err(e) = device.shutdown() { log::warn!("{:?}", e); } - #[cfg(any(target_os = "macos", target_os = "android"))] + #[cfg(target_os = "macos")] { let ip = current_device.load().virtual_ip; if let Ok(udp) = std::net::UdpSocket::bind("0.0.0.0:0") { @@ -150,6 +151,7 @@ pub fn start( if let Err(e) = start_multi(stop_manager, device, sender, &mut up_counter) { log::warn!("stop:{}", e); } + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] worker.stop_all(); })?; } else { @@ -171,6 +173,7 @@ pub fn start( ) { log::warn!("stop:{}", e); } + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] worker.stop_all(); })?; } diff --git a/vnt/src/util/notify.rs b/vnt/src/util/notify.rs index bc9d2429..5e8ec688 100644 --- a/vnt/src/util/notify.rs +++ b/vnt/src/util/notify.rs @@ -1,6 +1,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread::Thread; +use std::time::Duration; use std::{io, thread}; use parking_lot::Mutex; @@ -31,6 +32,9 @@ impl StopManager { pub fn wait(&self) { self.inner.wait(); } + pub fn wait_timeout(&self, dur: Duration) -> bool { + self.inner.wait_timeout(dur) + } pub fn is_stop(&self) -> bool { self.inner.state.load(Ordering::Acquire) } @@ -103,6 +107,18 @@ impl StopManagerInner { thread::park() } } + fn wait_timeout(&self, dur: Duration) -> bool { + { + let mut guard = self.park_threads.lock(); + guard.push(thread::current()); + drop(guard); + } + if self.worker_num.load(Ordering::Acquire) == 0 { + return true; + } + thread::park_timeout(dur); + self.worker_num.load(Ordering::Acquire) == 0 + } fn stop_call(&self) { if let Some(call) = self.stop_call.lock().take() { call(); From 035ae46ee513a1f51105a0e8dbc6bb1741d06e33 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:07:46 +0800 Subject: [PATCH 09/22] =?UTF-8?q?=E8=BF=87=E6=BB=A4/etc/machine-id?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/src/identifier.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/common/src/identifier.rs b/common/src/identifier.rs index 5a12ae5a..4d3590bc 100644 --- a/common/src/identifier.rs +++ b/common/src/identifier.rs @@ -55,7 +55,10 @@ pub fn get_unique_identifier() -> Option { // 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的 // 唯一标识,而且某些环境没有预装`dmidecode`命令 if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") { - return Some(identifier); + let identifier = identifier.trim(); + if !identifier.is_empty() { + return Some(identifier.to_string()); + } } let output = match Command::new("dmidecode") @@ -70,7 +73,7 @@ pub fn get_unique_identifier() -> Option { }; let result = String::from_utf8_lossy(&output.stdout); - let identifier = result.trim().to_string(); + let identifier = result.trim(); if identifier.is_empty() { None } else { From b61c140c24f0216d790be56aed4939045d28e91e Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:10:17 +0800 Subject: [PATCH 10/22] =?UTF-8?q?=E5=8E=BB=E9=99=A4linux=E4=B8=8Atap?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-cli/README.md | 4 ++- vnt-cli/src/config/mod.rs | 6 ++-- vnt-cli/src/main.rs | 5 +-- vnt-jni/src/config.rs | 4 +-- vnt/src/tun_tap_device/create_device.rs | 12 +++---- vnt/tun/src/linux/device.rs | 45 +++++++------------------ 6 files changed, 29 insertions(+), 47 deletions(-) diff --git a/vnt-cli/README.md b/vnt-cli/README.md index 52da0e00..97c5ea2a 100644 --- a/vnt-cli/README.md +++ b/vnt-cli/README.md @@ -15,6 +15,8 @@ 使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略 ### -a 加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高 + +注意:仅在windows上支持使用tap,用于兼容低版本windows系统(低版本windows不支持wintun) ### --nic `` 指定虚拟网卡名称,默认tun模式使用vnt-tun,tap模式使用vnt-tap ### -i ``、-o `` @@ -98,7 +100,7 @@ 配置文件采用yaml格式,可参考: ```yaml # 全部参数 -tap: false #是否使用tap +tap: false #是否使用tap 仅在windows上支持使用tap token: xxx #组网token device_id: xxx #当前设备id name: windows 11 #当前设备名称 diff --git a/vnt-cli/src/config/mod.rs b/vnt-cli/src/config/mod.rs index 3d9dfff1..0cbe330f 100644 --- a/vnt-cli/src/config/mod.rs +++ b/vnt-cli/src/config/mod.rs @@ -12,7 +12,7 @@ use vnt::core::Config; #[derive(Serialize, Deserialize, Debug)] #[serde(default)] pub struct FileConfig { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] pub tap: bool, pub token: String, pub device_id: String, @@ -47,7 +47,7 @@ pub struct FileConfig { impl Default for FileConfig { fn default() -> Self { Self { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] tap: false, token: "".to_string(), device_id: get_device_id(), @@ -134,7 +134,7 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { let use_channel_type = UseChannelType::from_str(&file_conf.use_channel) .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; let config = Config::new( - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] file_conf.tap, file_conf.token, file_conf.device_id, diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs index 3f1c0c44..e3611c66 100644 --- a/vnt-cli/src/main.rs +++ b/vnt-cli/src/main.rs @@ -131,7 +131,7 @@ fn main() { println!("parameter -k not found ."); return; } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] let tap = matches.opt_present("a"); let device_name = matches.opt_str("nic"); let token: String = matches.opt_get("k").unwrap().unwrap(); @@ -291,7 +291,7 @@ fn main() { #[cfg(feature = "port_mapping")] let port_mapping_list = matches.opt_strs("mapping"); let config = match Config::new( - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] tap, token, device_id, @@ -426,6 +426,7 @@ fn print_usage(program: &str, _opts: Options) { println!(" -d 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复"); println!(" -s 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录"); println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com"); + #[cfg(target_os = "windows")] println!(" -a 使用tap模式,默认使用tun模式"); println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); println!(" 并转发到10.26.0.3,可指定多个网段"); diff --git a/vnt-jni/src/config.rs b/vnt-jni/src/config.rs index eb1db2d7..2a94cab1 100644 --- a/vnt-jni/src/config.rs +++ b/vnt-jni/src/config.rs @@ -12,7 +12,7 @@ use vnt::core::Config; use crate::utils::*; pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] let tap = env.get_field(&config, "tap", "Z")?.z()?; let token = to_string_not_null(env, &config, "token")?; let name = to_string_not_null(env, &config, "name")?; @@ -90,7 +90,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { #[cfg(not(target_os = "android"))] let device_name = to_string(env, &config, "deviceName")?; let config = match Config::new( - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] tap, token, device_id, diff --git a/vnt/src/tun_tap_device/create_device.rs b/vnt/src/tun_tap_device/create_device.rs index 30a904f2..5b6fd4e5 100644 --- a/vnt/src/tun_tap_device/create_device.rs +++ b/vnt/src/tun_tap_device/create_device.rs @@ -5,12 +5,12 @@ use tun::Device; #[cfg(any(target_os = "windows", target_os = "linux"))] const DEFAULT_TUN_NAME: &str = "vnt-tun"; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(target_os = "windows")] const DEFAULT_TAP_NAME: &str = "vnt-tap"; #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] pub fn create_device(config: &crate::core::Config) -> io::Result> { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] let default_name: &str = if config.tap { DEFAULT_TAP_NAME } else { @@ -21,11 +21,11 @@ pub fn create_device(config: &crate::core::Config) -> io::Result> { let device_name = config .device_name .clone() - .unwrap_or(default_name.to_string()); - if &device_name == default_name { - delete_device(default_name); + .unwrap_or(DEFAULT_TUN_NAME.to_string()); + if &device_name == DEFAULT_TUN_NAME { + delete_device(DEFAULT_TUN_NAME); } - Arc::new(Device::new(Some(device_name), config.tap)?) + Arc::new(Device::new(Some(device_name))?) }; #[cfg(target_os = "macos")] let device = Arc::new(Device::new(config.device_name.clone())?); diff --git a/vnt/tun/src/linux/device.rs b/vnt/tun/src/linux/device.rs index f84ccf2a..a6d55b68 100644 --- a/vnt/tun/src/linux/device.rs +++ b/vnt/tun/src/linux/device.rs @@ -19,11 +19,10 @@ pub struct Device { name: String, ctl: Fd, tun: Fd, - mac: Option<[u8; 6]>, } impl Device { - pub fn new(name: Option, tap: bool) -> io::Result { + pub fn new(name: Option) -> io::Result { let device = unsafe { let dev = match name { Some(name) => { @@ -50,7 +49,7 @@ impl Device { ); } - let device_type: c_short = if tap { IFF_TAP } else { IFF_TUN } as c_short; + let device_type: c_short = IFF_TUN as c_short;//if tap { IFF_TAP } else { IFF_TUN } as c_short; let queues_num = 1; @@ -73,28 +72,14 @@ impl Device { let name = CStr::from_ptr(req.ifr_name.as_ptr()) .to_string_lossy() .to_string(); - let mac = if tap { - let get_mac_cmd = format!("cat /sys/class/net/{}/address", name); - let mac_out = exe_cmd(&get_mac_cmd)?; - let mac_str = String::from_utf8(mac_out.stdout).unwrap(); - let mut mac = [0; 6]; - let mut split = mac_str.split(":"); - for i in 0..6 { - mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap(); - } - Some(mac) - } else { - None - }; - let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name); - if let Err(e) = exe_cmd(&set_txqueuelen){ + let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name); + if let Err(e) = exe_cmd(&set_txqueuelen) { log::warn!("{:?}",e); } Device { name, tun, ctl, - mac, } }; device.enabled(true)?; @@ -234,6 +219,12 @@ impl Device { } } +impl Device { + pub fn as_tun_fd(&self) -> &Fd { + &self.tun + } +} + impl IFace for Device { fn version(&self) -> io::Result { Ok(String::new()) @@ -286,22 +277,10 @@ impl IFace for Device { } fn read(&self, buf: &mut [u8]) -> io::Result { - if self.mac.is_some() { - packet::read_tap( - buf, - |eth_buf| self.tun.read(eth_buf), - |eth_buf| self.tun.write(eth_buf), - ) - } else { - self.tun.read(buf) - } + self.tun.read(buf) } fn write(&self, buf: &[u8]) -> io::Result { - if let Some(mac) = &self.mac { - packet::write_tap(buf, |eth_buf| self.tun.write(eth_buf), mac) - } else { - self.tun.write(buf) - } + self.tun.write(buf) } } From 5a9e31bdedce33787e7b32dc00f7a7716ec49ce5 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:11:08 +0800 Subject: [PATCH 11/22] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BC=82=E6=AD=A5tun?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/tun/src/android/mod.rs | 5 +++++ vnt/tun/src/macos/device.rs | 5 +++++ vnt/tun/src/unix/fd.rs | 8 ++++++++ vnt/tun/src/unix/mod.rs | 1 + 4 files changed, 19 insertions(+) diff --git a/vnt/tun/src/android/mod.rs b/vnt/tun/src/android/mod.rs index d1d3f1ca..d9c7957a 100644 --- a/vnt/tun/src/android/mod.rs +++ b/vnt/tun/src/android/mod.rs @@ -13,6 +13,11 @@ impl Device { Ok(Self { fd: Fd::new(fd)? }) } } +impl Device { + pub fn as_tun_fd(&self) ->&Fd{ + &self.fd + } +} impl IFace for Device { fn version(&self) -> io::Result { Ok(String::new()) diff --git a/vnt/tun/src/macos/device.rs b/vnt/tun/src/macos/device.rs index 5b971af2..b423632f 100644 --- a/vnt/tun/src/macos/device.rs +++ b/vnt/tun/src/macos/device.rs @@ -224,6 +224,11 @@ impl Device { } } } +impl Device { + pub fn as_tun_fd(&self) ->&Fd{ + &self.tun + } +} impl IFace for Device { fn version(&self) -> io::Result { diff --git a/vnt/tun/src/unix/fd.rs b/vnt/tun/src/unix/fd.rs index c3778705..bdb00980 100644 --- a/vnt/tun/src/unix/fd.rs +++ b/vnt/tun/src/unix/fd.rs @@ -1,5 +1,6 @@ use std::io; use std::os::fd::{AsRawFd, IntoRawFd, RawFd}; +use libc::{F_GETFL, F_SETFL, fcntl, O_NONBLOCK}; pub struct Fd(pub RawFd); @@ -10,6 +11,12 @@ impl Fd { } Ok(Fd(value)) } + pub fn set_nonblock(&self) -> io::Result<()> { + match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } { + 0 => Ok(()), + _ => Err(io::Error::last_os_error()), + } + } } impl Fd { @@ -51,6 +58,7 @@ impl IntoRawFd for Fd { } } +#[cfg(not(target_os = "android"))] impl Drop for Fd { fn drop(&mut self) { unsafe { diff --git a/vnt/tun/src/unix/mod.rs b/vnt/tun/src/unix/mod.rs index 8d4537ac..9d99ddae 100644 --- a/vnt/tun/src/unix/mod.rs +++ b/vnt/tun/src/unix/mod.rs @@ -1,6 +1,7 @@ mod fd; pub use fd::Fd; +#[cfg(any(target_os = "macos", target_os = "linux"))] use std::process::Output; #[cfg(any(target_os = "macos", target_os = "linux"))] mod sockaddr; From cf4fc54dfdc03a6d3db81b6a8d35fa3fca0f2dc1 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:11:43 +0800 Subject: [PATCH 12/22] =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E6=98=A0=E5=B0=84?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E4=B8=BA=E7=A9=BA=E6=97=B6=E4=B8=8D=E5=90=AF?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/port_mapping/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vnt/src/port_mapping/mod.rs b/vnt/src/port_mapping/mod.rs index 9573311c..52a71a55 100644 --- a/vnt/src/port_mapping/mod.rs +++ b/vnt/src/port_mapping/mod.rs @@ -63,6 +63,9 @@ pub fn start_port_mapping( stop_manager: StopManager, vec: Vec<(bool, SocketAddr, String)>, ) -> anyhow::Result<()> { + if vec.is_empty() { + return Ok(()); + } let runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() .thread_name("portMapping") From 948f3d5d240cee66a8a4e9873d8d7acf8dbddaef Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:12:26 +0800 Subject: [PATCH 13/22] =?UTF-8?q?=E9=81=8D=E5=8E=86txt=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/util/dns_query.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/vnt/src/util/dns_query.rs b/vnt/src/util/dns_query.rs index a0eb77b3..cd4f77a2 100644 --- a/vnt/src/util/dns_query.rs +++ b/vnt/src/util/dns_query.rs @@ -102,7 +102,21 @@ pub fn dns_query_all( let mut err: Option = None; for name_server in name_servers { if let Some(domain) = txt_domain.as_ref() { - return txt_dns(domain, name_server); + match txt_dns(domain, name_server) { + Ok(addr) => { + if !addr.is_empty() { + return Ok(addr); + } + } + Err(e) => { + if let Some(err) = &mut err { + *err = anyhow::anyhow!("{} {}", err, e); + } else { + err.replace(anyhow::anyhow!("{}", e)); + } + } + } + continue; } let end_index = domain .rfind(":") From b12b0b95a08a5041e78e8e3d08dd1c9930de6923 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:13:44 +0800 Subject: [PATCH 14/22] =?UTF-8?q?=E5=8E=BB=E9=99=A4linux=E4=B8=8A=E7=9A=84?= =?UTF-8?q?tap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/core/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index 39598979..4c0d7284 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -13,7 +13,7 @@ mod conn; #[derive(Clone, Debug)] pub struct Config { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] pub tap: bool, pub token: String, pub device_id: String, @@ -50,7 +50,7 @@ pub struct Config { impl Config { pub fn new( - #[cfg(any(target_os = "windows", target_os = "linux"))] tap: bool, + #[cfg(target_os = "windows")] tap: bool, token: String, device_id: String, name: String, @@ -104,7 +104,7 @@ impl Config { #[cfg(feature = "port_mapping")] let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?; Ok(Self { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "windows")] tap, token, device_id, From ccd6e44c2bab0453e7bfab8b9b4fc152d06bb4a9 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:14:01 +0800 Subject: [PATCH 15/22] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=BC=82=E6=AD=A5tun?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/handle/tun_tap/mod.rs | 192 +------------------- vnt/src/handle/tun_tap/tun_handler.rs | 252 +++++++++++++++++--------- vnt/src/handle/tun_tap/unix.rs | 183 +++++++++++++++++++ vnt/src/handle/tun_tap/windows.rs | 124 +++++++++++++ 4 files changed, 486 insertions(+), 265 deletions(-) create mode 100644 vnt/src/handle/tun_tap/unix.rs create mode 100644 vnt/src/handle/tun_tap/windows.rs diff --git a/vnt/src/handle/tun_tap/mod.rs b/vnt/src/handle/tun_tap/mod.rs index 3697320f..5d804067 100644 --- a/vnt/src/handle/tun_tap/mod.rs +++ b/vnt/src/handle/tun_tap/mod.rs @@ -1,187 +1,11 @@ -use std::io; -use std::net::Ipv4Addr; - -use parking_lot::Mutex; - -use packet::ip::ipv4::packet::IpV4Packet; -use packet::ip::ipv4::protocol::Protocol; - -use crate::channel::context::ChannelContext; -use crate::cipher::Cipher; -use crate::external_route::ExternalRoute; -use crate::handle::{check_dest, CurrentDeviceInfo, PeerDeviceInfo}; -#[cfg(feature = "ip_proxy")] -use crate::ip_proxy::{IpProxyMap, ProxyHandler}; -use crate::protocol; -use crate::protocol::body::ENCRYPTION_RESERVED; -use crate::protocol::ip_turn_packet::BroadcastPacket; -use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL}; - mod channel_group; pub mod tun_handler; -fn broadcast( - server_cipher: &Cipher, - sender: &ChannelContext, - net_packet: &mut NetPacket<&mut [u8]>, - current_device: &CurrentDeviceInfo, - device_list: &Mutex<(u16, Vec)>, -) -> io::Result<()> { - let list: Vec = device_list - .lock() - .1 - .iter() - .filter(|info| info.status.is_online()) - .map(|info| info.virtual_ip) - .collect(); - const MAX_COUNT: usize = 8; - let mut p2p_ips = Vec::with_capacity(8); - let mut relay_ips = Vec::with_capacity(8); - let mut overflow = false; - for (index, peer_ip) in list.into_iter().enumerate() { - if index > MAX_COUNT { - overflow = true; - break; - } - if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) { - if sender - .send_by_key(net_packet.buffer(), route.route_key()) - .is_ok() - { - p2p_ips.push(peer_ip); - continue; - } - } - relay_ips.push(peer_ip); - } - if !overflow && relay_ips.is_empty() { - //全部p2p,不需要服务器中转 - return Ok(()); - } - - if p2p_ips.is_empty() { - //都没有p2p则直接由服务器转发 - if current_device.status.online() { - sender.send_default(net_packet.buffer(), current_device.connect_server)?; - } - return Ok(()); - } - if !overflow && relay_ips.len() == 2 { - // 如果转发的ip数不多就直接发 - for peer_ip in relay_ips { - //非直连的广播要改变目的地址,不然服务端收到了会再次广播 - net_packet.set_destination(peer_ip); - sender.send_ipv4_by_id( - net_packet.buffer(), - &peer_ip, - current_device.connect_server, - current_device.status.online(), - )?; - } - return Ok(()); - } - if current_device.status.offline() { - //离线的不再转发 - return Ok(()); - } - let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED]; - //剩余的发送到服务端,需要告知哪些已发送过 - let mut server_packet = NetPacket::new_encrypt(buf)?; - server_packet.set_default_version(); - server_packet.set_gateway_flag(true); - server_packet.first_set_ttl(MAX_TTL); - server_packet.set_source(net_packet.source()); - //使用对应的目的地址 - server_packet.set_destination(net_packet.destination()); - server_packet.set_protocol(protocol::Protocol::IpTurn); - server_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into()); - - let mut broadcast = BroadcastPacket::unchecked(server_packet.payload_mut()); - broadcast.set_address(&p2p_ips)?; - broadcast.set_data(net_packet.buffer())?; - server_cipher.encrypt_ipv4(&mut server_packet)?; - sender.send_default(server_packet.buffer(), current_device.connect_server) -} - -/// 实现一个原地发送,必须保证是如下结构 -/// |12字节开头|ip报文|至少1024字节结尾| -/// -#[inline] -pub fn base_handle( - context: &ChannelContext, - buf: &mut [u8], - data_len: usize, //数据总长度=12+ip包长度 - current_device: CurrentDeviceInfo, - ip_route: &ExternalRoute, - #[cfg(feature = "ip_proxy")] proxy_map: &Option, - client_cipher: &Cipher, - server_cipher: &Cipher, - device_list: &Mutex<(u16, Vec)>, -) -> io::Result<()> { - let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?; - let protocol = ipv4_packet.protocol(); - let src_ip = ipv4_packet.source_ip(); - let mut dest_ip = ipv4_packet.destination_ip(); - let mut net_packet = NetPacket::new0(data_len, buf)?; - net_packet.set_default_version(); - net_packet.set_protocol(protocol::Protocol::IpTurn); - net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into()); - net_packet.first_set_ttl(6); - net_packet.set_source(src_ip); - net_packet.set_destination(dest_ip); - if dest_ip == current_device.virtual_gateway { - // 发到网关的加密方式不一样,要单独处理 - if protocol == Protocol::Icmp { - net_packet.set_gateway_flag(true); - server_cipher.encrypt_ipv4(&mut net_packet)?; - context.send_default(net_packet.buffer(), current_device.connect_server)?; - } - return Ok(()); - } - if dest_ip.is_multicast() { - //当作广播处理 - dest_ip = Ipv4Addr::BROADCAST; - net_packet.set_destination(Ipv4Addr::BROADCAST); - } - if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip { - // 广播 发送到直连目标 - client_cipher.encrypt_ipv4(&mut net_packet)?; - broadcast( - server_cipher, - context, - &mut net_packet, - ¤t_device, - device_list, - )?; - return Ok(()); - } - if !check_dest( - dest_ip, - current_device.virtual_netmask, - current_device.virtual_network, - ) { - if let Some(r_dest_ip) = ip_route.route(&dest_ip) { - //路由的目标不能是自己 - if r_dest_ip == src_ip { - return Ok(()); - } - //需要修改目的地址 - dest_ip = r_dest_ip; - net_packet.set_destination(r_dest_ip); - } else { - return Ok(()); - } - } - #[cfg(feature = "ip_proxy")] - if let Some(proxy_map) = proxy_map { - let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?; - proxy_map.send_handle(&mut ipv4_packet)?; - } - client_cipher.encrypt_ipv4(&mut net_packet)?; - context.send_ipv4_by_id( - net_packet.buffer(), - &dest_ip, - current_device.connect_server, - current_device.status.online(), - ) -} +#[cfg(unix)] +mod unix; +#[cfg(unix)] +pub(crate) use unix::*; +#[cfg(target_os = "windows")] +mod windows; +#[cfg(target_os = "windows")] +pub(crate) use windows::*; diff --git a/vnt/src/handle/tun_tap/tun_handler.rs b/vnt/src/handle/tun_tap/tun_handler.rs index bfa18b92..cda5e3c1 100644 --- a/vnt/src/handle/tun_tap/tun_handler.rs +++ b/vnt/src/handle/tun_tap/tun_handler.rs @@ -1,3 +1,4 @@ +use std::net::Ipv4Addr; use std::sync::Arc; use std::{io, thread}; @@ -6,22 +7,27 @@ use parking_lot::Mutex; use packet::icmp::icmp::IcmpPacket; use packet::icmp::Kind; -use packet::ip::ipv4; use packet::ip::ipv4::packet::IpV4Packet; +use packet::ip::ipv4::protocol::Protocol; use tun::device::IFace; use tun::Device; use crate::channel::context::ChannelContext; use crate::cipher::Cipher; use crate::external_route::ExternalRoute; -use crate::handle::tun_tap::channel_group::{channel_group, GroupSyncSender}; -use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; +use crate::handle::tun_tap::channel_group::channel_group; +use crate::handle::{check_dest, CurrentDeviceInfo, PeerDeviceInfo}; #[cfg(feature = "ip_proxy")] use crate::ip_proxy::IpProxyMap; +use crate::ip_proxy::ProxyHandler; +use crate::protocol; +use crate::protocol::body::ENCRYPTION_RESERVED; +use crate::protocol::ip_turn_packet::BroadcastPacket; +use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL}; use crate::util::{SingleU64Adder, StopManager}; fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> io::Result<()> { - if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp { + if ipv4_packet.protocol() == Protocol::Icmp { let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?; if icmp.kind() == Kind::EchoRequest { icmp.set_kind(Kind::EchoReply); @@ -37,7 +43,7 @@ fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> io::R } /// 接收tun数据,并且转发到udp上 -fn handle( +pub(crate) fn handle( context: &ChannelContext, data: &mut [u8], len: usize, @@ -59,7 +65,7 @@ fn handle( if src_ip == dest_ip { return icmp(&device_writer, ipv4_packet); } - return crate::handle::tun_tap::base_handle( + return base_handle( context, data, len, @@ -86,24 +92,6 @@ pub fn start( mut up_counter: SingleU64Adder, device_list: Arc)>>, ) -> io::Result<()> { - #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] - let worker = { - #[cfg(target_os = "macos")] - let current_device = current_device.clone(); - let device = device.clone(); - stop_manager.add_listener("tun_device".into(), move || { - if let Err(e) = device.shutdown() { - log::warn!("{:?}", e); - } - #[cfg(target_os = "macos")] - { - let ip = current_device.load().virtual_ip; - if let Ok(udp) = std::net::UdpSocket::bind("0.0.0.0:0") { - let _ = udp.send_to(b"stop", format!("{:?}:1234", ip)); - } - } - })? - }; if parallel > 1 { let (sender, receivers) = channel_group::<(Vec, usize)>(parallel, 16); for (index, receiver) in receivers.into_iter().enumerate() { @@ -148,17 +136,20 @@ pub fn start( thread::Builder::new() .name("tunHandlerM".into()) .spawn(move || { - if let Err(e) = start_multi(stop_manager, device, sender, &mut up_counter) { + if let Err(e) = crate::handle::tun_tap::start_multi( + stop_manager, + device, + sender, + &mut up_counter, + ) { log::warn!("stop:{}", e); } - #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] - worker.stop_all(); })?; } else { thread::Builder::new() .name("tunHandlerS".into()) .spawn(move || { - if let Err(e) = start_simple( + if let Err(e) = crate::handle::tun_tap::start_simple( stop_manager, &context, device, @@ -173,74 +164,173 @@ pub fn start( ) { log::warn!("stop:{}", e); } - #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] - worker.stop_all(); })?; } Ok(()) } -fn start_simple( - stop_manager: StopManager, - context: &ChannelContext, - device: Arc, - current_device: Arc>, - ip_route: ExternalRoute, - #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, - client_cipher: Cipher, - server_cipher: Cipher, - up_counter: &mut SingleU64Adder, - device_list: Arc)>>, +fn broadcast( + server_cipher: &Cipher, + sender: &ChannelContext, + net_packet: &mut NetPacket<&mut [u8]>, + current_device: &CurrentDeviceInfo, + device_list: &Mutex<(u16, Vec)>, ) -> io::Result<()> { - let mut buf = [0; 1024 * 16]; - loop { - if stop_manager.is_stop() { - return Ok(()); + let list: Vec = device_list + .lock() + .1 + .iter() + .filter(|info| info.status.is_online()) + .map(|info| info.virtual_ip) + .collect(); + const MAX_COUNT: usize = 8; + let mut p2p_ips = Vec::with_capacity(8); + let mut relay_ips = Vec::with_capacity(8); + let mut overflow = false; + for (index, peer_ip) in list.into_iter().enumerate() { + if index > MAX_COUNT { + overflow = true; + break; } - let len = device.read(&mut buf[12..])? + 12; - //单线程的 - up_counter.add(len as u64); - #[cfg(any(target_os = "macos"))] - let mut buf = &mut buf[4..]; - // buf是重复利用的,需要重置头部 - buf[..12].fill(0); - match handle( - context, - &mut buf, - len, - &device, - current_device.load(), - &ip_route, - #[cfg(feature = "ip_proxy")] - &ip_proxy_map, - &client_cipher, - &server_cipher, - &device_list, - ) { - Ok(_) => {} - Err(e) => { - log::warn!("{:?}", e) + if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) { + if sender + .send_by_key(net_packet.buffer(), route.route_key()) + .is_ok() + { + p2p_ips.push(peer_ip); + continue; } } + relay_ips.push(peer_ip); + } + if !overflow && relay_ips.is_empty() { + //全部p2p,不需要服务器中转 + return Ok(()); } + + if p2p_ips.is_empty() { + //都没有p2p则直接由服务器转发 + if current_device.status.online() { + sender.send_default(net_packet.buffer(), current_device.connect_server)?; + } + return Ok(()); + } + if !overflow && relay_ips.len() == 2 { + // 如果转发的ip数不多就直接发 + for peer_ip in relay_ips { + //非直连的广播要改变目的地址,不然服务端收到了会再次广播 + net_packet.set_destination(peer_ip); + sender.send_ipv4_by_id( + net_packet.buffer(), + &peer_ip, + current_device.connect_server, + current_device.status.online(), + )?; + } + return Ok(()); + } + if current_device.status.offline() { + //离线的不再转发 + return Ok(()); + } + let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED]; + //剩余的发送到服务端,需要告知哪些已发送过 + let mut server_packet = NetPacket::new_encrypt(buf)?; + server_packet.set_default_version(); + server_packet.set_gateway_flag(true); + server_packet.first_set_ttl(MAX_TTL); + server_packet.set_source(net_packet.source()); + //使用对应的目的地址 + server_packet.set_destination(net_packet.destination()); + server_packet.set_protocol(protocol::Protocol::IpTurn); + server_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into()); + + let mut broadcast = BroadcastPacket::unchecked(server_packet.payload_mut()); + broadcast.set_address(&p2p_ips)?; + broadcast.set_data(net_packet.buffer())?; + server_cipher.encrypt_ipv4(&mut server_packet)?; + sender.send_default(server_packet.buffer(), current_device.connect_server) } -fn start_multi( - stop_manager: StopManager, - device: Arc, - mut group_sync_sender: GroupSyncSender<(Vec, usize)>, - up_counter: &mut SingleU64Adder, +/// 实现一个原地发送,必须保证是如下结构 +/// |12字节开头|ip报文|至少1024字节结尾| +/// +#[inline] +fn base_handle( + context: &ChannelContext, + buf: &mut [u8], + data_len: usize, //数据总长度=12+ip包长度 + current_device: CurrentDeviceInfo, + ip_route: &ExternalRoute, + #[cfg(feature = "ip_proxy")] proxy_map: &Option, + client_cipher: &Cipher, + server_cipher: &Cipher, + device_list: &Mutex<(u16, Vec)>, ) -> io::Result<()> { - loop { - if stop_manager.is_stop() { - return Ok(()); + let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?; + let protocol = ipv4_packet.protocol(); + let src_ip = ipv4_packet.source_ip(); + let mut dest_ip = ipv4_packet.destination_ip(); + let mut net_packet = NetPacket::new0(data_len, buf)?; + net_packet.set_default_version(); + net_packet.set_protocol(protocol::Protocol::IpTurn); + net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into()); + net_packet.first_set_ttl(6); + net_packet.set_source(src_ip); + net_packet.set_destination(dest_ip); + if dest_ip == current_device.virtual_gateway { + // 发到网关的加密方式不一样,要单独处理 + if protocol == Protocol::Icmp { + net_packet.set_gateway_flag(true); + server_cipher.encrypt_ipv4(&mut net_packet)?; + context.send_default(net_packet.buffer(), current_device.connect_server)?; } - let mut buf = vec![0; 1024 * 16]; - let len = device.read(&mut buf[12..])? + 12; - //单线程的 - up_counter.add(len as u64); - if group_sync_sender.send((buf, len)).is_err() { + return Ok(()); + } + if dest_ip.is_multicast() { + //当作广播处理 + dest_ip = Ipv4Addr::BROADCAST; + net_packet.set_destination(Ipv4Addr::BROADCAST); + } + if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip { + // 广播 发送到直连目标 + client_cipher.encrypt_ipv4(&mut net_packet)?; + broadcast( + server_cipher, + context, + &mut net_packet, + ¤t_device, + device_list, + )?; + return Ok(()); + } + if !check_dest( + dest_ip, + current_device.virtual_netmask, + current_device.virtual_network, + ) { + if let Some(r_dest_ip) = ip_route.route(&dest_ip) { + //路由的目标不能是自己 + if r_dest_ip == src_ip { + return Ok(()); + } + //需要修改目的地址 + dest_ip = r_dest_ip; + net_packet.set_destination(r_dest_ip); + } else { return Ok(()); } } + #[cfg(feature = "ip_proxy")] + if let Some(proxy_map) = proxy_map { + let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?; + proxy_map.send_handle(&mut ipv4_packet)?; + } + client_cipher.encrypt_ipv4(&mut net_packet)?; + context.send_ipv4_by_id( + net_packet.buffer(), + &dest_ip, + current_device.connect_server, + current_device.status.online(), + ) } diff --git a/vnt/src/handle/tun_tap/unix.rs b/vnt/src/handle/tun_tap/unix.rs new file mode 100644 index 00000000..0c52966e --- /dev/null +++ b/vnt/src/handle/tun_tap/unix.rs @@ -0,0 +1,183 @@ +use crate::channel::context::ChannelContext; +use crate::cipher::Cipher; +use crate::external_route::ExternalRoute; +use crate::handle::tun_tap::channel_group::GroupSyncSender; +use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; +use crate::ip_proxy::IpProxyMap; +use crate::util::{SingleU64Adder, StopManager}; +use crossbeam_utils::atomic::AtomicCell; +use mio::event::Source; +use mio::unix::SourceFd; +use mio::{Events, Interest, Poll, Token, Waker}; +use parking_lot::Mutex; +use std::io; +use std::os::fd::AsRawFd; +use std::sync::Arc; +use tun::Device; + +const STOP: Token = Token(0); +const FD: Token = Token(1); + +pub(crate) fn start_simple( + stop_manager: StopManager, + context: &ChannelContext, + device: Arc, + current_device: Arc>, + ip_route: ExternalRoute, + #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, + client_cipher: Cipher, + server_cipher: Cipher, + up_counter: &mut SingleU64Adder, + device_list: Arc)>>, +) -> io::Result<()> { + let poll = Poll::new()?; + let waker = Arc::new(Waker::new(poll.registry(), STOP)?); + let _waker = waker.clone(); + let worker = stop_manager.add_listener("tun_device".into(), move || { + let _ = waker.wake(); + })?; + if let Err(e) = start_simple0( + poll, + context, + device, + current_device, + ip_route, + #[cfg(feature = "ip_proxy")] + ip_proxy_map, + client_cipher, + server_cipher, + up_counter, + device_list, + ) { + log::error!("{:?}", e); + }; + worker.stop_all(); + drop(_waker); + Ok(()) +} + +fn start_simple0( + mut poll: Poll, + context: &ChannelContext, + device: Arc, + current_device: Arc>, + ip_route: ExternalRoute, + #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, + client_cipher: Cipher, + server_cipher: Cipher, + up_counter: &mut SingleU64Adder, + device_list: Arc)>>, +) -> io::Result<()> { + let mut buf = [0; 1024 * 16]; + let fd = device.as_tun_fd(); + fd.set_nonblock()?; + SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?; + let mut evnets = Events::with_capacity(4); + #[cfg(not(target_os = "macos"))] + let start = 12; + #[cfg(target_os = "macos")] + let start = 12 - 4; + loop { + poll.poll(&mut evnets, None)?; + for event in evnets.iter() { + if event.token() == STOP { + return Ok(()); + } + loop { + let len = match fd.read(&mut buf[start..]) { + Ok(len) => len + start, + Err(e) => { + if e.kind() == io::ErrorKind::WouldBlock { + break; + } + Err(e)? + } + }; + //单线程的 + up_counter.add(len as u64); + // buf是重复利用的,需要重置头部 + buf[..12].fill(0); + match crate::handle::tun_tap::tun_handler::handle( + context, + &mut buf, + len, + &device, + current_device.load(), + &ip_route, + #[cfg(feature = "ip_proxy")] + &ip_proxy_map, + &client_cipher, + &server_cipher, + &device_list, + ) { + Ok(_) => {} + Err(e) => { + log::warn!("{:?}", e) + } + } + } + } + } +} + +pub(crate) fn start_multi( + stop_manager: StopManager, + device: Arc, + group_sync_sender: GroupSyncSender<(Vec, usize)>, + up_counter: &mut SingleU64Adder, +) -> io::Result<()> { + let poll = Poll::new()?; + let waker = Arc::new(Waker::new(poll.registry(), STOP)?); + let _waker = waker.clone(); + let worker = stop_manager.add_listener("tun_device".into(), move || { + let _ = waker.wake(); + })?; + if let Err(e) = start_multi0(poll, device, group_sync_sender, up_counter) { + log::error!("{:?}", e); + }; + worker.stop_all(); + drop(_waker); + Ok(()) +} + +fn start_multi0( + mut poll: Poll, + device: Arc, + mut group_sync_sender: GroupSyncSender<(Vec, usize)>, + up_counter: &mut SingleU64Adder, +) -> io::Result<()> { + let fd = device.as_tun_fd(); + fd.set_nonblock()?; + SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?; + let mut evnets = Events::with_capacity(4); + let mut buf = vec![0; 1024 * 16]; + #[cfg(not(target_os = "macos"))] + let start = 12; + #[cfg(target_os = "macos")] + let start = 12 - 4; + loop { + poll.poll(&mut evnets, None)?; + for event in evnets.iter() { + if event.token() == STOP { + return Ok(()); + } + loop { + let len = match fd.read(&mut buf[start..]) { + Ok(len) => len + start, + Err(e) => { + if e.kind() == io::ErrorKind::WouldBlock { + break; + } + Err(e)? + } + }; + //单线程的 + up_counter.add(len as u64); + if group_sync_sender.send((buf, len)).is_err() { + return Ok(()); + } + buf = vec![0; 1024 * 16]; + } + } + } +} diff --git a/vnt/src/handle/tun_tap/windows.rs b/vnt/src/handle/tun_tap/windows.rs new file mode 100644 index 00000000..8546bff7 --- /dev/null +++ b/vnt/src/handle/tun_tap/windows.rs @@ -0,0 +1,124 @@ +use crate::channel::context::ChannelContext; +use crate::cipher::Cipher; +use crate::external_route::ExternalRoute; +use crate::handle::tun_tap::channel_group::GroupSyncSender; +use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; +use crate::ip_proxy::IpProxyMap; +use crate::util::{SingleU64Adder, StopManager}; +use crossbeam_utils::atomic::AtomicCell; +use parking_lot::Mutex; +use std::io; +use std::sync::Arc; +use tun::device::IFace; +use tun::Device; + +pub(crate) fn start_simple( + stop_manager: StopManager, + context: &ChannelContext, + device: Arc, + current_device: Arc>, + ip_route: ExternalRoute, + #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, + client_cipher: Cipher, + server_cipher: Cipher, + up_counter: &mut SingleU64Adder, + device_list: Arc)>>, +) -> io::Result<()> { + let worker = { + let device = device.clone(); + stop_manager.add_listener("tun_device".into(), move || { + if let Err(e) = device.shutdown() { + log::warn!("{:?}", e); + } + })? + }; + if let Err(e) = start_simple0( + context, + device, + current_device, + ip_route, + #[cfg(feature = "ip_proxy")] + ip_proxy_map, + client_cipher, + server_cipher, + up_counter, + device_list, + ) { + log::error!("{:?}", e); + } + worker.stop_all(); + Ok(()) +} +fn start_simple0( + context: &ChannelContext, + device: Arc, + current_device: Arc>, + ip_route: ExternalRoute, + #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, + client_cipher: Cipher, + server_cipher: Cipher, + up_counter: &mut SingleU64Adder, + device_list: Arc)>>, +) -> io::Result<()> { + let mut buf = [0; 1024 * 16]; + loop { + let len = device.read(&mut buf[12..])? + 12; + //单线程的 + up_counter.add(len as u64); + // buf是重复利用的,需要重置头部 + buf[..12].fill(0); + match crate::handle::tun_tap::tun_handler::handle( + context, + &mut buf, + len, + &device, + current_device.load(), + &ip_route, + #[cfg(feature = "ip_proxy")] + &ip_proxy_map, + &client_cipher, + &server_cipher, + &device_list, + ) { + Ok(_) => {} + Err(e) => { + log::warn!("tun/tap {:?}", e) + } + } + } +} +pub(crate) fn start_multi( + stop_manager: StopManager, + device: Arc, + group_sync_sender: GroupSyncSender<(Vec, usize)>, + up_counter: &mut SingleU64Adder, +) -> io::Result<()> { + let worker = { + let device = device.clone(); + stop_manager.add_listener("tun_device_multi".into(), move || { + if let Err(e) = device.shutdown() { + log::warn!("{:?}", e); + } + })? + }; + if let Err(e) = start_multi0(device, group_sync_sender, up_counter) { + log::error!("{:?}", e); + }; + worker.stop_all(); + Ok(()) +} +fn start_multi0( + device: Arc, + mut group_sync_sender: GroupSyncSender<(Vec, usize)>, + up_counter: &mut SingleU64Adder, +) -> io::Result<()> { + loop { + let mut buf = vec![0; 1024 * 16]; + let len = device.read(&mut buf[12..])? + 12; + //单线程的 + up_counter.add(len as u64); + if group_sync_sender.send((buf, len)).is_err() { + return Ok(()); + } + } +} From 4215488cb66e7c0dc56064abe55517fdf8924c23 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 20:16:02 +0800 Subject: [PATCH 16/22] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=AD=E7=BB=A7?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/core/conn.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 6feb6b38..9ed9b688 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -103,13 +103,17 @@ impl Vnt { stop_manager.clone(), config.port_mapping_list.clone(), )?; - let ports = config.ports.as_ref().map_or(vec![0, 0], |v| { + let mut ports = config.ports.as_ref().map_or(vec![0, 0], |v| { if v.is_empty() { vec![0, 0] } else { v.clone() } }); + if config.use_channel_type.is_only_relay() { + //中继模式下只监听一个端口就够了 + ports.truncate(1); + } //通道上下文 let (context, tcp_listener) = init_context( ports, @@ -327,15 +331,16 @@ pub fn start( client_cipher.clone(), ); } - // 定时地址探测 - maintain::addr_request( - &scheduler, - context.clone(), - current_device.clone(), - server_cipher.clone(), - config_info.clone(), - ); + if !context.use_channel_type().is_only_relay() { + // 定时地址探测 + maintain::addr_request( + &scheduler, + context.clone(), + current_device.clone(), + server_cipher.clone(), + config_info.clone(), + ); // 定时打洞 maintain::punch( &scheduler, From 1338bcbbc54b8d557a7d0cc36eaee99b7a2e7e1a Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 21:25:55 +0800 Subject: [PATCH 17/22] =?UTF-8?q?=E6=B6=88=E9=99=A4=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/tun/src/android/mod.rs | 10 +++++----- vnt/tun/src/lib.rs | 4 +++- vnt/tun/src/linux/device.rs | 15 +++++---------- vnt/tun/src/macos/device.rs | 3 ++- vnt/tun/src/packet/arp/packet.rs | 1 + vnt/tun/src/packet/ethernet/packet.rs | 5 ++++- vnt/tun/src/packet/mod.rs | 2 +- vnt/tun/src/unix/fd.rs | 2 +- vnt/tun/src/windows/netsh.rs | 3 ++- vnt/tun/src/windows/tap/mod.rs | 7 ++----- vnt/tun/src/windows/tun/mod.rs | 7 ++++--- vnt/tun/src/windows/tun/wintun_log.rs | 1 + vnt/tun/src/windows/tun/wintun_raw.rs | 2 ++ 13 files changed, 33 insertions(+), 29 deletions(-) diff --git a/vnt/tun/src/android/mod.rs b/vnt/tun/src/android/mod.rs index d9c7957a..79f78b95 100644 --- a/vnt/tun/src/android/mod.rs +++ b/vnt/tun/src/android/mod.rs @@ -14,7 +14,7 @@ impl Device { } } impl Device { - pub fn as_tun_fd(&self) ->&Fd{ + pub fn as_tun_fd(&self) -> &Fd { &self.fd } } @@ -31,7 +31,7 @@ impl IFace for Device { Err(io::Error::from(io::ErrorKind::Unsupported)) } - fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> { + fn set_ip(&self, _address: Ipv4Addr, _mask: Ipv4Addr) -> io::Result<()> { Err(io::Error::from(io::ErrorKind::Unsupported)) } @@ -39,15 +39,15 @@ impl IFace for Device { Err(io::Error::from(io::ErrorKind::Unsupported)) } - fn set_mtu(&self, value: u32) -> io::Result<()> { + fn set_mtu(&self, _value: u32) -> io::Result<()> { Err(io::Error::from(io::ErrorKind::Unsupported)) } - fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> { + fn add_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr, _metric: u16) -> io::Result<()> { Err(io::Error::from(io::ErrorKind::Unsupported)) } - fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> { + fn delete_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr) -> io::Result<()> { Err(io::Error::from(io::ErrorKind::Unsupported)) } diff --git a/vnt/tun/src/lib.rs b/vnt/tun/src/lib.rs index d287dd9a..b597a483 100644 --- a/vnt/tun/src/lib.rs +++ b/vnt/tun/src/lib.rs @@ -3,7 +3,6 @@ /// https://github.com/Tazdevil971/tap-windows /// https://github.com/nulldotblack/wintun pub mod device; -mod packet; #[cfg(target_os = "linux")] mod linux; @@ -29,3 +28,6 @@ mod windows; #[cfg(windows)] pub use windows::Device; + +#[cfg(windows)] +mod packet; diff --git a/vnt/tun/src/linux/device.rs b/vnt/tun/src/linux/device.rs index a6d55b68..77450a3c 100644 --- a/vnt/tun/src/linux/device.rs +++ b/vnt/tun/src/linux/device.rs @@ -1,18 +1,17 @@ +#![allow(dead_code)] use std::ffi::{CStr, CString}; use std::net::Ipv4Addr; use std::os::fd::AsRawFd; -use std::process::Command; use std::{io, mem, ptr}; use libc::{ - c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TAP, IFF_TUN, + c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TUN, IFF_UP, IFNAMSIZ, O_RDWR, SOCK_DGRAM, }; use crate::device::IFace; use crate::linux::route; use crate::linux::sys::*; -use crate::packet; use crate::unix::{exe_cmd, Fd, SockAddr}; pub struct Device { @@ -49,7 +48,7 @@ impl Device { ); } - let device_type: c_short = IFF_TUN as c_short;//if tap { IFF_TAP } else { IFF_TUN } as c_short; + let device_type: c_short = IFF_TUN as c_short; //if tap { IFF_TAP } else { IFF_TUN } as c_short; let queues_num = 1; @@ -74,13 +73,9 @@ impl Device { .to_string(); let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name); if let Err(e) = exe_cmd(&set_txqueuelen) { - log::warn!("{:?}",e); - } - Device { - name, - tun, - ctl, + log::warn!("{:?}", e); } + Device { name, tun, ctl } }; device.enabled(true)?; Ok(device) diff --git a/vnt/tun/src/macos/device.rs b/vnt/tun/src/macos/device.rs index b423632f..b7d70eb2 100644 --- a/vnt/tun/src/macos/device.rs +++ b/vnt/tun/src/macos/device.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use std::ffi::{c_void, CStr}; use std::net::Ipv4Addr; use std::os::fd::AsRawFd; @@ -225,7 +226,7 @@ impl Device { } } impl Device { - pub fn as_tun_fd(&self) ->&Fd{ + pub fn as_tun_fd(&self) -> &Fd { &self.tun } } diff --git a/vnt/tun/src/packet/arp/packet.rs b/vnt/tun/src/packet/arp/packet.rs index ea027a3a..a2c96cd7 100644 --- a/vnt/tun/src/packet/arp/packet.rs +++ b/vnt/tun/src/packet/arp/packet.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use std::{fmt, io}; /// 地址解析协议,由IP地址找到MAC地址 diff --git a/vnt/tun/src/packet/ethernet/packet.rs b/vnt/tun/src/packet/ethernet/packet.rs index 440d61ab..a3f74606 100644 --- a/vnt/tun/src/packet/ethernet/packet.rs +++ b/vnt/tun/src/packet/ethernet/packet.rs @@ -21,7 +21,10 @@ impl> EthernetPacket { let packet = EthernetPacket::unchecked(buffer); //头部固定14位 if packet.buffer.as_ref().len() < 14 { - Err(io::Error::new(io::ErrorKind::InvalidData,format!("len={}", packet.buffer.as_ref().len())))?; + Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("len={}", packet.buffer.as_ref().len()), + ))?; } Ok(packet) diff --git a/vnt/tun/src/packet/mod.rs b/vnt/tun/src/packet/mod.rs index 07905b7e..aee2cf12 100644 --- a/vnt/tun/src/packet/mod.rs +++ b/vnt/tun/src/packet/mod.rs @@ -13,7 +13,7 @@ where let mut eth_buf = [0; 65536]; loop { let len = read_fn(&mut eth_buf)?; - if len == 0{ + if len == 0 { return Ok(len); } //处理arp包 diff --git a/vnt/tun/src/unix/fd.rs b/vnt/tun/src/unix/fd.rs index bdb00980..4c3f9733 100644 --- a/vnt/tun/src/unix/fd.rs +++ b/vnt/tun/src/unix/fd.rs @@ -1,6 +1,6 @@ +use libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK}; use std::io; use std::os::fd::{AsRawFd, IntoRawFd, RawFd}; -use libc::{F_GETFL, F_SETFL, fcntl, O_NONBLOCK}; pub struct Fd(pub RawFd); diff --git a/vnt/tun/src/windows/netsh.rs b/vnt/tun/src/windows/netsh.rs index 2fed74a2..d2e3962e 100644 --- a/vnt/tun/src/windows/netsh.rs +++ b/vnt/tun/src/windows/netsh.rs @@ -1,6 +1,7 @@ +#![allow(dead_code)] use crate::windows::exe_cmd; +use std::io; use std::net::Ipv4Addr; -use std::{io, process}; /// 设置网卡名称 pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> { diff --git a/vnt/tun/src/windows/tap/mod.rs b/vnt/tun/src/windows/tap/mod.rs index bb3024e1..74c5c0a9 100644 --- a/vnt/tun/src/windows/tap/mod.rs +++ b/vnt/tun/src/windows/tap/mod.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use std::io; use std::net::Ipv4Addr; use winapi::shared::ifdef::NET_LUID; @@ -11,8 +12,6 @@ use winapi::um::winnt::{ use crate::device::IFace; use crate::packet; -use crate::packet::ethernet::protocol::Protocol; -use crate::packet::{arp, ethernet}; use crate::windows::{ctl_code, decode_utf16, encode_utf16, ffi, netsh, route}; /* Present in 8.1 */ @@ -97,7 +96,7 @@ impl Device { let index = ffi::luid_to_index(&luid).map(|index| index as u32)?; // 设置网卡跃点 if let Err(e) = netsh::set_interface_metric(index, 0) { - log::warn!("{:?}",e); + log::warn!("{:?}", e); } let device = Self { handle, @@ -122,8 +121,6 @@ impl Device { } } -const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9]; - impl IFace for Device { fn version(&self) -> io::Result { let mut version = [0u32; 3]; diff --git a/vnt/tun/src/windows/tun/mod.rs b/vnt/tun/src/windows/tun/mod.rs index 0d027c96..62c0326c 100644 --- a/vnt/tun/src/windows/tun/mod.rs +++ b/vnt/tun/src/windows/tun/mod.rs @@ -1,4 +1,5 @@ -use libloading::{Error, Library}; +#![allow(dead_code)] +use libloading::Library; use std::io; use std::net::Ipv4Addr; @@ -84,7 +85,7 @@ impl Device { //SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred //guid to the winapi guid type is safe and will allow the windows kernel to see our GUID - let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) }; + let guid_struct: wintun_raw::GUID = std::mem::transmute(guid); let guid_ptr = &guid_struct as *const wintun_raw::GUID; //SAFETY: the function is loaded from the wintun dll properly, we are providing valid @@ -118,7 +119,7 @@ impl Device { let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?; // 设置网卡跃点 if let Err(e) = netsh::set_interface_metric(index, 0) { - log::warn!("{:?}",e); + log::warn!("{:?}", e); } Ok(Self { luid: std::mem::transmute(luid), diff --git a/vnt/tun/src/windows/tun/wintun_log.rs b/vnt/tun/src/windows/tun/wintun_log.rs index aa505464..4472cf20 100644 --- a/vnt/tun/src/windows/tun/wintun_log.rs +++ b/vnt/tun/src/windows/tun/wintun_log.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] use log::*; use crate::windows::tun::wintun_raw; diff --git a/vnt/tun/src/windows/tun/wintun_raw.rs b/vnt/tun/src/windows/tun/wintun_raw.rs index 9e11d33d..e754bd5d 100644 --- a/vnt/tun/src/windows/tun/wintun_raw.rs +++ b/vnt/tun/src/windows/tun/wintun_raw.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] /* automatically generated by rust-bindgen 0.59.1 */ #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] From f6cfa1b84c8de9d6a1839c87e9c1848037997e9e Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Thu, 9 May 2024 22:51:27 +0800 Subject: [PATCH 18/22] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=AE=89=E5=8D=93?= =?UTF-8?q?=E7=AB=AFtun=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/handle/recv_data/server.rs | 3 +-- vnt/src/tun_tap_device/tun_create_helper.rs | 19 ++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/vnt/src/handle/recv_data/server.rs b/vnt/src/handle/recv_data/server.rs index 72eb14c2..71ce3d0b 100644 --- a/vnt/src/handle/recv_data/server.rs +++ b/vnt/src/handle/recv_data/server.rs @@ -320,8 +320,7 @@ impl ServerPacketHandler { "device_fd == 0".into(), )); } else { - let device = Arc::new(tun::Device::new(device_fd as _)?); - if let Err(e) = self.device.start(device) { + if let Err(e) = self.device.start(device_fd as _) { self.callback.error(ErrorInfo::new_msg( ErrorType::Unknown, format!("{:?}", e), diff --git a/vnt/src/tun_tap_device/tun_create_helper.rs b/vnt/src/tun_tap_device/tun_create_helper.rs index 576f9b1b..1b71ceae 100644 --- a/vnt/src/tun_tap_device/tun_create_helper.rs +++ b/vnt/src/tun_tap_device/tun_create_helper.rs @@ -26,7 +26,7 @@ impl DeviceAdapter { #[cfg(target_os = "android")] pub fn new(tun_device_helper: TunDeviceHelper) -> Self { Self { - tun: Arc::new(Mutex::new(None)), + tun: Arc::new(AtomicCell::new(-1 as _)), tun_device_helper, } } @@ -43,22 +43,19 @@ impl std::ops::Deref for DeviceAdapter { #[cfg(target_os = "android")] #[derive(Clone)] pub struct DeviceAdapter { - tun: Arc>>>, + tun: Arc>, tun_device_helper: TunDeviceHelper, } #[cfg(target_os = "android")] impl DeviceAdapter { pub fn write(&self, buf: &[u8]) -> io::Result { - if let Some(device) = self.tun.lock().as_ref() { - use tun::device::IFace; - device.write(buf) - } else { - Err(io::Error::new(io::ErrorKind::Other, "not tun device")) - } + let fd = self.tun.load(); + tun::Fd(fd).write(buf) } - pub fn start(&self, device: Arc) -> io::Result<()> { - self.tun_device_helper.start(device.clone())?; - self.tun.lock().replace(device); + pub fn start(&self, fd: std::os::fd::RawFd) -> io::Result<()> { + //安卓端fd是由外部释放的,所以这里这么搞免得加锁 + self.tun_device_helper.start(Arc::new(Device::new(fd)?))?; + self.tun.store(fd); Ok(()) } } From 699262d79e40bd19c5e60085c9daa768889d9732 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Fri, 10 May 2024 23:16:37 +0800 Subject: [PATCH 19/22] rustup set auto-self-update disable --- .github/workflows/rust.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 86e3eb6b..c7ae3246 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -105,6 +105,8 @@ jobs: run: | # dependencies are only needed on ubuntu as that's the only place where # we make cross-compilation + rustup set auto-self-update disable + if [[ $OS =~ ^ubuntu.*$ ]]; then sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools # curl -s musl.cc | grep mipsel @@ -136,6 +138,9 @@ jobs: # mips平台使用1.71.1版本 rustup install 1.71.1 rustup default 1.71.1 + else + rustup install 1.77 + rustup default 1.77 fi if [ -n "$MUSL_URI" ]; then @@ -144,8 +149,11 @@ jobs: tar zxf ./musl_gcc/$MUSL_URI.tgz -C ./musl_gcc/ sudo ln -s $(pwd)/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/ fi + else + rustup install 1.77 + rustup default 1.77 fi - + rustup -V # some additional configuration for cross-compilation on linux cat >>~/.cargo/config < Date: Fri, 10 May 2024 23:18:24 +0800 Subject: [PATCH 20/22] =?UTF-8?q?=E9=80=9A=E8=BF=87stun=E6=8E=A2=E6=B5=8B?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=EF=BC=8C=E8=A7=A3=E5=86=B3=E4=BD=BF=E7=94=A8?= =?UTF-8?q?ipv6=E6=88=96tcp=E6=9C=8D=E5=8A=A1=E6=97=B6=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/core/conn.rs | 4 ++ vnt/src/handle/maintain/addr_request.rs | 66 ++++++++++++++++++++----- vnt/src/handle/maintain/mod.rs | 2 +- vnt/src/handle/recv_data/mod.rs | 15 +++++- vnt/src/nat/mod.rs | 66 ++++++++++++++++++++++++- vnt/src/nat/stun.rs | 50 ++++++++++++++++--- 6 files changed, 181 insertions(+), 22 deletions(-) diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 9ed9b688..00308fb7 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -339,6 +339,7 @@ pub fn start( context.clone(), current_device.clone(), server_cipher.clone(), + nat_test.clone(), config_info.clone(), ); // 定时打洞 @@ -420,4 +421,7 @@ impl Vnt { pub fn wait_timeout(&self, dur: Duration) -> bool { self.stop_manager.wait_timeout(dur) } + pub fn config(&self) -> &Config { + &self.config + } } diff --git a/vnt/src/handle/maintain/addr_request.rs b/vnt/src/handle/maintain/addr_request.rs index 05412f5d..dc66f64f 100644 --- a/vnt/src/handle/maintain/addr_request.rs +++ b/vnt/src/handle/maintain/addr_request.rs @@ -4,8 +4,10 @@ use std::time::Duration; use crossbeam_utils::atomic::AtomicCell; use crate::channel::context::ChannelContext; +use crate::channel::punch::NatType; use crate::cipher::Cipher; use crate::handle::{BaseConfigInfo, CurrentDeviceInfo}; +use crate::nat::NatTest; use crate::protocol::body::ENCRYPTION_RESERVED; use crate::protocol::{control_packet, NetPacket, Protocol, MAX_TTL}; use crate::util::Scheduler; @@ -15,6 +17,7 @@ pub fn addr_request( context: ChannelContext, current_device_info: Arc>, server_cipher: Cipher, + nat_test: NatTest, _config: BaseConfigInfo, ) { pub_address_request( @@ -22,31 +25,67 @@ pub fn addr_request( context, current_device_info.clone(), server_cipher, + nat_test, + 0, ); } -pub fn pub_address_request( + +fn pub_address_request( scheduler: &Scheduler, context: ChannelContext, current_device_info: Arc>, server_cipher: Cipher, + nat_test: NatTest, + count: usize, ) { - addr_request0(&context, ¤t_device_info, &server_cipher); - // 9秒发送一次 - let rs = scheduler.timeout(Duration::from_secs(9), |s| { - pub_address_request(s, context, current_device_info, server_cipher) + let channel_num = context.channel_num(); + let index = count % channel_num; + let mut time = if index == channel_num - 1 { 19 } else { 1 }; + if let Err(e) = addr_request0( + &context, + ¤t_device_info, + &server_cipher, + &nat_test, + index, + ) { + log::warn!("{:?}", e); + } + let nat_info = nat_test.nat_info(); + if nat_info.nat_type == NatType::Symmetric { + //对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改) + if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() { + time = 600; + } + } + + let rs = scheduler.timeout(Duration::from_secs(time), move |s| { + pub_address_request( + s, + context, + current_device_info, + server_cipher, + nat_test, + index + 1, + ) }); if !rs { log::info!("定时任务停止"); } } -pub fn addr_request0( +fn addr_request0( context: &ChannelContext, current_device: &AtomicCell, server_cipher: &Cipher, -) { + nat_test: &NatTest, + index: usize, +) -> anyhow::Result<()> { let current_dev = current_device.load(); - if current_dev.connect_server.is_ipv4() && current_dev.status.online() { + if current_dev.status.offline() { + return Ok(()); + } + + if current_dev.connect_server.is_ipv4() && !context.is_main_tcp() { // 如果连接的是ipv4服务,则探测公网端口 let gateway_ip = current_dev.virtual_gateway; let src_ip = current_dev.virtual_ip; @@ -58,10 +97,11 @@ pub fn addr_request0( packet.first_set_ttl(MAX_TTL); packet.set_source(src_ip); packet.set_destination(gateway_ip); - if let Err(e) = server_cipher.encrypt_ipv4(&mut packet) { - log::warn!("AddrRequest err={:?}", e) - } else { - context.try_send_all_main(packet.buffer(), current_dev.connect_server); - } + server_cipher.encrypt_ipv4(&mut packet)?; + context.send_main_udp(index, packet.buffer(), current_dev.connect_server)?; + } else { + let (data, addr) = nat_test.send_data()?; + context.send_main_udp(index, &data, addr)?; } + Ok(()) } diff --git a/vnt/src/handle/maintain/mod.rs b/vnt/src/handle/maintain/mod.rs index 1055835f..5e9dfe0f 100644 --- a/vnt/src/handle/maintain/mod.rs +++ b/vnt/src/handle/maintain/mod.rs @@ -6,7 +6,7 @@ mod re_nat_type; pub use re_nat_type::retrieve_nat_type; mod addr_request; -pub use addr_request::addr_request; +pub use addr_request::*; mod punch; pub use punch::*; diff --git a/vnt/src/handle/recv_data/mod.rs b/vnt/src/handle/recv_data/mod.rs index 32420f64..b644edab 100644 --- a/vnt/src/handle/recv_data/mod.rs +++ b/vnt/src/handle/recv_data/mod.rs @@ -39,10 +39,22 @@ pub struct RecvDataHandler { client: ClientPacketHandler, server: ServerPacketHandler, counter: U64Adder, + nat_test: NatTest, } impl RecvChannelHandler for RecvDataHandler { fn handle(&mut self, buf: &mut [u8], route_key: RouteKey, context: &ChannelContext) { + //判断stun响应包 + if !route_key.is_tcp() { + if let Ok(rs) = self + .nat_test + .recv_data(route_key.index(), route_key.addr, buf) + { + if rs { + return; + } + } + } if let Err(e) = self.handle0(buf, route_key, context) { log::error!("[{}]-{:?}", thread::current().name().unwrap_or(""), e); } @@ -86,7 +98,7 @@ impl RecvDataHandler { client_cipher, punch_sender, peer_nat_info_map, - nat_test, + nat_test.clone(), route, #[cfg(feature = "ip_proxy")] ip_proxy_map, @@ -98,6 +110,7 @@ impl RecvDataHandler { client, server, counter, + nat_test, } } fn handle0( diff --git a/vnt/src/nat/mod.rs b/vnt/src/nat/mod.rs index ca28b053..b442c30f 100644 --- a/vnt/src/nat/mod.rs +++ b/vnt/src/nat/mod.rs @@ -1,5 +1,6 @@ +use anyhow::Context; use std::io; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; use std::net::{SocketAddr, UdpSocket}; use std::ops::Sub; use std::sync::Arc; @@ -7,6 +8,7 @@ use std::time::{Duration, Instant}; use crossbeam_utils::atomic::AtomicCell; use parking_lot::Mutex; +use rand::Rng; use crate::channel::punch::{NatInfo, NatType}; use crate::proto::message::PunchNatType; @@ -202,4 +204,66 @@ impl NatTest { Ok(guard.clone()) } + pub fn send_data(&self) -> anyhow::Result<(Vec, SocketAddr)> { + let len = self.stun_server.len(); + let stun_server = if len == 1 { + &self.stun_server[0] + } else { + let index = rand::thread_rng().gen_range(0..self.stun_server.len()); + &self.stun_server[index] + }; + let addr = stun_server + .to_socket_addrs()? + .next() + .with_context(|| format!("stun error {:?}", stun_server))?; + Ok((stun::send_stun_request(), addr)) + } + pub fn recv_data( + &self, + index: usize, + source_addr: SocketAddr, + buf: &[u8], + ) -> anyhow::Result { + if let Some(addr) = stun::recv_stun_response(buf) { + if let SocketAddr::V4(addr) = addr { + let mut check_fail = true; + let source_ip = match source_addr.ip() { + IpAddr::V4(ip) => ip, + IpAddr::V6(ip) => { + if let Some(ip) = ip.to_ipv4_mapped() { + ip + } else { + return Ok(false); + } + } + }; + 'a: for stun_server in &self.stun_server { + for x in stun_server.to_socket_addrs()? { + if source_addr.port() == x.port() { + if let IpAddr::V4(ip) = x.ip() { + if ip == source_ip { + check_fail = false; + break 'a; + } + }; + } + } + } + if check_fail { + return Ok(false); + } + let ip = addr.ip(); + if !ip.is_multicast() + && !ip.is_broadcast() + && !ip.is_unspecified() + && !ip.is_loopback() + && !ip.is_private() + { + self.update_addr(index, *addr.ip(), addr.port()); + return Ok(true); + } + } + } + return Ok(false); + } } diff --git a/vnt/src/nat/stun.rs b/vnt/src/nat/stun.rs index 08b5cba6..ef4a6362 100644 --- a/vnt/src/nat/stun.rs +++ b/vnt/src/nat/stun.rs @@ -4,6 +4,7 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::time::Duration; use crate::channel::punch::NatType; +use rand::RngCore; use std::net::UdpSocket; use stun_format::Attr; @@ -79,8 +80,7 @@ pub fn stun_test_nat0(stun_servers: Vec) -> io::Result<(NatType, Vec io::Result> { udp.connect(stun_server)?; - // 随便搞个当id - let tid = stun_server.as_ptr() as u128; + let tid = rand::thread_rng().next_u64() as u128; let mut addr = HashSet::new(); let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?; if mapped_addr1.is_ipv4() { @@ -119,13 +119,12 @@ fn test_nat_( for _ in 0..2 { let mut buf = [0u8; 28]; let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice()); - msg.typ(stun_format::MsgType::BindingRequest).unwrap(); - msg.tid(tid).unwrap(); + msg.typ(stun_format::MsgType::BindingRequest); + msg.tid(tid); msg.add_attr(Attr::ChangeRequest { change_ip, change_port, - }) - .unwrap(); + }); udp.send(msg.as_bytes())?; let mut buf = [0; 10240]; let (len, _addr) = match udp.recv_from(&mut buf) { @@ -178,3 +177,42 @@ fn stun_addr(addr: stun_format::SocketAddr) -> SocketAddr { } } } + +const TAG: u128 = 1827549368 << 64; + +pub fn send_stun_request() -> Vec { + let mut buf = [0u8; 28]; + let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice()); + msg.typ(stun_format::MsgType::BindingRequest); + let id = rand::thread_rng().next_u64() as u128; + msg.tid(id | TAG); + msg.add_attr(Attr::ChangeRequest { + change_ip: false, + change_port: false, + }); + msg.as_bytes().to_vec() +} + +pub fn recv_stun_response(buf: &[u8]) -> Option { + if buf[0] != 0x01 && buf[1] != 0x01 { + return None; + } + let msg = stun_format::Msg::from(buf); + if let Some(tid) = msg.tid() { + if tid & TAG != TAG { + return None; + } + } + for x in msg.attrs_iter() { + match x { + Attr::MappedAddress(addr) => { + return Some(stun_addr(addr)); + } + Attr::XorMappedAddress(addr) => { + return Some(stun_addr(addr)); + } + _ => {} + } + } + None +} From 9df324f402ddfd848250d12a2c900f00cea99447 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Fri, 10 May 2024 23:18:45 +0800 Subject: [PATCH 21/22] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E6=98=A0=E5=B0=84=E5=92=8Cip=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-cli/src/command/entity.rs | 4 +++ vnt-cli/src/command/mod.rs | 6 +++++ vnt-cli/src/console_out/mod.rs | 46 +++++++++++++++++++++++++++++++--- vnt/src/channel/punch.rs | 2 +- vnt/src/core/mod.rs | 7 +++++- 5 files changed, 59 insertions(+), 6 deletions(-) diff --git a/vnt-cli/src/command/entity.rs b/vnt-cli/src/command/entity.rs index 154127fd..5c06d18a 100644 --- a/vnt-cli/src/command/entity.rs +++ b/vnt-cli/src/command/entity.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::net::{Ipv4Addr, SocketAddr}; #[derive(Serialize, Deserialize, Debug)] pub struct Info { pub name: String, @@ -13,6 +14,9 @@ pub struct Info { pub ipv6_addr: String, pub up: u64, pub down: u64, + pub port_mapping_list: Vec<(bool, SocketAddr, String)>, + pub in_ips: Vec<(u32, u32, Ipv4Addr)>, + pub out_ips: Vec<(u32, u32)>, } #[derive(Serialize, Deserialize, Debug)] diff --git a/vnt-cli/src/command/mod.rs b/vnt-cli/src/command/mod.rs index e059c2cd..eee969c5 100644 --- a/vnt-cli/src/command/mod.rs +++ b/vnt-cli/src/command/mod.rs @@ -185,6 +185,9 @@ pub fn command_info(vnt: &Vnt) -> Info { .unwrap_or("None".to_string()); let up = vnt.up_stream(); let down = vnt.down_stream(); + let port_mapping_list = vnt.config().port_mapping_list.clone(); + let in_ips = vnt.config().in_ips.clone(); + let out_ips = vnt.config().out_ips.clone(); Info { name, virtual_ip, @@ -198,5 +201,8 @@ pub fn command_info(vnt: &Vnt) -> Info { ipv6_addr, up, down, + port_mapping_list, + in_ips, + out_ips, } } diff --git a/vnt-cli/src/console_out/mod.rs b/vnt-cli/src/console_out/mod.rs index 557987d7..44bde16c 100644 --- a/vnt-cli/src/console_out/mod.rs +++ b/vnt-cli/src/console_out/mod.rs @@ -1,4 +1,5 @@ use console::{style, Style}; +use std::net::Ipv4Addr; use crate::command::entity::{DeviceItem, Info, RouteItem}; @@ -9,10 +10,15 @@ pub fn console_info(status: Info) { println!("Virtual ip: {}", style(status.virtual_ip).green()); println!("Virtual gateway: {}", style(status.virtual_gateway).green()); println!("Virtual netmask: {}", style(status.virtual_netmask).green()); - println!( - "Connection status: {}", - style(status.connect_status).green() - ); + if status.connect_status.eq_ignore_ascii_case("Connected") { + println!( + "Connection status: {}", + style(status.connect_status).green() + ); + } else { + println!("Connection status: {}", style(status.connect_status).red()); + } + println!("NAT type: {}", style(status.nat_type).green()); println!("Relay server: {}", style(status.relay_server).green()); println!("Public ips: {}", style(status.public_ips).green()); @@ -20,6 +26,38 @@ pub fn console_info(status: Info) { println!("IPv6: {}", style(status.ipv6_addr).green()); println!("Up: {}", style(convert(status.up)).green()); println!("Down: {}", style(convert(status.down)).green()); + + if !status.port_mapping_list.is_empty() { + println!("------------------------------------------"); + println!("Port mapping {}", status.port_mapping_list.len()); + for (is_tcp, addr, dest) in status.port_mapping_list { + if is_tcp { + println!(" TCP: {} -> {}", addr, dest) + } else { + println!(" UDP: {} -> {}", addr, dest) + } + } + } + if !status.in_ips.is_empty() || !status.out_ips.is_empty() { + println!("------------------------------------------"); + } + if !status.in_ips.is_empty() { + println!("IP forwarding {}", status.in_ips.len()); + for (dest, mask, ip) in status.in_ips { + println!( + " -- {} --> {}/{}", + ip, + Ipv4Addr::from(dest), + mask.count_ones() + ) + } + } + if !status.out_ips.is_empty() { + println!("Allows network {}", status.out_ips.len()); + for (dest, mask) in status.out_ips { + println!(" {}/{}", Ipv4Addr::from(dest), mask.count_ones()) + } + } } fn convert(num: u64) -> String { diff --git a/vnt/src/channel/punch.rs b/vnt/src/channel/punch.rs index 004b80a1..6c424a56 100644 --- a/vnt/src/channel/punch.rs +++ b/vnt/src/channel/punch.rs @@ -103,7 +103,7 @@ impl NatInfo { if port != 0 { if let Some(public_port) = self.public_ports.get_mut(index) { if *public_port != port { - log::info!("端口变化={}:{}", ip, port) + log::info!("端口变化={}:{} index={}", ip, port, index) } *public_port = port; } diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index 4c0d7284..bd1da8e8 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -57,7 +57,7 @@ impl Config { server_address_str: String, mut name_servers: Vec, mut stun_server: Vec, - in_ips: Vec<(u32, u32, Ipv4Addr)>, + mut in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32)>, password: Option, mtu: Option, @@ -103,6 +103,11 @@ impl Config { address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?; #[cfg(feature = "port_mapping")] let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?; + + for (dest, mask, _) in &mut in_ips { + *dest = *mask & *dest; + } + in_ips.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1)); Ok(Self { #[cfg(target_os = "windows")] tap, From 0e4294415e78c626a85605d9f9a763737c0b1412 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Fri, 10 May 2024 23:19:52 +0800 Subject: [PATCH 22/22] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 29 +++++++++++ vnt-jni/Cargo.toml | 3 ++ .../java/top/wherewego/vnt/jni/Config.java | 48 ++++++++++++++----- vnt-jni/src/lib.rs | 1 + vnt-jni/src/vnt.rs | 2 +- vnt-jni/src/vnt_logger.rs | 12 +++++ vnt/src/ip_proxy/icmp_proxy.rs | 12 +++-- 7 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 vnt-jni/src/vnt_logger.rs diff --git a/Cargo.lock b/Cargo.lock index 8a797cb4..b7858798 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,6 +67,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +[[package]] +name = "android_log-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" + +[[package]] +name = "android_logger" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f" +dependencies = [ + "android_log-sys", + "env_logger", + "log", + "once_cell", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -382,6 +400,16 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "log", + "regex", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1618,6 +1646,7 @@ dependencies = [ name = "vnt-jni" version = "1.2.9" dependencies = [ + "android_logger", "common", "jni", "log", diff --git a/vnt-jni/Cargo.toml b/vnt-jni/Cargo.toml index 00610d8e..339c3f5d 100644 --- a/vnt-jni/Cargo.toml +++ b/vnt-jni/Cargo.toml @@ -14,5 +14,8 @@ jni = { version = "0.21.1", default-features = false } log = "0.4.20" spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64","pem"]} +[target.'cfg(target_os = "android")'.dependencies] +android_logger = "0.13" + [lib] crate-type = ["staticlib", "cdylib"] \ No newline at end of file diff --git a/vnt-jni/java/top/wherewego/vnt/jni/Config.java b/vnt-jni/java/top/wherewego/vnt/jni/Config.java index 342127dc..2bfe7eed 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/Config.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/Config.java @@ -1,13 +1,16 @@ package top.wherewego.vnt.jni; +import java.io.Serializable; +import java.util.Arrays; + /** * 启动配置 * * @author https://github.com/lbl8603/vnt */ -public class Config { +public class Config implements Serializable { /** - * 是否是tap模式,仅支持windows和linux + * 是否是tap模式,仅支持windows */ private boolean tap; /** @@ -38,10 +41,6 @@ public class Config { * 是否开启服务端加密 */ private boolean serverEncrypt; - /** - * 仅使用中继转发 - */ - private boolean relay; /** * 设备id,请使用唯一值 */ @@ -174,13 +173,6 @@ public void setServerEncrypt(boolean serverEncrypt) { this.serverEncrypt = serverEncrypt; } - public boolean isRelay() { - return relay; - } - - public void setRelay(boolean relay) { - this.relay = relay; - } public String getDeviceId() { return deviceId; @@ -308,4 +300,34 @@ public Integer getPacketDelay() { public void setPacketDelay(Integer packetDelay) { this.packetDelay = packetDelay; } + + @Override + public String toString() { + return "Config{" + + "tap=" + tap + + ", token='" + token + '\'' + + ", name='" + name + '\'' + + ", password='" + password + '\'' + + ", cipherModel='" + cipherModel + '\'' + + ", punchModel='" + punchModel + '\'' + + ", mtu=" + mtu + + ", serverEncrypt=" + serverEncrypt + + ", deviceId='" + deviceId + '\'' + + ", server='" + server + '\'' + + ", dns=" + Arrays.toString(dns) + + ", portMapping=" + Arrays.toString(portMapping) + + ", stunServer=" + Arrays.toString(stunServer) + + ", tcp=" + tcp + + ", ip='" + ip + '\'' + + ", finger=" + finger + + ", firstLatency=" + firstLatency + + ", inIps=" + Arrays.toString(inIps) + + ", outIps=" + Arrays.toString(outIps) + + ", ports=" + Arrays.toString(ports) + + ", deviceName='" + deviceName + '\'' + + ", useChannel='" + useChannel + '\'' + + ", packetLossRate=" + packetLossRate + + ", packetDelay=" + packetDelay + + '}'; + } } diff --git a/vnt-jni/src/lib.rs b/vnt-jni/src/lib.rs index 898137c3..7ec5f133 100644 --- a/vnt-jni/src/lib.rs +++ b/vnt-jni/src/lib.rs @@ -2,3 +2,4 @@ pub mod callback; pub mod config; pub mod utils; pub mod vnt; +pub(crate) mod vnt_logger; diff --git a/vnt-jni/src/vnt.rs b/vnt-jni/src/vnt.rs index 03fe4c5f..6156b080 100644 --- a/vnt-jni/src/vnt.rs +++ b/vnt-jni/src/vnt.rs @@ -11,7 +11,6 @@ use vnt::core::Vnt; use vnt::handle::PeerDeviceInfo; use crate::callback::CallBack; - #[no_mangle] pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0( mut env: JNIEnv<'static>, @@ -19,6 +18,7 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0( config: JObject, call_back: JObject<'static>, ) -> jlong { + crate::vnt_logger::init_log(); let jvm = if let Ok(jvm) = env.get_java_vm() { jvm } else { diff --git a/vnt-jni/src/vnt_logger.rs b/vnt-jni/src/vnt_logger.rs new file mode 100644 index 00000000..56b64eb7 --- /dev/null +++ b/vnt-jni/src/vnt_logger.rs @@ -0,0 +1,12 @@ +#[cfg(target_os = "android")] +pub fn init_log() { + use android_logger::Config; + use log::LevelFilter; + android_logger::init_once( + Config::default() + .with_max_level(LevelFilter::Info) // limit log level + .with_tag("vnt_jni"), // logs will show under mytag tag + ); +} +#[cfg(not(target_os = "android"))] +pub fn init_log() {} diff --git a/vnt/src/ip_proxy/icmp_proxy.rs b/vnt/src/ip_proxy/icmp_proxy.rs index 7c4f68fa..fc8f26a3 100644 --- a/vnt/src/ip_proxy/icmp_proxy.rs +++ b/vnt/src/ip_proxy/icmp_proxy.rs @@ -166,11 +166,17 @@ fn recv_handle( } } } - _ => {} + h => { + log::warn!("不支持的icmp代理 {:?},{:?}", peer_ip, h) + } }, - Err(_) => {} + Err(e) => { + log::warn!("icmp {:?}", e) + } }, - Err(_) => {} + Err(e) => { + log::warn!("icmp {:?}", e) + } } }