diff --git a/common/src/cli.rs b/common/src/cli.rs index d340ade..01f82f2 100644 --- a/common/src/cli.rs +++ b/common/src/cli.rs @@ -363,7 +363,7 @@ fn get_description(key: &str, language: &str) -> String { ("--ip ", ("指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配", "Specify virtual IP, must be unique and valid within server subnet, by default allocated by server")), ("--model ", ("加密模式(默认aes_gcm),可选值{}", "Encryption mode (default aes_gcm), options {}")), ("--finger", ("增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启", "Add data fingerprint verification for increased security, client must enable if server does")), - ("--punch ", ("取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞", "Values ipv4/ipv6/all, ipv4 for IPv4 hole punching only")), + ("--punch ", ("取值ipv4/ipv6/ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-udp/all,ipv4表示仅使用ipv4打洞", "Values ipv4/ipv6/ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-udp/all, ipv4 for IPv4 hole punching only")), ("--ports ", ("取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担", "Values 0~65535, specify a group of local listening ports, defaults to two random ports, using many ports increases network load")), ("--cmd", ("开启交互式命令,使用此参数开启控制台输入", "Enable interactive command mode, use this parameter to enable console input")), ("--no-proxy", ("关闭内置代理,如需点对网则需要配置网卡NAT转发", "Disable built-in proxy, configure network card NAT forwarding for point-to-point networking")), diff --git a/vnt/src/channel/punch.rs b/vnt/src/channel/punch.rs index 07764a8..cb735c1 100644 --- a/vnt/src/channel/punch.rs +++ b/vnt/src/channel/punch.rs @@ -14,15 +14,38 @@ use crate::channel::context::ChannelContext; use crate::channel::sender::ConnectUtil; use crate::external_route::ExternalRoute; use crate::handle::CurrentDeviceInfo; -use crate::nat::NatTest; +use crate::nat::{is_ipv4_global, NatTest}; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum PunchModel { IPv4, IPv6, + IPv4Tcp, + IPv4Udp, + IPv6Tcp, + IPv6Udp, All, } - +impl PunchModel { + pub fn use_tcp(&self) -> bool { + self != &PunchModel::IPv4Udp && self != &PunchModel::IPv6Udp + } + pub fn use_udp(&self) -> bool { + self != &PunchModel::IPv4Tcp && self != &PunchModel::IPv6Tcp + } + pub fn use_ipv6(&self) -> bool { + self == &PunchModel::All + || self == &PunchModel::IPv6 + || self == &PunchModel::IPv6Tcp + || self == &PunchModel::IPv6Udp + } + pub fn use_ipv4(&self) -> bool { + self == &PunchModel::All + || self == &PunchModel::IPv4 + || self == &PunchModel::IPv4Tcp + || self == &PunchModel::IPv4Udp + } +} impl FromStr for PunchModel { type Err = String; @@ -30,8 +53,15 @@ impl FromStr for PunchModel { match s.to_lowercase().trim() { "ipv4" => Ok(PunchModel::IPv4), "ipv6" => Ok(PunchModel::IPv6), + "ipv4-tcp" => Ok(PunchModel::IPv4Tcp), + "ipv4-udp" => Ok(PunchModel::IPv4Udp), + "ipv6-tcp" => Ok(PunchModel::IPv6Tcp), + "ipv6-udp" => Ok(PunchModel::IPv6Udp), "all" => Ok(PunchModel::All), - _ => Err(format!("not match '{}', enum: ipv4/ipv6/all", s)), + _ => Err(format!( + "not match '{}', enum: ipv4/ipv4-tcp/ipv4-udp/ipv6/ipv6-tcp/ipv6-udp/all", + s + )), } } } @@ -187,7 +217,6 @@ pub struct Punch { port_vec: Vec, port_index: HashMap, punch_model: PunchModel, - is_tcp: bool, connect_util: ConnectUtil, external_route: ExternalRoute, nat_test: NatTest, @@ -198,7 +227,6 @@ impl Punch { pub fn new( context: ChannelContext, punch_model: PunchModel, - is_tcp: bool, connect_util: ConnectUtil, external_route: ExternalRoute, nat_test: NatTest, @@ -213,7 +241,6 @@ impl Punch { port_vec, port_index: HashMap::new(), punch_model, - is_tcp, connect_util, external_route, nat_test, @@ -242,48 +269,53 @@ impl Punch { return Ok(()); } let device_info = self.current_device.load(); + nat_info.public_ips.retain(|ip| { + is_ipv4_global(ip) + && self.external_route.route(ip).is_none() + && device_info.not_in_network(*ip) + }); + nat_info.public_ports.retain(|port| *port != 0); + nat_info.udp_ports.retain(|port| *port != 0); + + nat_info.local_ipv4 = nat_info.local_ipv4.filter(|ip| { self.external_route.route(ip).is_none() && device_info.not_in_network(*ip) }); - nat_info.local_ipv4.filter(|ip| { - self.external_route.route(ip).is_none() && device_info.not_in_network(*ip) - }); - nat_info.ipv6.filter(|ip| { + nat_info.ipv6 = nat_info.ipv6.filter(|ip| { if let Some(ip) = ip.to_ipv4() { self.external_route.route(&ip).is_none() } else { true } }); - if punch_tcp && self.is_tcp && nat_info.tcp_port != 0 { + if punch_tcp && self.punch_model.use_tcp() && nat_info.tcp_port != 0 { //向tcp发起连接 - if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() { - self.connect_tcp(buf, ipv6_addr) + if self.punch_model.use_ipv6() { + if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() { + self.connect_tcp(buf, ipv6_addr) + } } - //向tcp发起连接 - if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() { - self.connect_tcp(buf, ipv4_addr) - } - for ip in &nat_info.public_ips { - let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.tcp_port)); - self.connect_tcp(buf, addr) - } - } - let channel_num = self.context.channel_num(); - for index in 0..channel_num { - if let Some(ipv4_addr) = nat_info.local_udp_ipv4addr(index) { - if !self.nat_test.is_local_address(false, ipv4_addr) { - let _ = self.context.send_main_udp(index, buf, ipv4_addr); + if self.punch_model.use_ipv4() { + if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() { + self.connect_tcp(buf, ipv4_addr) + } + for ip in &nat_info.public_ips { + let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.tcp_port)); + self.connect_tcp(buf, addr) } } } + if !self.punch_model.use_udp() { + return Ok(()); + } + let channel_num = self.context.channel_num(); - if self.punch_model != PunchModel::IPv4 { + if self.punch_model.use_ipv6() { for index in 0..channel_num { if let Some(ipv6_addr) = nat_info.local_udp_ipv6addr(index) { if !self.nat_test.is_local_address(false, ipv6_addr) { let rs = self.context.send_main_udp(index, buf, ipv6_addr); - log::info!("发送到ipv6地址:{:?},rs={:?}", ipv6_addr, rs); + log::info!("发送到ipv6地址:{:?},rs={:?} {}", ipv6_addr, rs, id); if rs.is_ok() && self.punch_model == PunchModel::IPv6 { return Ok(()); } @@ -291,6 +323,33 @@ impl Punch { } } } + if !self.punch_model.use_ipv4() { + return Ok(()); + } + for index in 0..channel_num { + if let Some(ipv4_addr) = nat_info.local_udp_ipv4addr(index) { + if !self.nat_test.is_local_address(false, ipv4_addr) { + let _ = self.context.send_main_udp(index, buf, ipv4_addr); + } + } + } + // 可能是开放了端口的,需要打洞 + for index in 0..channel_num { + for port in &nat_info.udp_ports { + if *port == 0 { + continue; + } + for ip in &nat_info.public_ips { + if ip.is_unspecified() { + continue; + } + let addr = SocketAddrV4::new(*ip, *port); + let _ = self.context.send_main_udp(index, buf, addr.into()); + thread::sleep(Duration::from_millis(3)); + } + } + } + match nat_info.nat_type { NatType::Symmetric => { // 假设对方绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,自己随机尝试k次的情况下 diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index cacd907..d41a874 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -266,7 +266,6 @@ impl VntInner { let punch = Punch::new( context.clone(), config.punch_model, - config.protocol.is_base_tcp(), connect_util.clone(), external_route.clone(), nat_test.clone(),