From bbfa255dd37b33053378b77cca0fce65ac86e06e Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Mon, 29 Apr 2024 23:23:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=8E=AF=E8=B7=AF=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/channel/punch.rs | 47 ++++++++++++-------- vnt/src/core/conn.rs | 1 + vnt/src/handle/recv_data/client.rs | 41 +++++++++++++++++ vnt/src/nat/mod.rs | 70 +++++++++++++++++++++++++++++- 4 files changed, 139 insertions(+), 20 deletions(-) diff --git a/vnt/src/channel/punch.rs b/vnt/src/channel/punch.rs index ee3de88..9c29088 100644 --- a/vnt/src/channel/punch.rs +++ b/vnt/src/channel/punch.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::str::FromStr; use std::time::Duration; use std::{io, thread}; @@ -11,6 +11,7 @@ use rand::Rng; use crate::channel::context::Context; use crate::channel::sender::AcceptSocketSender; use crate::external_route::ExternalRoute; +use crate::nat::NatTest; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum PunchModel { @@ -187,6 +188,7 @@ pub struct Punch { is_tcp: bool, tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option>)>, external_route: ExternalRoute, + nat_test: NatTest, } impl Punch { @@ -196,6 +198,7 @@ impl Punch { is_tcp: bool, tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option>)>, external_route: ExternalRoute, + nat_test: NatTest, ) -> Self { let mut port_vec: Vec = (1..65535).collect(); port_vec.push(65535); @@ -209,19 +212,16 @@ impl Punch { is_tcp, tcp_socket_sender, external_route, + nat_test, } } } impl Punch { fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) -> bool { - if let IpAddr::V4(ip) = addr.ip() { - if self.external_route.route(&ip).is_some() { - log::warn!("跳过打洞目标{},防止环路 ", addr); - return false; - } + if self.nat_test.is_local_address(true, addr) { + return false; } - // mio是非阻塞的,不能立马判断是否能连接成功,所以用标准库的tcp match std::net::TcpStream::connect_timeout(&addr, Duration::from_millis(100)) { Ok(tcp_stream) => { @@ -243,13 +243,26 @@ impl Punch { &mut self, buf: &[u8], id: Ipv4Addr, - nat_info: NatInfo, + mut nat_info: NatInfo, punch_tcp: bool, ) -> io::Result<()> { if self.context.route_table.no_need_punch(&id) { log::info!("已打洞成功,无需打洞:{:?}", id); return Ok(()); } + nat_info + .public_ips + .retain(|ip| self.external_route.route(&ip).is_none()); + nat_info + .local_ipv4 + .filter(|ip| self.external_route.route(&ip).is_none()); + nat_info.ipv6.filter(|ip| { + if let Some(ip) = ip.to_ipv4_mapped() { + self.external_route.route(&ip).is_none() + } else { + true + } + }); if punch_tcp && self.is_tcp && nat_info.tcp_port != 0 { //向tcp发起连接 if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() { @@ -274,23 +287,21 @@ impl Punch { 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 let IpAddr::V4(ip) = ipv4_addr.ip() { - if self.external_route.route(&ip).is_some() { - log::warn!("跳过打洞目标{},防止环路", ipv4_addr); - continue; - } + if !self.nat_test.is_local_address(false, ipv4_addr) { + let _ = self.context.send_main_udp(index, buf, ipv4_addr); } - let _ = self.context.send_main_udp(index, buf, ipv4_addr); } } if self.punch_model != PunchModel::IPv4 { for index in 0..channel_num { if let Some(ipv6_addr) = nat_info.local_udp_ipv6addr(index) { - let rs = self.context.send_main_udp(index, buf, ipv6_addr); - log::info!("发送到ipv6地址:{:?},rs={:?}", ipv6_addr, rs); - if rs.is_ok() && self.punch_model == PunchModel::IPv6 { - return Ok(()); + 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); + if rs.is_ok() && self.punch_model == PunchModel::IPv6 { + return Ok(()); + } } } } diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 03f0da1..852391b 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -212,6 +212,7 @@ impl Vnt { config.tcp, tcp_socket_sender.clone(), external_route.clone(), + nat_test.clone(), ); #[cfg(not(target_os = "android"))] diff --git a/vnt/src/handle/recv_data/client.rs b/vnt/src/handle/recv_data/client.rs index 3b86fc2..f53f9a2 100644 --- a/vnt/src/handle/recv_data/client.rs +++ b/vnt/src/handle/recv_data/client.rs @@ -29,6 +29,7 @@ use crate::protocol::{ use crate::tun_tap_device::tun_create_helper::DeviceAdapter; #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] use tun::device::IFace; + /// 处理来源于客户端的包 #[derive(Clone)] pub struct ClientPacketHandler { @@ -142,6 +143,31 @@ impl ClientPacketHandler { //拦截不符合的目标 return Ok(()); } + match ipv4.protocol() { + ipv4::protocol::Protocol::Tcp => { + let payload = ipv4.payload(); + if payload.len() < 20 { + return Ok(()); + } + let destination_port = + u16::from_be_bytes(payload[2..4].try_into().unwrap()); + if self.nat_test.is_local_tcp(real_dest, destination_port) { + return Ok(()); + } + } + ipv4::protocol::Protocol::Udp => { + let payload = ipv4.payload(); + if payload.len() < 8 { + return Ok(()); + } + let destination_port = + u16::from_be_bytes(payload[2..4].try_into().unwrap()); + if self.nat_test.is_local_udp(real_dest, destination_port) { + return Ok(()); + } + } + _ => {} + } #[cfg(feature = "ip_proxy")] if let Some(ip_proxy_map) = &self.ip_proxy_map { if ip_proxy_map.recv_handle(&mut ipv4, source, destination)? { @@ -192,6 +218,15 @@ impl ClientPacketHandler { if context.use_channel_type().is_only_relay() { return Ok(()); } + //忽略掉来源于自己的包 + if route_key.is_tcp() {} + if self + .nat_test + .is_local_address(route_key.is_tcp(), route_key.addr) + { + return Ok(()); + } + //回应 net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into()); net_packet.set_source(current_device.virtual_ip); @@ -207,6 +242,12 @@ impl ClientPacketHandler { if context.use_channel_type().is_only_relay() { return Ok(()); } + if self + .nat_test + .is_local_address(route_key.is_tcp(), route_key.addr) + { + return Ok(()); + } let route = Route::from_default_rt(route_key, 1); context.route_table.add_route_if_absent(source, route); } diff --git a/vnt/src/nat/mod.rs b/vnt/src/nat/mod.rs index d416fdf..ddecc75 100644 --- a/vnt/src/nat/mod.rs +++ b/vnt/src/nat/mod.rs @@ -1,6 +1,6 @@ use std::io; -use std::net::UdpSocket; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::net::{SocketAddr, UdpSocket}; use std::ops::Sub; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -22,6 +22,7 @@ pub fn local_ipv4_() -> io::Result { IpAddr::V6(_) => Ok(Ipv4Addr::UNSPECIFIED), } } + pub fn local_ipv4() -> Option { match local_ipv4_() { Ok(ipv4) => Some(ipv4), @@ -41,6 +42,7 @@ pub fn local_ipv6_() -> io::Result { IpAddr::V6(ip) => Ok(ip), } } + pub fn local_ipv6() -> Option { match local_ipv6_() { Ok(ipv6) => Some(ipv6), @@ -56,6 +58,8 @@ pub struct NatTest { stun_server: Vec, info: Arc>, time: Arc>, + udp_ports: Vec, + tcp_port: u16, } impl From for PunchNatType { @@ -94,7 +98,7 @@ impl NatTest { 0, local_ipv4, ipv6, - udp_ports, + udp_ports.clone(), tcp_port, NatType::Cone, ); @@ -105,6 +109,8 @@ impl NatTest { time: Arc::new(AtomicCell::new( Instant::now().sub(Duration::from_secs(100)), )), + udp_ports, + tcp_port, } } pub fn can_update(&self) -> bool { @@ -116,6 +122,66 @@ impl NatTest { pub fn nat_info(&self) -> NatInfo { self.info.lock().clone() } + pub fn is_local_udp(&self, ipv4: Ipv4Addr, port: u16) -> bool { + for x in &self.udp_ports { + if x == &port { + let guard = self.info.lock(); + if let Some(ip) = guard.local_ipv4 { + if ipv4 == ip { + return true; + } + } + break; + } + } + false + } + pub fn is_local_tcp(&self, ipv4: Ipv4Addr, port: u16) -> bool { + if self.tcp_port == port { + let guard = self.info.lock(); + if let Some(ip) = guard.local_ipv4 { + if ipv4 == ip { + return true; + } + } + } + false + } + pub fn is_local_address(&self, is_tcp: bool, addr: SocketAddr) -> bool { + let port = addr.port(); + let check_ip = || { + let guard = self.info.lock(); + match addr.ip() { + IpAddr::V4(ipv4) => { + if let Some(ip) = guard.local_ipv4 { + if ipv4 == ip { + return true; + } + } + } + IpAddr::V6(ipv6) => { + if let Some(ip) = guard.ipv6 { + if ipv6 == ip { + return true; + } + } + } + } + false + }; + if is_tcp { + if self.tcp_port == port { + return check_ip(); + } + } else { + for x in &self.udp_ports { + if x == &port { + return check_ip(); + } + } + } + false + } pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) { let mut guard = self.info.lock(); guard.update_addr(index, ip, port)