From 147156d96d4afd4858de45a3d255929e05d72873 Mon Sep 17 00:00:00 2001 From: lubeilin <1791778603@qq.com> Date: Tue, 5 Mar 2024 21:32:20 +0800 Subject: [PATCH] =?UTF-8?q?[mio]=20=E5=A2=9E=E5=8A=A0=E6=A8=A1=E6=8B=9F?= =?UTF-8?q?=E5=BC=B1=E7=BD=91=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-cli/src/config/mod.rs | 6 ++++ vnt-cli/src/main.rs | 19 ++++++++---- vnt-jni/src/config.rs | 2 ++ vnt/src/channel/context.rs | 42 ++++++++++++++++++++++++++- vnt/src/channel/mod.rs | 11 ++++++- vnt/src/core/conn.rs | 2 ++ vnt/src/core/mod.rs | 7 +++++ vnt/src/handle/tun_tap/mod.rs | 7 +---- vnt/src/handle/tun_tap/tun_handler.rs | 10 +++---- 9 files changed, 87 insertions(+), 19 deletions(-) diff --git a/vnt-cli/src/config/mod.rs b/vnt-cli/src/config/mod.rs index a2c733f..4416ffa 100644 --- a/vnt-cli/src/config/mod.rs +++ b/vnt-cli/src/config/mod.rs @@ -37,6 +37,8 @@ pub struct FileConfig { pub cmd: bool, pub first_latency: bool, pub device_name: Option, + pub packet_loss: Option, + pub packet_delay: u32, } impl Default for FileConfig { @@ -71,6 +73,8 @@ impl Default for FileConfig { cmd: false, first_latency: false, device_name: None, + packet_loss: None, + packet_delay: 0, } } } @@ -166,6 +170,8 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { file_conf.first_latency, file_conf.device_name, use_channel_type, + file_conf.packet_loss, + file_conf.packet_delay ) .unwrap(); Ok((config, file_conf.cmd)) diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs index d060c0a..1202c26 100644 --- a/vnt-cli/src/main.rs +++ b/vnt-cli/src/main.rs @@ -68,12 +68,9 @@ fn main() { opts.optflag("", "cmd", "开启窗口输入"); opts.optflag("", "no-proxy", "关闭内置代理"); opts.optflag("", "first-latency", "优先延迟"); - opts.optopt( - "", - "use-channel", - "使用通道 relay/p2p,默认两者都使用", - "", - ); + opts.optopt("", "use-channel", "使用通道 relay/p2p", ""); + opts.optopt("", "packet-loss", "丢包率", ""); + opts.optopt("", "packet-delay", "延迟", ""); opts.optopt("f", "", "配置文件", ""); //"后台运行时,查看其他设备列表" opts.optflag("", "list", "后台运行时,查看其他设备列表"); @@ -294,6 +291,12 @@ fn main() { #[cfg(feature = "ip_proxy")] let no_proxy = matches.opt_present("no-proxy"); let first_latency = matches.opt_present("first-latency"); + let packet_loss = matches + .opt_get::("packet-loss") + .expect("--packet-loss"); + let packet_delay = matches + .opt_get::("packet-delay") + .expect("--packet-delay").unwrap_or(0); let config = Config::new( #[cfg(any(target_os = "windows", target_os = "linux"))] tap, @@ -320,6 +323,8 @@ fn main() { first_latency, device_name, use_channel_type, + packet_loss, + packet_delay ) .unwrap(); (config, cmd) @@ -461,6 +466,8 @@ fn print_usage(program: &str, _opts: Options) { println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道"); println!(" --use-channel 使用通道 relay/p2p/all,默认两者都使用"); println!(" --nic 指定虚拟网卡名称"); + println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网"); + println!(" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"); println!(); println!( diff --git a/vnt-jni/src/config.rs b/vnt-jni/src/config.rs index d71536a..21df406 100644 --- a/vnt-jni/src/config.rs +++ b/vnt-jni/src/config.rs @@ -132,6 +132,8 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { #[cfg(target_os = "android")] device_fd, UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(), + None, + 0, ) { Ok(config) => config, Err(e) => { diff --git a/vnt/src/channel/context.rs b/vnt/src/channel/context.rs index 7195225..d7f2cad 100644 --- a/vnt/src/channel/context.rs +++ b/vnt/src/channel/context.rs @@ -8,6 +8,7 @@ use std::time::{Duration, Instant}; use crossbeam_utils::atomic::AtomicCell; use parking_lot::RwLock; +use rand::Rng; use crate::channel::punch::NatType; use crate::channel::sender::{AcceptSocketSender, ChannelSender, PacketSender}; @@ -26,9 +27,21 @@ impl Context { use_channel_type: UseChannelType, first_latency: bool, is_tcp: bool, + packet_loss_rate: Option, + packet_delay: u32, ) -> Self { let channel_num = main_udp_socket.len(); assert_ne!(channel_num, 0, "not channel"); + let packet_loss_rate = packet_loss_rate + .map(|v| { + let v = (v * PACKET_LOSS_RATE_DENOMINATOR as f64) as u32; + if v > PACKET_LOSS_RATE_DENOMINATOR { + PACKET_LOSS_RATE_DENOMINATOR + } else { + v + } + }) + .unwrap_or(0); let inner = ContextInner { main_udp_socket, sub_udp_socket: RwLock::new(Vec::with_capacity(64)), @@ -36,6 +49,8 @@ impl Context { route_table: RouteTable::new(use_channel_type, first_latency, channel_num), is_tcp, state: AtomicBool::new(true), + packet_loss_rate, + packet_delay, }; Self { inner: Arc::new(inner), @@ -56,7 +71,7 @@ impl Deref for Context { /// 对称网络增加的udp socket数目,有助于增加打洞成功率 pub const SYMMETRIC_CHANNEL_NUM: usize = 64; - +const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000; pub struct ContextInner { // 核心udp socket pub(crate) main_udp_socket: Vec, @@ -70,6 +85,10 @@ pub struct ContextInner { is_tcp: bool, //状态 state: AtomicBool, + //控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000 + packet_loss_rate: u32, + //控制延迟 + packet_delay: u32, } impl ContextInner { @@ -230,6 +249,27 @@ impl ContextInner { } } } + /// 发送网络数据 + pub fn send_ipv4_by_id( + &self, + buf: &[u8], + id: &Ipv4Addr, + server_addr: SocketAddr, + ) -> io::Result<()> { + if self.packet_loss_rate > 0 { + if rand::thread_rng().gen_ratio(self.packet_loss_rate, PACKET_LOSS_RATE_DENOMINATOR) { + return Ok(()); + } + } + if self.packet_delay > 0 { + std::thread::sleep(Duration::from_millis(self.packet_delay as _)); + } + if self.send_by_id(buf, id).is_err() && !self.route_table.use_channel_type.is_only_p2p() { + self.send_default(buf, server_addr) + } else { + Ok(()) + } + } /// 将数据发到指定id pub fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<()> { let route = self.route_table.get_route_by_id(id)?; diff --git a/vnt/src/channel/mod.rs b/vnt/src/channel/mod.rs index 2b06a07..3d44ae4 100644 --- a/vnt/src/channel/mod.rs +++ b/vnt/src/channel/mod.rs @@ -141,6 +141,8 @@ pub fn init_context( use_channel_type: UseChannelType, first_latency: bool, is_tcp: bool, + packet_loss_rate: Option, + packet_delay: u32, ) -> io::Result<(Context, mio::net::TcpListener)> { assert!(!ports.is_empty(), "not channel"); let mut udps = Vec::with_capacity(ports.len()); @@ -158,7 +160,14 @@ pub fn init_context( main_channel.set_write_timeout(Some(Duration::from_secs(5)))?; udps.push(main_channel); } - let context = Context::new(udps, use_channel_type, first_latency, is_tcp); + let context = Context::new( + udps, + use_channel_type, + first_latency, + is_tcp, + packet_loss_rate, + packet_delay, + ); let port = context.main_local_udp_port()?[0]; //监听v6+v4双栈,tcp通道使用异步io diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 8d92817..c424d7f 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -93,6 +93,8 @@ impl Vnt { config.use_channel_type, config.first_latency, config.tcp, + config.packet_loss_rate, + config.packet_delay, )?; let local_ipv4 = nat::local_ipv4(); let local_ipv6 = nat::local_ipv6(); diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index 920d157..b53ac46 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -39,6 +39,9 @@ pub struct Config { #[cfg(target_os = "android")] pub device_fd: i32, pub use_channel_type: UseChannelType, + //控制丢包率 + pub packet_loss_rate: Option, + pub packet_delay: u32, } impl Config { @@ -67,6 +70,8 @@ impl Config { #[cfg(not(target_os = "android"))] device_name: Option, #[cfg(target_os = "android")] device_fd: i32, use_channel_type: UseChannelType, + packet_loss_rate: Option, + packet_delay: u32, ) -> io::Result { for x in stun_server.iter_mut() { if !x.contains(":") { @@ -111,6 +116,8 @@ impl Config { #[cfg(target_os = "android")] device_fd, use_channel_type, + packet_loss_rate, + packet_delay, }) } } diff --git a/vnt/src/handle/tun_tap/mod.rs b/vnt/src/handle/tun_tap/mod.rs index 3f557b7..8659e18 100644 --- a/vnt/src/handle/tun_tap/mod.rs +++ b/vnt/src/handle/tun_tap/mod.rs @@ -150,10 +150,5 @@ pub fn base_handle( } client_cipher.encrypt_ipv4(&mut net_packet)?; //优先发到直连到地址 - if context.send_by_id(net_packet.buffer(), &dest_ip).is_err() { - if !context.use_channel_type().is_only_p2p() { - context.send_default(net_packet.buffer(), current_device.connect_server)?; - } - } - return Ok(()); + context.send_ipv4_by_id(net_packet.buffer(), &dest_ip, current_device.connect_server) } diff --git a/vnt/src/handle/tun_tap/tun_handler.rs b/vnt/src/handle/tun_tap/tun_handler.rs index b7ae2e3..c849309 100644 --- a/vnt/src/handle/tun_tap/tun_handler.rs +++ b/vnt/src/handle/tun_tap/tun_handler.rs @@ -47,11 +47,11 @@ fn handle( client_cipher: &Cipher, server_cipher: &Cipher, ) -> io::Result<()> { - if len > 12 && data[12] >> 4 != 4 { - //忽略非ipv4包 - return Ok(()); - } - let ipv4_packet = IpV4Packet::new(&mut data[12..len])?; + //忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了 + let ipv4_packet = match IpV4Packet::new(&mut data[12..len]) { + Ok(packet) => packet, + Err(_) => return Ok(()), + }; let src_ip = ipv4_packet.source_ip(); let dest_ip = ipv4_packet.destination_ip(); if src_ip == dest_ip {