From 965cbfbb7ee049ce6b0cce6c011f5eff666580e4 Mon Sep 17 00:00:00 2001 From: jslyrd Date: Tue, 16 Jul 2024 22:32:48 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=8B=B1=E6=96=87?= =?UTF-8?q?=E5=B8=AE=E5=8A=A9=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/Cargo.toml | 1 + common/src/cli.rs | 404 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 318 insertions(+), 87 deletions(-) diff --git a/common/Cargo.toml b/common/Cargo.toml index 80fa20b..fae5719 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -16,6 +16,7 @@ serde_yaml = "0.9.32" getopts = "0.2.21" gethostname = "0.4.3" uuid = { version = "1.8.0", features = ["v4"] } +sys-locale = "0.3.1" [features] default = [] diff --git a/common/src/cli.rs b/common/src/cli.rs index f5c5c8b..af86454 100644 --- a/common/src/cli.rs +++ b/common/src/cli.rs @@ -5,10 +5,12 @@ use crate::{config, generated_serial_number}; use anyhow::anyhow; use console::style; use getopts::Options; +use std::collections::HashMap; use std::io; use std::net::Ipv4Addr; use std::path::PathBuf; use std::str::FromStr; +use sys_locale::get_locale; use vnt::channel::punch::PunchModel; use vnt::channel::UseChannelType; use vnt::cipher::CipherModel; @@ -43,48 +45,145 @@ pub fn parse_args_config() -> anyhow::Result, bool)> let args: Vec = std::env::args().collect(); let program = args[0].clone(); let mut opts = Options::new(); - opts.optopt("k", "", "组网标识", ""); - opts.optopt("n", "", "设备名称", ""); - opts.optopt("d", "", "设备标识", ""); - opts.optflag("c", "", "关闭交互式命令"); - opts.optopt("s", "", "注册和中继服务器地址", ""); - opts.optmulti("e", "", "stun服务器", ""); - opts.optflag("a", "", "使用tap模式"); - opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", ""); - opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", ""); - opts.optmulti("o", "", "配置点对网出站时使用", ""); - opts.optopt("w", "", "客户端加密", ""); - opts.optflag("W", "", "服务端加密"); - opts.optopt("u", "", "自定义mtu(默认为1430)", ""); - opts.optopt("", "ip", "指定虚拟ip", ""); - opts.optflag("", "relay", "仅使用服务器转发"); - opts.optopt("", "par", "任务并行度(必须为正整数)", ""); - opts.optopt("", "model", "加密模式", ""); - opts.optflag("", "finger", "指纹校验"); - opts.optopt("", "punch", "取值ipv4/ipv6", ""); - opts.optopt("", "ports", "监听的端口", ""); - opts.optflag("", "cmd", "开启窗口输入"); - opts.optflag("", "no-proxy", "关闭内置代理"); - opts.optflag("", "first-latency", "优先延迟"); - opts.optopt("", "use-channel", "使用通道 relay/p2p", ""); - opts.optopt("", "packet-loss", "丢包率", ""); - opts.optopt("", "packet-delay", "延迟", ""); - opts.optmulti("", "dns", "dns", ""); - opts.optmulti("", "mapping", "mapping", ""); - opts.optmulti("", "vnt-mapping", "vnt-mapping", ""); - opts.optopt("f", "", "配置文件", ""); - opts.optopt("", "compressor", "压缩算法", ""); - opts.optflag("", "disable-stats", "关闭流量统计"); - //"后台运行时,查看其他设备列表" - opts.optflag("", "add", "后台运行时,添加地址"); - opts.optflag("", "list", "后台运行时,查看其他设备列表"); - opts.optflag("", "all", "后台运行时,查看其他设备完整信息"); - opts.optflag("", "info", "后台运行时,查看当前设备信息"); - opts.optflag("", "route", "后台运行时,查看数据转发路径"); - opts.optflag("", "chart_a", "后台运行时,查看流量统计"); - opts.optopt("", "chart_b", "后台运行时,查看流量统计", ""); - opts.optflag("", "stop", "停止后台运行"); - opts.optflag("h", "help", "帮助"); + // 获取系统语言 + let language = get_locale().unwrap_or_else(|| String::from("en-US")); + if language.starts_with("zh") { + opts.optopt("k", "", "组网标识", ""); + opts.optopt("n", "", "设备名称", ""); + opts.optopt("d", "", "设备标识", ""); + opts.optflag("c", "", "关闭交互式命令"); + opts.optopt("s", "", "注册和中继服务器地址", ""); + opts.optmulti("e", "", "stun服务器", ""); + opts.optflag("a", "", "使用tap模式"); + opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", ""); + opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", ""); + opts.optmulti("o", "", "配置点对网出站时使用", ""); + opts.optopt("w", "", "客户端加密", ""); + opts.optflag("W", "", "服务端加密"); + opts.optopt("u", "", "自定义mtu(默认为1430)", ""); + opts.optopt("", "ip", "指定虚拟ip", ""); + opts.optflag("", "relay", "仅使用服务器转发"); + opts.optopt("", "par", "任务并行度(必须为正整数)", ""); + opts.optopt("", "model", "加密模式", ""); + opts.optflag("", "finger", "指纹校验"); + opts.optopt("", "punch", "取值ipv4/ipv6", ""); + opts.optopt("", "ports", "监听的端口", ""); + opts.optflag("", "cmd", "开启窗口输入"); + opts.optflag("", "no-proxy", "关闭内置代理"); + opts.optflag("", "first-latency", "优先延迟"); + opts.optopt("", "use-channel", "使用通道 relay/p2p", ""); + opts.optopt("", "packet-loss", "丢包率", ""); + opts.optopt("", "packet-delay", "延迟", ""); + opts.optmulti("", "dns", "dns", ""); + opts.optmulti("", "mapping", "mapping", ""); + opts.optmulti("", "vnt-mapping", "vnt-mapping", ""); + opts.optopt("f", "", "配置文件", ""); + opts.optopt("", "compressor", "压缩算法", ""); + opts.optflag("", "disable-stats", "关闭流量统计"); + //"后台运行时,查看其他设备列表" + opts.optflag("", "add", "后台运行时,添加地址"); + opts.optflag("", "list", "后台运行时,查看其他设备列表"); + opts.optflag("", "all", "后台运行时,查看其他设备完整信息"); + opts.optflag("", "info", "后台运行时,查看当前设备信息"); + opts.optflag("", "route", "后台运行时,查看数据转发路径"); + opts.optflag("", "chart_a", "后台运行时,查看流量统计"); + opts.optopt("", "chart_b", "后台运行时,查看流量统计", ""); + opts.optflag("", "stop", "停止后台运行"); + opts.optflag("h", "help", "帮助"); + } else { + opts.optopt("k", "", "Network token", ""); + opts.optopt("n", "", "Network name", ""); + opts.optopt("d", "", "Device id", ""); + opts.optflag("c", "", "Close interactive command"); + opts.optopt( + "s", + "", + "registration and relay server addresses", + "", + ); + opts.optmulti("e", "", "STUN servers", ""); + opts.optflag("a", "", "Tap mode"); + opts.optopt( + "", + "nic", + "Virtual network adapter name, required when using Tap mode on Windows", + "", + ); + opts.optmulti( + "i", + "", + "Configuring inbound point-to-site (IP proxy) usage", + "", + ); + opts.optmulti( + "o", + "", + "Configuring outbound point-to-site usage", + "", + ); + opts.optopt("w", "", "Client encryption", ""); + opts.optflag("W", "", "Server-side encryption"); + opts.optopt("u", "", "Customize MTU (default is 1430)", ""); + opts.optopt("", "ip", "Specify virtual IP", ""); + opts.optflag("", "relay", "Use server-side forwarding only"); + opts.optopt( + "", + "par", + "Concurrency level (must be a positive integer)", + "", + ); + opts.optopt("", "model", "Encryption mode", ""); + opts.optflag("", "finger", "Fingerprint verification"); + opts.optopt("", "punch", "Value can be either IPv4 or IPv6", ""); + opts.optopt("", "ports", "Listening port", ""); + opts.optflag("", "cmd", "Enable window input"); + opts.optflag("", "no-proxy", "Disable built-in proxy"); + opts.optflag("", "first-latency", "Priority delay"); + opts.optopt("", "use-channel", "Use channel relay/p2p", ""); + opts.optopt("", "packet-loss", "Packet loss rate", ""); + opts.optopt("", "packet-delay", "Latency", ""); + opts.optmulti("", "dns", "dns", ""); + opts.optmulti("", "mapping", "mapping", ""); + opts.optmulti("", "vnt-mapping", "vnt-mapping", ""); + opts.optopt("f", "", "Configuration file", ""); + opts.optopt("", "compressor", "Compression algorithm", ""); + opts.optflag("", "disable-stats", "Disable traffic statistics"); + //"后台运行时,查看其他设备列表" + opts.optflag("", "add", "When running in the background, add an address"); + opts.optflag( + "", + "list", + "When running in the background, view the list of other devices", + ); + opts.optflag( + "", + "all", + "When running in the background, view comprehensive information about other devices", + ); + opts.optflag( + "", + "info", + "When running in the background, view information about the current device", + ); + opts.optflag( + "", + "route", + "When running in the background, view the data forwarding path", + ); + opts.optflag( + "", + "chart_a", + "When running in the background, view traffic statistics", + ); + opts.optopt( + "", + "chart_b", + "When running in the background, view traffic statistics", + "", + ); + opts.optflag("", "stop", "Stop running in the background"); + opts.optflag("h", "help", "help"); + } let matches = match opts.parse(&args[1..]) { Ok(m) => m, Err(f) => { @@ -113,10 +212,13 @@ pub fn parse_args_config() -> anyhow::Result, bool)> } else if matches.opt_present("all") { command::command(command::CommandEnum::All); return Ok(None); - } else if matches.opt_present("chart_a") { + } + #[cfg(feature = "command")] + if matches.opt_present("chart_a") { command::command(command::CommandEnum::ChartA); return Ok(None); } + #[cfg(feature = "command")] if let Some(v) = matches.opt_str("chart_b") { command::command(command::CommandEnum::ChartB(v)); return Ok(None); @@ -337,38 +439,122 @@ pub fn parse_args_config() -> anyhow::Result, bool)> Ok(Some((config, vnt_link_config, cmd))) } +fn get_description(key: &str, language: &str) -> String { + // 设置一个全局的映射来存储中英文对照 + let descriptions: HashMap<&str, (&str, &str)> = [ + ("-k ", ("使用相同的token,就能组建一个局域网络", "Use the same token to form a local network")), + ("-n ", ("给设备一个名字,便于区分不同设备,默认使用系统版本", "Give the device a name to distinguish it, defaults to system version")), + ("-d ", ("设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复", "Device unique identifier, used by the server to allocate virtual IP when --ip parameter is not used, must be unique")), + ("-s ", ("注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://", "Registration and relay server address, protocols support using tcp://, ws://, and wss://, default is udp://")), + ("-e ", ("stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com", "STUN server for detecting NAT type, can specify multiple addresses, e.g., -e stun.miwifi.com -e turn.cloudflare.com")), + ("-a", ("使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡", "Use tap mode, default is tun mode, specify '--nic' parameter with tap network card")), + ("-i ", ("配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3,可指定多个网段", "Used when configuring point-to-point network (IP proxy), -i 192.168.0.0/24,10.26.0.3 allows receiving data from subnet 192.168.0.0/24 and forwarding to 10.26.0.3, specify multiple subnets")), + ("-o ", ("配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段", "Used when configuring point-to-point network, -o 192.168.0.0/24 allows forwarding data to 192.168.0.0/24, specify multiple subnets")), + ("-w ", ("使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "Encrypt client data with keys generated by this password, server cannot decrypt, clients must use the same password to communicate")), + ("-W", ("加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确", "Encrypt the data currently being communicated between the client and server, please pay attention to whether the server fingerprint is correct")), + ("-u ", ("自定义mtu(不加密默认为1450,加密默认为1410", "Customize MTU (1450 by default without encryption, 1410 with encryption)")), + ("-f ", ("读取配置文件中的配置", "Read configuration from file")), + ("--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")), + ("--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")), + ("--first-latency", ("优先低延迟的通道,默认情况优先使用p2p通道", "Prioritize low-latency channels, defaults to prioritizing p2p channel")), + ("--use-channel ", ("使用通道 relay/p2p/all,默认两者都使用", "Use channel relay/p2p/all, defaults to using both")), + ("--nic ", ("指定虚拟网卡名称", "Specify virtual network card name")), + ("--packet-loss <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate packet loss, value between 0 and 1, program actively drops packets based on set probability, useful for simulating weak networks")), + ("--packet-delay <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate latency, integer, in milliseconds (ms). The program will delay sending packets according to the set value and can be used to simulate weak networks")), + ("--dns ", ("DNS服务器地址,可使用多个dns,不指定时使用系统解析", "DNS server address, can specify multiple DNS servers, defaults to system resolution if not specified")), + ("--mapping ", ("端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备", "Port mapping, e.g., --mapping udp:0.0.0.0:80-domain:80 maps to a device accessible by local routing")), + ("--compressor-all ", ("启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10", "Enable compression, options lz4/zstd<,level>, level is compression level, e.g., --compressor lz4 or --compressor zstd,10")), + ("--compressor-lz4 ", ("启用压缩,可选值lz4,例如 --compressor lz4", "Enable compression, option lz4, e.g., --compressor lz4")), + ("--compressor-zstd ", ("启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10", "Enable compression, options zstd<,level>, level is compression level, e.g., --compressor zstd,10")), + ("--vnt-mapping ", ("vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备", "VNT address mapping, e.g., --vnt-mapping tcp:80-10.26.0.10:80 maps to a device in VNT network or its subnet")), + ("--disable-stats", ("关闭流量统计", "Disable traffic statistics")), + ("--list", ("后台运行时,查看其他设备列表", "View list of other devices when running in background")), + ("--all", ("后台运行时,查看其他设备完整信息", "View complete information of other devices when running in background")), + ("--info", ("后台运行时,查看当前设备信息", "View information of current device when running in background")), + ("--route", ("后台运行时,查看数据转发路径", "View data forwarding path when running in background")), + ("--chart_a", ("后台运行时,查看所有IP的流量统计", "View traffic statistics of all IPs when running in background")), + ("--chart_b ", ("后台运行时,查看单个IP的历史流量", "View historical traffic of a single IP when running in background")), + ("--stop", ("停止后台运行", "Stop running in background")) + // ... 其他选项 + ] + .iter() + .cloned() + .collect(); + + if let Some(&(zh, en)) = descriptions.get(key) { + if language.starts_with("zh") { + return zh.to_string(); // 返回 String 类型 + } + // 默认返回英文 + return en.to_string(); // 返回 String 类型 + } + // 如果没有找到对应的键,则返回空字符串 + String::new() +} + fn print_usage(program: &str, _opts: Options) { + // 获取系统语言 Locale::user_default().unwrap_or_else(|_| Locale::default()); + let language = get_locale().unwrap_or_else(|| String::from("en-US")); println!("Usage: {} [options]", program); println!("version:{}", vnt::VNT_VERSION); println!("Serial:{}", generated_serial_number::SERIAL_NUMBER); println!("Options:"); println!( " -k {}", - green("使用相同的token,就能组建一个局域网络".to_string()) + green(get_description("-k ", &language).to_string()) ); - println!(" -n 给设备一个名字,便于区分不同设备,默认使用系统版本"); - println!(" -d 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复"); println!( - " -s 注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://" + " -n {}", + get_description("-n ", &language) + ); + println!( + " -d {}", + get_description("-d ", &language) + ); + println!( + " -s {}", + get_description("-s ", &language) + ); + println!( + " -e {}", + get_description("-e ", &language) ); - println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com"); #[cfg(target_os = "windows")] #[cfg(feature = "integrated_tun")] + println!(" -a {}", get_description("-a", &language)); println!( - " -a 使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡" + " -i {}", + get_description("-i ", &language) + ); + println!( + " -o {}", + get_description("-o ", &language) + ); + println!( + " -w {}", + get_description("-w ", &language) ); - println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); - println!(" 并转发到10.26.0.3,可指定多个网段"); - println!(" -o 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段"); - - println!(" -w 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信"); #[cfg(feature = "server_encrypt")] - println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确"); - println!(" -u 自定义mtu(不加密默认为1450,加密默认为1410)"); + println!(" -W {}", get_description("-W", &language)); + println!( + " -u {}", + get_description("-u ", &language) + ); #[cfg(feature = "file_config")] - println!(" -f 读取配置文件中的配置"); + println!( + " -f {}", + get_description("-f ", &language) + ); - println!(" --ip 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配"); + println!( + " --ip {}", + get_description("--ip ", &language) + ); let mut enums = String::new(); #[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))] enums.push_str("/aes_gcm"); @@ -382,7 +568,8 @@ fn print_usage(program: &str, _opts: Options) { enums.push_str("/sm4_cbc"); enums.push_str("/xor"); println!( - " --model 加密模式(默认aes_gcm),可选值{}", + " --model {}{}", + get_description("--model ", &language), &enums[1..] ); #[cfg(any( @@ -393,45 +580,88 @@ fn print_usage(program: &str, _opts: Options) { feature = "aes_ecb", feature = "sm4_cbc" ))] - println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启"); - println!(" --punch 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞"); - println!(" --ports 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担"); + println!( + " --finger {}", + get_description("--finger", &language) + ); + println!( + " --punch {}", + get_description("--punch ", &language) + ); + println!( + " --ports {}", + get_description("--ports ", &language) + ); #[cfg(feature = "command")] - println!(" --cmd 开启交互式命令,使用此参数开启控制台输入"); + println!( + " --cmd {}", + get_description("--cmd", &language) + ); #[cfg(feature = "ip_proxy")] #[cfg(feature = "integrated_tun")] - println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发"); - println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道"); - println!(" --use-channel 使用通道 relay/p2p/all,默认两者都使用"); + println!( + " --no-proxy {}", + get_description("--no-proxy", &language) + ); + println!( + " --first-latency {}", + get_description("--first-latency", &language) + ); + println!( + " --use-channel {}", + get_description("--use-channel ", &language) + ); #[cfg(not(feature = "vn-link-model"))] - println!(" --nic 指定虚拟网卡名称"); - println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网"); println!( - " --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网" + " --nic {}", + get_description("--nic ", &language) + ); + println!( + " --packet-loss <0> {}", + get_description("--packet-loss <0>", &language) + ); + println!( + " --packet-delay <0> {}", + get_description("--packet-delay <0>", &language) + ); + println!( + " --dns {}", + get_description("--dns ", &language) ); - println!(" --dns DNS服务器地址,可使用多个dns,不指定时使用系统解析"); #[cfg(feature = "port_mapping")] - println!(" --mapping 端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备"); + println!( + " --mapping {}", + get_description("--mapping ", &language) + ); #[cfg(all(feature = "lz4", feature = "zstd"))] - println!(" --compressor 启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10"); + println!( + " --compressor {}", + get_description("--compressor-all ", &language) + ); #[cfg(feature = "lz4")] #[cfg(not(feature = "zstd"))] - println!(" --compressor 启用压缩,可选值lz4,例如 --compressor lz4"); + println!( + " --compressor {}", + get_description("--compressor-lz4 ", &language) + ); #[cfg(feature = "zstd")] #[cfg(not(feature = "lz4"))] - println!(" --compressor 启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10"); + println!( + " --compressor {}", + get_description("--compressor-zstd ", &language) + ); #[cfg(not(feature = "integrated_tun"))] println!( " --vnt-mapping {}", - green( - "vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备" - .to_string() - ) + green(get_description("--vnt-mapping ", &language).to_string()) + ); + println!( + " --disable-stats {}", + get_description("--disable-stats", &language) ); - println!(" --disable-stats 关闭流量统计"); println!(); #[cfg(feature = "command")] { @@ -442,34 +672,34 @@ fn print_usage(program: &str, _opts: Options) { // ); println!( " --list {}", - yellow("后台运行时,查看其他设备列表".to_string()) + yellow(get_description("--list", &language).to_string()) ); println!( " --all {}", - yellow("后台运行时,查看其他设备完整信息".to_string()) + yellow(get_description("--all", &language).to_string()) ); println!( " --info {}", - yellow("后台运行时,查看当前设备信息".to_string()) + yellow(get_description("--info", &language).to_string()) ); println!( " --route {}", - yellow("后台运行时,查看数据转发路径".to_string()) + yellow(get_description("--route", &language).to_string()) ); println!( " --chart_a {}", - yellow("后台运行时,查看所有IP的流量统计".to_string()) + yellow(get_description("--chart_a", &language).to_string()) ); println!( " --chart_b {}", - yellow("后台运行时,查看单个IP的历史流量".to_string()) + yellow(get_description("--chart_b ", &language).to_string()) ); println!( " --stop {}", - yellow("停止后台运行".to_string()) + yellow(get_description("--stop", &language).to_string()) ); } - println!(" -h, --help 帮助"); + println!(" -h, --help display help information(显示帮助信息)"); } fn green(str: String) -> impl std::fmt::Display { From 7ebdffcdd3c5f0ed47e832381ddfb61cda78621e Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Sat, 20 Jul 2024 10:38:18 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=94=AF=E6=8C=81wg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/src/cli.rs | 4 + common/src/command/entity.rs | 1 + common/src/command/mod.rs | 1 + common/src/config/file_config.rs | 4 + common/src/console_out/mod.rs | 22 +++-- vn-link-cli/Cargo.toml | 2 +- vnt/proto/message.proto | 1 + vnt/src/channel/punch.rs | 5 +- vnt/src/channel/sender.rs | 90 +++++++++++++++++++-- vnt/src/core/conn.rs | 35 ++++---- vnt/src/core/mod.rs | 4 + vnt/src/handle/maintain/heartbeat.rs | 44 +++++----- vnt/src/handle/maintain/punch.rs | 18 ++--- vnt/src/handle/mod.rs | 9 +++ vnt/src/handle/recv_data/client.rs | 3 + vnt/src/handle/recv_data/mod.rs | 4 +- vnt/src/handle/recv_data/server.rs | 27 +++++-- vnt/src/handle/tun_tap/tun_handler.rs | 54 ++++++++++--- vnt/src/handle/tun_tap/unix.rs | 14 +++- vnt/src/handle/tun_tap/windows.rs | 14 +++- vnt/src/protocol/ip_turn_packet.rs | 11 ++- vnt/src/tun_tap_device/tun_create_helper.rs | 13 +-- 22 files changed, 282 insertions(+), 98 deletions(-) diff --git a/common/src/cli.rs b/common/src/cli.rs index e66bab8..23f533b 100644 --- a/common/src/cli.rs +++ b/common/src/cli.rs @@ -75,6 +75,7 @@ pub fn parse_args_config() -> anyhow::Result, bool)> opts.optopt("f", "", "配置文件", ""); opts.optopt("", "compressor", "压缩算法", ""); opts.optflag("", "disable-stats", "关闭流量统计"); + opts.optflag("", "allow-wg", "允许接入WireGuard"); //"后台运行时,查看其他设备列表" opts.optflag("", "add", "后台运行时,添加地址"); opts.optflag("", "list", "后台运行时,查看其他设备列表"); @@ -281,6 +282,7 @@ pub fn parse_args_config() -> anyhow::Result, bool)> let port_mapping_list = matches.opt_strs("mapping"); let vnt_mapping_list = matches.opt_strs("vnt-mapping"); let disable_stats = matches.opt_present("disable-stats"); + let allow_wire_guard = matches.opt_present("allow-wg"); let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() { Compressor::from_str(compressor) .map_err(|e| anyhow!("{}", e)) @@ -321,6 +323,7 @@ pub fn parse_args_config() -> anyhow::Result, bool)> port_mapping_list, compressor, !disable_stats, + allow_wire_guard, ) { Ok(config) => config, Err(e) => { @@ -435,6 +438,7 @@ fn print_usage(program: &str, _opts: Options) { ) ); println!(" --disable-stats 关闭流量统计"); + println!(" --allow-wg 允许接入WireGuard客户端"); println!(); #[cfg(feature = "command")] { diff --git a/common/src/command/entity.rs b/common/src/command/entity.rs index b42f054..9770897 100644 --- a/common/src/command/entity.rs +++ b/common/src/command/entity.rs @@ -45,6 +45,7 @@ pub struct DeviceItem { pub client_secret_hash: Vec, pub current_client_secret: bool, pub current_client_secret_hash: Vec, + pub wire_guard: bool, } #[derive(Serialize, Deserialize, Debug, Default)] diff --git a/common/src/command/mod.rs b/common/src/command/mod.rs index b408b88..2ffa8bc 100644 --- a/common/src/command/mod.rs +++ b/common/src/command/mod.rs @@ -219,6 +219,7 @@ pub fn command_list(vnt: &Vnt) -> Vec { client_secret_hash: peer.client_secret_hash, current_client_secret, current_client_secret_hash: client_encrypt_hash.to_vec(), + wire_guard: peer.wireguard, }; list.push(item); } diff --git a/common/src/config/file_config.rs b/common/src/config/file_config.rs index 2c9b24e..c5b2b1b 100644 --- a/common/src/config/file_config.rs +++ b/common/src/config/file_config.rs @@ -46,6 +46,8 @@ pub struct FileConfig { pub compressor: Option, pub vnt_mapping: Vec, pub disable_stats: bool, + // 允许传递wg流量 + pub allow_wire_guard: bool, } impl Default for FileConfig { @@ -90,6 +92,7 @@ impl Default for FileConfig { compressor: None, vnt_mapping: vec![], disable_stats: false, + allow_wire_guard: false, } } } @@ -177,6 +180,7 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, Vec, bool file_conf.mapping, compressor, !file_conf.disable_stats, + file_conf.allow_wire_guard, )?; Ok((config, file_conf.vnt_mapping, file_conf.cmd)) diff --git a/common/src/console_out/mod.rs b/common/src/console_out/mod.rs index 2efde46..3a3bc7c 100644 --- a/common/src/console_out/mod.rs +++ b/common/src/console_out/mod.rs @@ -132,15 +132,21 @@ pub fn console_device_list(mut list: Vec) { ("Rt".to_string(), Style::new()), ]); for item in list { + let name = if item.wire_guard { + format!("{}(wg)", item.name) + } else { + item.name + }; if &item.status == "Online" { - if item.client_secret != item.current_client_secret - || (!item.current_client_secret_hash.is_empty() - && !item.client_secret_hash.is_empty() - && item.current_client_secret_hash != item.client_secret_hash) + if !item.wire_guard + && (item.client_secret != item.current_client_secret + || (!item.current_client_secret_hash.is_empty() + && !item.client_secret_hash.is_empty() + && item.current_client_secret_hash != item.client_secret_hash)) { //加密状态不一致,无法通信的 out_list.push(vec![ - (item.name, Style::new().red()), + (name, Style::new().red()), (item.virtual_ip, Style::new().red()), (item.status, Style::new().red()), ("Mismatch".to_string(), Style::new().red()), @@ -149,7 +155,7 @@ pub fn console_device_list(mut list: Vec) { } else { if item.nat_traversal_type.contains("p2p") { out_list.push(vec![ - (item.name, Style::new().green()), + (name, Style::new().green()), (item.virtual_ip, Style::new().green()), (item.status, Style::new().green()), (item.nat_traversal_type, Style::new().green()), @@ -157,7 +163,7 @@ pub fn console_device_list(mut list: Vec) { ]); } else { out_list.push(vec![ - (item.name, Style::new().yellow()), + (name, Style::new().yellow()), (item.virtual_ip, Style::new().yellow()), (item.status, Style::new().yellow()), (item.nat_traversal_type, Style::new().yellow()), @@ -167,7 +173,7 @@ pub fn console_device_list(mut list: Vec) { } } else { out_list.push(vec![ - (item.name, Style::new().color256(102)), + (name, Style::new().color256(102)), (item.virtual_ip, Style::new().color256(102)), (item.status, Style::new().color256(102)), ("".to_string(), Style::new().color256(102)), diff --git a/vn-link-cli/Cargo.toml b/vn-link-cli/Cargo.toml index 8a1d4b7..e4e3559 100644 --- a/vn-link-cli/Cargo.toml +++ b/vn-link-cli/Cargo.toml @@ -11,7 +11,7 @@ log = "0.4.17" [features] default = ["default-feature"] -default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4"] +default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4", "ws"] openssl = ["vn-link/openssl", "common/openssl"] openssl-vendored = ["vn-link/openssl-vendored", "common/openssl-vendored"] diff --git a/vnt/proto/message.proto b/vnt/proto/message.proto index 47e9e97..197c884 100644 --- a/vnt/proto/message.proto +++ b/vnt/proto/message.proto @@ -43,6 +43,7 @@ message DeviceInfo { uint32 device_status = 3; bool client_secret = 4; bytes client_secret_hash = 5; + bool wireguard = 6; } message DeviceList { diff --git a/vnt/src/channel/punch.rs b/vnt/src/channel/punch.rs index 5b2a760..07764a8 100644 --- a/vnt/src/channel/punch.rs +++ b/vnt/src/channel/punch.rs @@ -264,9 +264,8 @@ impl Punch { if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() { self.connect_tcp(buf, ipv4_addr) } - if nat_info.nat_type == NatType::Cone && nat_info.public_ips.len() == 1 { - let addr = - SocketAddr::V4(SocketAddrV4::new(nat_info.public_ips[0], nat_info.tcp_port)); + for ip in &nat_info.public_ips { + let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.tcp_port)); self.connect_tcp(buf, addr) } } diff --git a/vnt/src/channel/sender.rs b/vnt/src/channel/sender.rs index 08e9252..5cfa27c 100644 --- a/vnt/src/channel/sender.rs +++ b/vnt/src/channel/sender.rs @@ -1,9 +1,11 @@ +use std::collections::HashMap; use std::io; use std::net::{Ipv4Addr, SocketAddr}; use std::sync::mpsc::{SyncSender, TrySendError}; use std::sync::Arc; use crossbeam_utils::atomic::AtomicCell; +use parking_lot::Mutex; use tokio::sync::mpsc::Sender; use crate::channel::context::ChannelContext; @@ -11,7 +13,7 @@ use crate::channel::notify::AcceptNotify; use crate::cipher::Cipher; use crate::compression::Compressor; use crate::external_route::ExternalRoute; -use crate::handle::CurrentDeviceInfo; +use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; use crate::protocol; use crate::protocol::{ip_turn_packet, NetPacket}; @@ -21,7 +23,10 @@ pub struct IpPacketSender { current_device: Arc>, compressor: Compressor, client_cipher: Cipher, + server_cipher: Cipher, ip_route: ExternalRoute, + device_map: Arc)>>, + allow_wire_guard: bool, } impl IpPacketSender { @@ -30,14 +35,20 @@ impl IpPacketSender { current_device: Arc>, compressor: Compressor, client_cipher: Cipher, + server_cipher: Cipher, ip_route: ExternalRoute, + device_map: Arc)>>, + allow_wire_guard: bool, ) -> Self { Self { context, current_device, compressor, client_cipher, + server_cipher, ip_route, + device_map, + allow_wire_guard, } } pub fn self_virtual_ip(&self) -> Ipv4Addr { @@ -58,19 +69,54 @@ impl IpPacketSender { if let Some(v) = self.ip_route.route(&dest_ip) { dest_ip = v; } - if dest_ip.is_multicast() || dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip { + if dest_ip.is_multicast() { //广播 dest_ip = Ipv4Addr::BROADCAST; } - let mut net_packet = NetPacket::new0(data_len, buf)?; - let mut auxiliary = NetPacket::new(auxiliary_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 self.allow_wire_guard { + if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip { + let exists_wg = self + .device_map + .lock() + .1 + .values() + .any(|v| v.status.is_online() && v.wireguard); + if exists_wg { + send_to_wg_broadcast( + &self.context, + &net_packet, + &self.server_cipher, + &device_info, + )?; + } + } else { + let guard = self.device_map.lock(); + if let Some(peer_info) = guard.1.get(&dest_ip) { + if peer_info.wireguard { + if peer_info.status.is_offline() { + return Ok(()); + } + drop(guard); + send_to_wg( + &self.context, + &mut net_packet, + &self.server_cipher, + &device_info, + )?; + return Ok(()); + } + } + } + } + + let mut auxiliary = NetPacket::new(auxiliary_buf)?; let mut net_packet = if self.compressor.compress(&net_packet, &mut auxiliary)? { auxiliary.set_default_version(); @@ -84,7 +130,7 @@ impl IpPacketSender { net_packet }; self.client_cipher.encrypt_ipv4(&mut net_packet)?; - if dest_ip.is_broadcast() { + if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip { //走服务端广播 self.context .send_default(&net_packet, device_info.connect_server)?; @@ -105,6 +151,40 @@ impl IpPacketSender { } } +pub fn send_to_wg_broadcast( + sender: &ChannelContext, + net_packet: &NetPacket<&mut [u8]>, + server_cipher: &Cipher, + current_device: &CurrentDeviceInfo, +) -> anyhow::Result<()> { + let mut copy_packet = NetPacket::new0(net_packet.data_len(), [0; 65536])?; + copy_packet.set_default_version(); + copy_packet.set_protocol(protocol::Protocol::IpTurn); + copy_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into()); + copy_packet.first_set_ttl(6); + copy_packet.set_source(net_packet.source()); + copy_packet.set_destination(net_packet.destination()); + copy_packet.set_gateway_flag(true); + copy_packet.set_payload(net_packet.payload())?; + server_cipher.encrypt_ipv4(&mut copy_packet)?; + sender.send_default(©_packet, current_device.connect_server)?; + + Ok(()) +} +pub fn send_to_wg( + sender: &ChannelContext, + net_packet: &mut NetPacket<&mut [u8]>, + server_cipher: &Cipher, + current_device: &CurrentDeviceInfo, +) -> anyhow::Result<()> { + net_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into()); + net_packet.set_gateway_flag(true); + server_cipher.encrypt_ipv4(net_packet)?; + sender.send_default(&net_packet, current_device.connect_server)?; + + Ok(()) +} + pub struct AcceptSocketSender { sender: SyncSender, notify: AcceptNotify, diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 6aab462..cacd907 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -66,12 +66,13 @@ pub struct VntInner { config: Config, current_device: Arc>, nat_test: NatTest, - device_list: Arc)>>, + device_map: Arc)>>, context: Arc>>, peer_nat_info_map: Arc>>, client_secret_hash: Option<[u8; 16]>, compressor: Compressor, client_cipher: Cipher, + server_cipher: Cipher, external_route: ExternalRoute, up_traffic_meter: Option, down_traffic_meter: Option, @@ -128,8 +129,8 @@ impl VntInner { config.server_address, ))); //设备列表 - let device_list: Arc)>> = - Arc::new(Mutex::new((0, Vec::with_capacity(16)))); + let device_map: Arc)>> = + Arc::new(Mutex::new((0, HashMap::with_capacity(16)))); //基础信息 let config_info = BaseConfigInfo::new( config.name.clone(), @@ -147,6 +148,7 @@ impl VntInner { #[cfg(feature = "integrated_tun")] #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] config.device_name.clone(), + config.allow_wire_guard, ); // 服务停止管理器 let stop_manager = { @@ -228,7 +230,7 @@ impl VntInner { proxy_map.clone(), client_cipher.clone(), server_cipher.clone(), - device_list.clone(), + device_map.clone(), config.compressor, device.clone().into_device_adapter(), ) @@ -241,7 +243,7 @@ impl VntInner { client_cipher.clone(), current_device.clone(), device, - device_list.clone(), + device_map.clone(), config_info.clone(), nat_test.clone(), callback.clone(), @@ -287,7 +289,7 @@ impl VntInner { { let context = context.clone(); let nat_test = nat_test.clone(); - let device_list = device_list.clone(); + let device_map = device_map.clone(); let config_info = config_info.clone(); let current_device = current_device.clone(); if !config.use_channel_type.is_only_relay() { @@ -300,13 +302,14 @@ impl VntInner { ); } let client_cipher = client_cipher.clone(); + let server_cipher = server_cipher.clone(); //延迟启动 scheduler.timeout(Duration::from_secs(3), move |scheduler| { start( scheduler, context, nat_test, - device_list, + device_map, current_device, client_cipher, server_cipher, @@ -323,12 +326,13 @@ impl VntInner { config, current_device, nat_test, - device_list, + device_map, context: Arc::new(Mutex::new(Some(context))), peer_nat_info_map, client_secret_hash: config_info.client_secret_hash, compressor, client_cipher, + server_cipher, external_route, up_traffic_meter, down_traffic_meter, @@ -340,7 +344,7 @@ pub fn start( scheduler: &Scheduler, context: ChannelContext, nat_test: NatTest, - device_list: Arc)>>, + device_map: Arc)>>, current_device: Arc>, client_cipher: Cipher, server_cipher: Cipher, @@ -354,7 +358,7 @@ pub fn start( &scheduler, context.clone(), current_device.clone(), - device_list.clone(), + device_map.clone(), client_cipher.clone(), server_cipher.clone(), ); @@ -374,7 +378,7 @@ pub fn start( &scheduler, context.clone(), current_device.clone(), - device_list.clone(), + device_map.clone(), client_cipher.clone(), ); } @@ -393,7 +397,7 @@ pub fn start( &scheduler, context.clone(), nat_test.clone(), - device_list.clone(), + device_map.clone(), current_device.clone(), client_cipher.clone(), punch_receiver, @@ -432,10 +436,10 @@ impl VntInner { self.nat_test.nat_info() } pub fn device_list(&self) -> Vec { - let device_list_lock = self.device_list.lock(); + let device_list_lock = self.device_map.lock(); let (_epoch, device_list) = device_list_lock.clone(); drop(device_list_lock); - device_list + device_list.into_values().collect() } pub fn route(&self, ip: &Ipv4Addr) -> Option { self.context.lock().as_ref()?.route_table.route_one(ip) @@ -507,7 +511,10 @@ impl VntInner { self.current_device.clone(), self.compressor.clone(), self.client_cipher.clone(), + self.server_cipher.clone(), self.external_route.clone(), + self.device_map.clone(), + self.config.allow_wire_guard, )) } else { None diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index 44238fa..56701ad 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -51,6 +51,7 @@ pub struct Config { pub port_mapping_list: Vec<(bool, SocketAddr, String)>, pub compressor: Compressor, pub enable_traffic: bool, + pub allow_wire_guard: bool, } impl Config { @@ -88,6 +89,8 @@ impl Config { #[cfg(feature = "port_mapping")] port_mapping_list: Vec, compressor: Compressor, enable_traffic: bool, + // 允许传递wg流量 + allow_wire_guard: bool, ) -> anyhow::Result { for x in stun_server.iter_mut() { if !x.contains(":") { @@ -180,6 +183,7 @@ impl Config { port_mapping_list, compressor, enable_traffic, + allow_wire_guard, }) } } diff --git a/vnt/src/handle/maintain/heartbeat.rs b/vnt/src/handle/maintain/heartbeat.rs index f18ac8d..d5e21ee 100644 --- a/vnt/src/handle/maintain/heartbeat.rs +++ b/vnt/src/handle/maintain/heartbeat.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::net::Ipv4Addr; use std::sync::Arc; use std::time::Duration; @@ -19,14 +20,14 @@ pub fn heartbeat( scheduler: &Scheduler, context: ChannelContext, current_device_info: Arc>, - device_list: Arc)>>, + device_map: Arc)>>, client_cipher: Cipher, server_cipher: Cipher, ) { heartbeat0( &context, ¤t_device_info.load(), - &device_list, + &device_map, &client_cipher, &server_cipher, ); @@ -36,7 +37,7 @@ pub fn heartbeat( s, context, current_device_info, - device_list, + device_map, client_cipher, server_cipher, ) @@ -49,7 +50,7 @@ pub fn heartbeat( fn heartbeat0( context: &ChannelContext, current_device: &CurrentDeviceInfo, - device_list: &Mutex<(u16, Vec)>, + device_map: &Mutex<(u16, HashMap)>, client_cipher: &Cipher, server_cipher: &Cipher, ) { @@ -57,7 +58,7 @@ fn heartbeat0( let src_ip = current_device.virtual_ip; // 可能服务器ip发生变化,导致发送失败 let mut is_send_gateway = false; - match heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip) { + match heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip) { Ok(net_packet) => { if let Err(e) = context.send_default(&net_packet, current_device.connect_server) { log::warn!("heartbeat err={:?}", e) @@ -75,7 +76,7 @@ fn heartbeat0( if is_send_gateway { continue; } - heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip) + heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip) } else { heartbeat_packet_client(client_cipher, src_ip, dest_ip) }; @@ -92,9 +93,9 @@ fn heartbeat0( } } } - let peer_list = { device_list.lock().1.clone() }; - for peer in &peer_list { - if !peer.status.is_online() { + let peer_list = { device_map.lock().1.clone() }; + for peer in peer_list.values() { + if !peer.status.is_online() || peer.wireguard { continue; } if current_device.is_gateway(&peer.virtual_ip) { @@ -124,11 +125,11 @@ pub fn client_relay( scheduler: &Scheduler, context: ChannelContext, current_device: Arc>, - device_list: Arc)>>, + device_map: Arc)>>, client_cipher: Cipher, ) { let rs = scheduler.timeout(Duration::from_secs(30), move |s| { - client_relay_(s, context, current_device, device_list, client_cipher) + client_relay_(s, context, current_device, device_map, client_cipher) }); if !rs { log::info!("定时任务停止"); @@ -140,19 +141,19 @@ fn client_relay_( scheduler: &Scheduler, context: ChannelContext, current_device: Arc>, - device_list: Arc)>>, + device_map: Arc)>>, client_cipher: Cipher, ) { if let Err(e) = client_relay0( &context, ¤t_device.load(), - &device_list, + &device_map, &client_cipher, ) { log::error!("{:?}", e); } let rs = scheduler.timeout(Duration::from_secs(30), move |s| { - client_relay_(s, context, current_device, device_list, client_cipher) + client_relay_(s, context, current_device, device_map, client_cipher) }); if !rs { log::info!("定时任务停止"); @@ -162,17 +163,20 @@ fn client_relay_( fn client_relay0( context: &ChannelContext, current_device: &CurrentDeviceInfo, - device_list: &Mutex<(u16, Vec)>, + device_map: &Mutex<(u16, HashMap)>, client_cipher: &Cipher, ) -> anyhow::Result<()> { // 离线了不再探测 if current_device.status.offline() { return Ok(()); } - let peer_list = { device_list.lock().1.clone() }; + let peer_list = { device_map.lock().1.clone() }; let mut routes = context.route_table.route_table_p2p(); - for peer in &peer_list { - if !peer.status.is_online() || peer.virtual_ip == current_device.virtual_ip { + for peer in peer_list.values() { + if peer.wireguard + || !peer.status.is_online() + || peer.virtual_ip == current_device.virtual_ip + { continue; } if context @@ -232,14 +236,14 @@ fn heartbeat_packet_client( } fn heartbeat_packet_server( - device_list: &Mutex<(u16, Vec)>, + device_map: &Mutex<(u16, HashMap)>, server_cipher: &Cipher, src: Ipv4Addr, dest: Ipv4Addr, ) -> anyhow::Result> { let mut net_packet = heartbeat_packet(src, dest)?; let mut ping = PingPacket::new(net_packet.payload_mut())?; - ping.set_epoch(device_list.lock().0); + ping.set_epoch(device_map.lock().0); net_packet.set_gateway_flag(true); server_cipher.encrypt_ipv4(&mut net_packet)?; Ok(net_packet) diff --git a/vnt/src/handle/maintain/punch.rs b/vnt/src/handle/maintain/punch.rs index 51a21e9..8bbbe84 100644 --- a/vnt/src/handle/maintain/punch.rs +++ b/vnt/src/handle/maintain/punch.rs @@ -90,7 +90,7 @@ pub fn punch( scheduler: &Scheduler, context: ChannelContext, nat_test: NatTest, - device_list: Arc)>>, + device_map: Arc)>>, current_device: Arc>, client_cipher: Cipher, receiver: PunchReceiver, @@ -102,7 +102,7 @@ pub fn punch( scheduler, context, nat_test, - device_list, + device_map, current_device.clone(), client_cipher.clone(), 0, @@ -170,7 +170,7 @@ fn punch_request( scheduler: &Scheduler, context: ChannelContext, nat_test: NatTest, - device_list: Arc)>>, + device_map: Arc)>>, current_device: Arc>, client_cipher: Cipher, count: usize, @@ -182,7 +182,7 @@ fn punch_request( if let Err(e) = punch0( &context, &nat_test, - &device_list, + &device_map, curr, &client_cipher, &punch_record, @@ -201,7 +201,7 @@ fn punch_request( s, context, nat_test, - device_list, + device_map, current_device, client_cipher, count + 1, @@ -218,7 +218,7 @@ fn punch_request( fn punch0( context: &ChannelContext, nat_test: &NatTest, - device_list: &Arc)>>, + device_map: &Arc)>>, current_device: CurrentDeviceInfo, client_cipher: &Cipher, punch_record: &Mutex>, @@ -237,11 +237,11 @@ fn punch0( return Ok(()); } let current_ip = current_device.virtual_ip; - let mut list: Vec = device_list + let mut list: Vec = device_map .lock() .1 - .iter() - .filter(|info| info.status.is_online() && info.virtual_ip > current_ip) + .values() + .filter(|info| !info.wireguard && info.status.is_online() && info.virtual_ip > current_ip) .cloned() .collect(); list.shuffle(&mut rand::thread_rng()); diff --git a/vnt/src/handle/mod.rs b/vnt/src/handle/mod.rs index e39305f..754b7b3 100644 --- a/vnt/src/handle/mod.rs +++ b/vnt/src/handle/mod.rs @@ -29,6 +29,7 @@ pub struct PeerDeviceInfo { pub status: PeerDeviceStatus, pub client_secret: bool, pub client_secret_hash: Vec, + pub wireguard: bool, } impl PeerDeviceInfo { @@ -38,6 +39,7 @@ impl PeerDeviceInfo { status: u8, client_secret: bool, client_secret_hash: Vec, + wireguard: bool, ) -> Self { Self { virtual_ip, @@ -45,6 +47,7 @@ impl PeerDeviceInfo { status: PeerDeviceStatus::from(status), client_secret, client_secret_hash, + wireguard, } } } @@ -66,6 +69,7 @@ pub struct BaseConfigInfo { #[cfg(feature = "integrated_tun")] #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] pub device_name: Option, + pub allow_wire_guard: bool, } impl BaseConfigInfo { @@ -85,6 +89,7 @@ impl BaseConfigInfo { #[cfg(feature = "integrated_tun")] #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] device_name: Option, + allow_wire_guard: bool, ) -> Self { Self { name, @@ -102,6 +107,7 @@ impl BaseConfigInfo { #[cfg(feature = "integrated_tun")] #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] device_name, + allow_wire_guard, } } } @@ -116,6 +122,9 @@ impl PeerDeviceStatus { pub fn is_online(&self) -> bool { self == &PeerDeviceStatus::Online } + pub fn is_offline(&self) -> bool { + self == &PeerDeviceStatus::Offline + } } impl Into for PeerDeviceStatus { diff --git a/vnt/src/handle/recv_data/client.rs b/vnt/src/handle/recv_data/client.rs index 13879d3..fc61721 100644 --- a/vnt/src/handle/recv_data/client.rs +++ b/vnt/src/handle/recv_data/client.rs @@ -194,6 +194,9 @@ impl ClientPacketHandler { } self.device.write(net_packet.payload())?; } + ip_turn_packet::Protocol::WGIpv4 => { + // WG客户端的数据不会直接发过来,不用处理 + } ip_turn_packet::Protocol::Ipv4Broadcast => { //客户端不帮忙转发广播包,所以不会出现这种类型的数据 } diff --git a/vnt/src/handle/recv_data/mod.rs b/vnt/src/handle/recv_data/mod.rs index e2bd5d6..4b745c1 100644 --- a/vnt/src/handle/recv_data/mod.rs +++ b/vnt/src/handle/recv_data/mod.rs @@ -80,7 +80,7 @@ impl RecvDataHandler { client_cipher: Cipher, current_device: Arc>, device: Device, - device_list: Arc)>>, + device_map: Arc)>>, config_info: BaseConfigInfo, nat_test: NatTest, callback: Call, @@ -101,7 +101,7 @@ impl RecvDataHandler { server_cipher, current_device.clone(), device.clone(), - device_list, + device_map, config_info, nat_test.clone(), callback, diff --git a/vnt/src/handle/recv_data/server.rs b/vnt/src/handle/recv_data/server.rs index 66ecfc0..2abce5c 100644 --- a/vnt/src/handle/recv_data/server.rs +++ b/vnt/src/handle/recv_data/server.rs @@ -1,4 +1,5 @@ use anyhow::anyhow; +use std::collections::HashMap; use std::io; use std::net::Ipv4Addr; use std::sync::Arc; @@ -42,7 +43,7 @@ pub struct ServerPacketHandler { server_cipher: Cipher, current_device: Arc>, device: Device, - device_list: Arc)>>, + device_map: Arc)>>, config_info: BaseConfigInfo, nat_test: NatTest, callback: Call, @@ -60,7 +61,7 @@ impl ServerPacketHandler { server_cipher: Cipher, current_device: Arc>, device: Device, - device_list: Arc)>>, + device_map: Arc)>>, config_info: BaseConfigInfo, nat_test: NatTest, callback: Call, @@ -75,7 +76,7 @@ impl ServerPacketHandler { server_cipher, current_device, device, - device_list, + device_map, config_info, nat_test, callback, @@ -246,6 +247,11 @@ impl PacketHandler for ServerPacketHandl _ => {} } } + ip_turn_packet::Protocol::WGIpv4 => { + if self.config_info.allow_wire_guard { + self.device.write(net_packet.payload())?; + } + } ip_turn_packet::Protocol::Ipv4Broadcast => {} ip_turn_packet::Protocol::Unknown(_) => {} } @@ -353,7 +359,8 @@ impl ServerPacketHandler { ); log::info!("tun信息{:?}", tun_info); self.callback.create_tun(tun_info); - self.tun_device_helper.start(device)?; + self.tun_device_helper + .start(device, self.config_info.allow_wire_guard)?; } Err(e) => { log::error!("{:?}", e); @@ -435,14 +442,18 @@ impl ServerPacketHandler { info.device_status as u8, info.client_secret, info.client_secret_hash, + info.wireguard, ) }) .collect(); { - let mut dev = self.device_list.lock(); + let mut dev = self.device_map.lock(); //这里可能会收到旧的消息,但是随着时间推移总会收到新的 dev.0 = epoch; - dev.1 = ip_list.clone(); + dev.1.clear(); + for info in ip_list.clone() { + dev.1.insert(info.virtual_ip, info); + } } self.callback.peer_client_list( ip_list @@ -506,7 +517,7 @@ impl ServerPacketHandler { self.callback.error(err); //掉线epoch要归零 { - let mut dev = self.device_list.lock(); + let mut dev = self.device_map.lock(); dev.0 = 0; drop(dev); } @@ -554,7 +565,7 @@ impl ServerPacketHandler { let rt = (current_time - pong_packet.time()) as i64; let route = Route::from(route_key, metric, rt); context.route_table.add_route(net_packet.source(), route); - let epoch = self.device_list.lock().0; + let epoch = self.device_map.lock().0; if pong_packet.epoch() != epoch { //纪元不一致,可能有新客户端连接,向服务端拉取客户端列表 let mut poll_device = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?; diff --git a/vnt/src/handle/tun_tap/tun_handler.rs b/vnt/src/handle/tun_tap/tun_handler.rs index 6aee8f2..ef57181 100644 --- a/vnt/src/handle/tun_tap/tun_handler.rs +++ b/vnt/src/handle/tun_tap/tun_handler.rs @@ -1,10 +1,10 @@ +use crossbeam_utils::atomic::AtomicCell; +use parking_lot::Mutex; +use std::collections::HashMap; use std::net::Ipv4Addr; use std::sync::Arc; use std::{io, thread}; -use crossbeam_utils::atomic::AtomicCell; -use parking_lot::Mutex; - use packet::icmp::icmp::IcmpPacket; use packet::icmp::Kind; use packet::ip::ipv4::packet::IpV4Packet; @@ -13,6 +13,7 @@ use tun::device::IFace; use tun::Device; use crate::channel::context::ChannelContext; +use crate::channel::sender::{send_to_wg, send_to_wg_broadcast}; use crate::cipher::Cipher; use crate::compression::Compressor; use crate::external_route::ExternalRoute; @@ -27,7 +28,6 @@ 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::StopManager; - fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyhow::Result<()> { if ipv4_packet.protocol() == Protocol::Icmp { let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?; @@ -53,9 +53,10 @@ pub fn start( #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, client_cipher: Cipher, server_cipher: Cipher, - device_list: Arc)>>, + device_map: Arc)>>, compressor: Compressor, device_stop: DeviceStop, + allow_wire_guard: bool, ) -> io::Result<()> { thread::Builder::new() .name("tunHandlerS".into()) @@ -70,9 +71,10 @@ pub fn start( ip_proxy_map, client_cipher, server_cipher, - device_list, + device_map, compressor, device_stop, + allow_wire_guard, ) { log::warn!("stop:{}", e); } @@ -86,13 +88,13 @@ fn broadcast( sender: &ChannelContext, net_packet: &mut NetPacket<&mut [u8]>, current_device: &CurrentDeviceInfo, - device_list: &Mutex<(u16, Vec)>, + device_map: &Mutex<(u16, HashMap)>, ) -> anyhow::Result<()> { - let list: Vec = device_list + let list: Vec = device_map .lock() .1 - .iter() - .filter(|info| info.status.is_online()) + .values() + .filter(|info| !info.wireguard && info.status.is_online()) .map(|info| info.virtual_ip) .collect(); const MAX_COUNT: usize = 8; @@ -177,8 +179,9 @@ pub(crate) fn handle( #[cfg(feature = "ip_proxy")] proxy_map: &Option, client_cipher: &Cipher, server_cipher: &Cipher, - device_list: &Mutex<(u16, Vec)>, + device_map: &Mutex<(u16, HashMap)>, compressor: &Compressor, + allow_wire_guard: bool, ) -> anyhow::Result<()> { //忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了 let ipv4_packet = match IpV4Packet::new(&mut buf[12..data_len]) { @@ -237,6 +240,33 @@ pub(crate) fn handle( dest_ip = Ipv4Addr::BROADCAST; net_packet.set_destination(Ipv4Addr::BROADCAST); } + let is_broadcast = dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip; + if allow_wire_guard { + if is_broadcast { + // wg客户端和vnt客户端分开广播 + let exists_wg = device_map + .lock() + .1 + .values() + .any(|v| v.status.is_online() && v.wireguard); + if exists_wg { + send_to_wg_broadcast(context, &net_packet, server_cipher, ¤t_device)?; + } + } else { + // 如果是wg客户端则发到vnts转发 + let guard = device_map.lock(); + if let Some(peer_info) = guard.1.get(&dest_ip) { + if peer_info.wireguard { + if peer_info.status.is_offline() { + return Ok(()); + } + drop(guard); + send_to_wg(context, &mut net_packet, server_cipher, ¤t_device)?; + return Ok(()); + } + } + } + } let mut net_packet = if compressor.compress(&net_packet, &mut out)? { out.set_default_version(); @@ -257,7 +287,7 @@ pub(crate) fn handle( context, &mut net_packet, ¤t_device, - device_list, + device_map, )?; return Ok(()); } diff --git a/vnt/src/handle/tun_tap/unix.rs b/vnt/src/handle/tun_tap/unix.rs index a75d02c..80d7a22 100644 --- a/vnt/src/handle/tun_tap/unix.rs +++ b/vnt/src/handle/tun_tap/unix.rs @@ -13,7 +13,9 @@ use mio::event::Source; use mio::unix::SourceFd; use mio::{Events, Interest, Poll, Token, Waker}; use parking_lot::Mutex; +use std::collections::HashMap; use std::io; +use std::net::Ipv4Addr; use std::os::fd::AsRawFd; use std::sync::Arc; use tun::Device; @@ -30,9 +32,10 @@ pub(crate) fn start_simple( #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, client_cipher: Cipher, server_cipher: Cipher, - device_list: Arc)>>, + device_map: Arc)>>, compressor: Compressor, device_stop: DeviceStop, + allow_wire_guard: bool, ) -> anyhow::Result<()> { let poll = Poll::new()?; let waker = Arc::new(Waker::new(poll.registry(), STOP)?); @@ -61,8 +64,9 @@ pub(crate) fn start_simple( ip_proxy_map, client_cipher, server_cipher, - device_list, + device_map, compressor, + allow_wire_guard, ) { log::error!("{:?}", e); }; @@ -83,8 +87,9 @@ fn start_simple0( #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, client_cipher: Cipher, server_cipher: Cipher, - device_list: Arc)>>, + device_map: Arc)>>, compressor: Compressor, + allow_wire_guard: bool, ) -> anyhow::Result<()> { let mut buf = [0; BUFFER_SIZE]; let mut extend = [0; BUFFER_SIZE]; @@ -134,8 +139,9 @@ fn start_simple0( &ip_proxy_map, &client_cipher, &server_cipher, - &device_list, + &device_map, &compressor, + allow_wire_guard, ) { Ok(_) => {} Err(e) => { diff --git a/vnt/src/handle/tun_tap/windows.rs b/vnt/src/handle/tun_tap/windows.rs index 0df3e4a..3c91b56 100644 --- a/vnt/src/handle/tun_tap/windows.rs +++ b/vnt/src/handle/tun_tap/windows.rs @@ -10,6 +10,8 @@ use crate::ip_proxy::IpProxyMap; use crate::util::StopManager; use crossbeam_utils::atomic::AtomicCell; use parking_lot::Mutex; +use std::collections::HashMap; +use std::net::Ipv4Addr; use std::sync::Arc; use tun::device::IFace; use tun::Device; @@ -23,9 +25,10 @@ pub(crate) fn start_simple( #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, client_cipher: Cipher, server_cipher: Cipher, - device_list: Arc)>>, + device_map: Arc)>>, compressor: Compressor, device_stop: DeviceStop, + allow_wire_guard: bool, ) -> anyhow::Result<()> { let worker = { let device = device.clone(); @@ -54,8 +57,9 @@ pub(crate) fn start_simple( ip_proxy_map, client_cipher, server_cipher, - device_list, + device_map, compressor, + allow_wire_guard, ) { log::error!("{:?}", e); } @@ -74,8 +78,9 @@ fn start_simple0( #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, client_cipher: Cipher, server_cipher: Cipher, - device_list: Arc)>>, + device_map: Arc)>>, compressor: Compressor, + allow_wire_guard: bool, ) -> anyhow::Result<()> { let mut buf = [0; BUFFER_SIZE]; let mut extend = [0; BUFFER_SIZE]; @@ -96,8 +101,9 @@ fn start_simple0( &ip_proxy_map, &client_cipher, &server_cipher, - &device_list, + &device_map, &compressor, + allow_wire_guard, ) { Ok(_) => {} Err(e) => { diff --git a/vnt/src/protocol/ip_turn_packet.rs b/vnt/src/protocol/ip_turn_packet.rs index b009f3f..edccdd5 100644 --- a/vnt/src/protocol/ip_turn_packet.rs +++ b/vnt/src/protocol/ip_turn_packet.rs @@ -1,9 +1,12 @@ +#![allow(dead_code)] + use std::io; use std::net::Ipv4Addr; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum Protocol { Ipv4, + WGIpv4, Ipv4Broadcast, Unknown(u8), } @@ -12,16 +15,18 @@ impl From for Protocol { fn from(value: u8) -> Self { match value { 4 => Protocol::Ipv4, + 5 => Protocol::WGIpv4, 201 => Protocol::Ipv4Broadcast, val => Protocol::Unknown(val), } } } -impl Into for Protocol { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: Protocol) -> Self { + match val { Protocol::Ipv4 => 4, + Protocol::WGIpv4 => 5, Protocol::Ipv4Broadcast => 201, Protocol::Unknown(val) => val, } diff --git a/vnt/src/tun_tap_device/tun_create_helper.rs b/vnt/src/tun_tap_device/tun_create_helper.rs index 76babcf..12d1b1b 100644 --- a/vnt/src/tun_tap_device/tun_create_helper.rs +++ b/vnt/src/tun_tap_device/tun_create_helper.rs @@ -1,4 +1,6 @@ +use std::collections::HashMap; use std::io; +use std::net::Ipv4Addr; use std::sync::Arc; use crossbeam_utils::atomic::AtomicCell; @@ -67,7 +69,7 @@ struct TunDeviceHelperInner { ip_proxy_map: Option, client_cipher: Cipher, server_cipher: Cipher, - device_list: Arc)>>, + device_map: Arc)>>, compressor: Compressor, } @@ -80,7 +82,7 @@ impl TunDeviceHelper { #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, client_cipher: Cipher, server_cipher: Cipher, - device_list: Arc)>>, + device_map: Arc)>>, compressor: Compressor, device_adapter: DeviceAdapter, ) -> Self { @@ -93,7 +95,7 @@ impl TunDeviceHelper { ip_proxy_map, client_cipher, server_cipher, - device_list, + device_map, compressor, }; Self { @@ -117,7 +119,7 @@ impl TunDeviceHelper { } } /// 要保证先stop 再start - pub fn start(&self, device: Arc) -> io::Result<()> { + pub fn start(&self, device: Arc, allow_wire_guard: bool) -> io::Result<()> { self.device_adapter.insert(device.clone()); let device_stop = DeviceStop::default(); let s = self.device_stop.lock().replace(device_stop.clone()); @@ -133,9 +135,10 @@ impl TunDeviceHelper { inner.ip_proxy_map, inner.client_cipher, inner.server_cipher, - inner.device_list, + inner.device_map, inner.compressor, device_stop, + allow_wire_guard, ) } } From f90ef96a5d4173d39d2b869269c68caaaf21535c Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Sat, 20 Jul 2024 11:12:45 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=A2=9E=E5=8A=A0sys-locale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 6692847..0f9ed98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,6 +319,7 @@ dependencies = [ "rand", "serde", "serde_yaml", + "sys-locale", "uuid", "vnt", ] @@ -1834,6 +1835,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sys-locale" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" +dependencies = [ + "libc", +] + [[package]] name = "tempfile" version = "3.10.1" From 05cf0e1a6f644f0e48c8fed1ed2ab533a98336fb Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:48:56 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 16 ++++++++-------- README.md | 14 +++++++------- common/Cargo.toml | 2 +- vn-link-cli/Cargo.toml | 2 +- vn-link/Cargo.toml | 4 ++-- vnt-cli/Cargo.toml | 2 +- vnt-cli/README.md | 12 +++++++++++- vnt/Cargo.toml | 6 +++--- 8 files changed, 34 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f9ed98..c9e5943 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,7 +307,7 @@ dependencies = [ [[package]] name = "common" -version = "1.2.11" +version = "1.2.12" dependencies = [ "anyhow", "chrono", @@ -881,7 +881,7 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsm" version = "0.5.1" -source = "git+https://github.com/lbl8603/libsm#f9e1b8cf20d0829efb4934a940d0ba4f3ee0ac14" +source = "git+https://github.com/vnt-dev/libsm#f9e1b8cf20d0829efb4934a940d0ba4f3ee0ac14" dependencies = [ "byteorder", "getrandom", @@ -955,7 +955,7 @@ dependencies = [ [[package]] name = "lwip-rs" version = "0.1.0" -source = "git+https://github.com/lbl8603/lwip-rs#3133f0c3bde55333a27641182ae3550e7acc2a39" +source = "git+https://github.com/vnt-dev/lwip-rs#3133f0c3bde55333a27641182ae3550e7acc2a39" dependencies = [ "bindgen", "cc", @@ -1121,7 +1121,7 @@ dependencies = [ [[package]] name = "openssl-sys" version = "0.9.93" -source = "git+https://github.com/lbl8603/rust-openssl#e8b3d2c02d2d07a0e4a82ff4e4bef210f4bc71c8" +source = "git+https://github.com/vnt-dev/rust-openssl#e8b3d2c02d2d07a0e4a82ff4e4bef210f4bc71c8" dependencies = [ "cc", "libc", @@ -2105,7 +2105,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vn-link" -version = "1.2.11" +version = "1.2.12" dependencies = [ "anyhow", "crossbeam-utils", @@ -2118,7 +2118,7 @@ dependencies = [ [[package]] name = "vn-link-cli" -version = "1.2.11" +version = "1.2.12" dependencies = [ "common", "log", @@ -2128,7 +2128,7 @@ dependencies = [ [[package]] name = "vnt" -version = "1.2.11" +version = "1.2.12" dependencies = [ "aes", "aes-gcm", @@ -2175,7 +2175,7 @@ dependencies = [ [[package]] name = "vnt-cli" -version = "1.2.11" +version = "1.2.12" dependencies = [ "anyhow", "chrono", diff --git a/README.md b/README.md index 26a92ba..a1006bc 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A virtual network tool (VPN) 将不同网络下的多个设备虚拟到一个局域网下 -### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md) +### vnt-cli参数详解 [参数说明](https://github.com/vnt-dev/vnt/blob/main/vnt-cli/README.md) ### 快速使用: @@ -39,7 +39,7 @@ A virtual network tool (VPN) ``` 4. 最后可以用虚拟ip实现设备间相互访问 - ssh + ssh 5. 帮助,使用-h命令查看 ### 更多玩法 @@ -56,7 +56,7 @@ A virtual network tool (VPN) - 需要root/管理员权限 - vnt-cli需要使用命令行运行 - Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli) -- 可以自己搭注册和中继服务器([server](https://github.com/lbl8603/vnts)) +- 可以自己搭注册和中继服务器([server](https://github.com/vnt-dev/vnts)) - vnt使用stun服务器探测网络NAT类型,默认使用谷歌和腾讯的stun服务器,也可自己搭建(-e参数指定) ### 编译 @@ -181,7 +181,7 @@ sudo pfctl -f /etc/pf.conf -e ### GUI -支持安卓和Windows [下载](https://github.com/lbl8603/VntApp/releases/) +支持安卓和Windows [下载](https://github.com/vnt-dev/VntApp/releases/) ### 特性 @@ -291,7 +291,7 @@ QQ: 1034868233 ### 赞助 如果VNT对你有帮助,欢迎打赏作者 - + ### 其他 @@ -302,6 +302,6 @@ QQ: 1034868233 ### 参与贡献 - - + + diff --git a/common/Cargo.toml b/common/Cargo.toml index fae5719..e7dd42b 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "common" -version = "1.2.11" +version = "1.2.12" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/vn-link-cli/Cargo.toml b/vn-link-cli/Cargo.toml index e4e3559..9f8ada2 100644 --- a/vn-link-cli/Cargo.toml +++ b/vn-link-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vn-link-cli" -version = "1.2.11" +version = "1.2.12" edition = "2021" [dependencies] diff --git a/vn-link/Cargo.toml b/vn-link/Cargo.toml index 5e44997..476a804 100644 --- a/vn-link/Cargo.toml +++ b/vn-link/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "vn-link" -version = "1.2.11" +version = "1.2.12" edition = "2021" [dependencies] -lwip-rs = { git = "https://github.com/lbl8603/lwip-rs" } +lwip-rs = { git = "https://github.com/vnt-dev/lwip-rs" } vnt = { path = "../vnt", package = "vnt", default-features = false } log = "0.4.17" anyhow = "1.0.82" diff --git a/vnt-cli/Cargo.toml b/vnt-cli/Cargo.toml index f4675e4..5d4c665 100644 --- a/vnt-cli/Cargo.toml +++ b/vnt-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vnt-cli" -version = "1.2.11" +version = "1.2.12" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/vnt-cli/README.md b/vnt-cli/README.md index 92518ae..69da1df 100644 --- a/vnt-cli/README.md +++ b/vnt-cli/README.md @@ -135,7 +135,7 @@ aes_gcm/aes_cbc/aes_ecb/sm4_cbc/chacha20_poly1305/chacha20/xor,默认使用aes ### --no-proxy 关闭内置的ip代理,内置的代理较为简单,而且一般来说直接使用网卡NAT转发性能会更高, -有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/lbl8603/vnt#%E7%BC%96%E8%AF%91) +有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/vnt-dev/vnt#%E7%BC%96%E8%AF%91) ### --dns `<223.5.5.5>` @@ -201,6 +201,8 @@ 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数据 +disable_stats: false # 为true表示关闭统计 +allow_wire_guard: false # 为true则表示允许接入wg ``` 或者需要哪个配置就加哪个,当然token是必须的 @@ -223,6 +225,14 @@ token: xxx #组网token 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网 +### --disable-stats + +关闭流量统计 + +### --allow-wg + +允许接入WireGuard客户端,和wg混用时必须开启此参数 + ### --list 在后台运行时,查看其他设备列表 diff --git a/vnt/Cargo.toml b/vnt/Cargo.toml index dd95ec4..63d8c8a 100644 --- a/vnt/Cargo.toml +++ b/vnt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vnt" -version = "1.2.11" +version = "1.2.12" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -29,8 +29,8 @@ 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 } +openssl-sys = { git = "https://github.com/vnt-dev/rust-openssl", optional = true } +libsm = { git = "https://github.com/vnt-dev/libsm", optional = true } mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] } crossbeam-queue = "0.3.11" From b8cbf2cdac8e9da2228bb8a5b7e79b5f2127e7fa Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Sat, 20 Jul 2024 23:26:11 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E4=B8=8D=E5=9C=A8=E7=BA=BF=E7=9A=84?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E4=B8=8D=E8=BD=AC=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/handle/tun_tap/tun_handler.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vnt/src/handle/tun_tap/tun_handler.rs b/vnt/src/handle/tun_tap/tun_handler.rs index ef57181..6b04e22 100644 --- a/vnt/src/handle/tun_tap/tun_handler.rs +++ b/vnt/src/handle/tun_tap/tun_handler.rs @@ -126,7 +126,7 @@ fn broadcast( } return Ok(()); } - if !overflow && relay_ips.len() == 2 { + if !overflow && relay_ips.len() == 1 { // 如果转发的ip数不多就直接发 for peer_ip in relay_ips { //非直连的广播要改变目的地址,不然服务端收到了会再次广播 @@ -256,10 +256,10 @@ pub(crate) fn handle( // 如果是wg客户端则发到vnts转发 let guard = device_map.lock(); if let Some(peer_info) = guard.1.get(&dest_ip) { + if peer_info.status.is_offline() { + return Ok(()); + } if peer_info.wireguard { - if peer_info.status.is_offline() { - return Ok(()); - } drop(guard); send_to_wg(context, &mut net_packet, server_cipher, ¤t_device)?; return Ok(()); From be966c4f832c097956247567f44ae3b5c7946385 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Tue, 23 Jul 2024 22:25:55 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E7=AE=80=E5=8C=96=E5=B9=BF=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt/src/handle/tun_tap/tun_handler.rs | 39 +++++++++------------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/vnt/src/handle/tun_tap/tun_handler.rs b/vnt/src/handle/tun_tap/tun_handler.rs index 6b04e22..aa0bba7 100644 --- a/vnt/src/handle/tun_tap/tun_handler.rs +++ b/vnt/src/handle/tun_tap/tun_handler.rs @@ -97,9 +97,12 @@ fn broadcast( .filter(|info| !info.wireguard && info.status.is_online()) .map(|info| info.virtual_ip) .collect(); + if list.is_empty() { + return Ok(()); + } const MAX_COUNT: usize = 8; let mut p2p_ips = Vec::with_capacity(8); - let mut relay_ips = Vec::with_capacity(8); + let mut relay = false; let mut overflow = false; for (index, peer_ip) in list.into_iter().enumerate() { if index > MAX_COUNT { @@ -112,38 +115,22 @@ fn broadcast( continue; } } - relay_ips.push(peer_ip); + relay = true; } - if !overflow && relay_ips.is_empty() { + if !overflow && !relay { //全部p2p,不需要服务器中转 return Ok(()); } - - if p2p_ips.is_empty() { - //都没有p2p则直接由服务器转发 - if current_device.status.online() { - sender.send_default(&net_packet, current_device.connect_server)?; - } - return Ok(()); - } - if !overflow && relay_ips.len() == 1 { - // 如果转发的ip数不多就直接发 - for peer_ip in relay_ips { - //非直连的广播要改变目的地址,不然服务端收到了会再次广播 - net_packet.set_destination(peer_ip); - sender.send_ipv4_by_id( - &net_packet, - &peer_ip, - current_device.connect_server, - current_device.status.online(), - )?; - } - return Ok(()); - } if current_device.status.offline() { //离线的不再转发 return Ok(()); } + if p2p_ips.is_empty() { + //都没有p2p则直接由服务器转发 + sender.send_default(&net_packet, current_device.connect_server)?; + 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)?; @@ -279,7 +266,7 @@ pub(crate) fn handle( } else { net_packet }; - if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip { + if is_broadcast { // 广播 发送到直连目标 client_cipher.encrypt_ipv4(&mut net_packet)?; broadcast( From 352f322f6108105fbdb33d607f6e858e7c3f66d8 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Wed, 24 Jul 2024 22:11:50 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E7=94=9F=E6=88=90guid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + vnt/tun/Cargo.toml | 1 + vnt/tun/src/windows/tun/mod.rs | 15 ++++++++++----- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9e5943..10045db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1968,6 +1968,7 @@ dependencies = [ "libloading", "log", "rand", + "sha2", "widestring", "winapi", ] diff --git a/vnt/tun/Cargo.toml b/vnt/tun/Cargo.toml index cdede0f..08b8d16 100644 --- a/vnt/tun/Cargo.toml +++ b/vnt/tun/Cargo.toml @@ -11,6 +11,7 @@ libc = "0.2.153" log = { version = "0.4.20", features = [] } rand = "0.8.5" +sha2 = { version = "0.10.6", features = ["oid"] } [target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] ioctl = { version = "0.8", package = "ioctl-sys" } diff --git a/vnt/tun/src/windows/tun/mod.rs b/vnt/tun/src/windows/tun/mod.rs index d155c8f..8c826eb 100644 --- a/vnt/tun/src/windows/tun/mod.rs +++ b/vnt/tun/src/windows/tun/mod.rs @@ -1,9 +1,8 @@ #![allow(dead_code)] use libloading::Library; +use sha2::Digest; use std::io; use std::net::Ipv4Addr; - -use rand::Rng; use winapi::um::winbase; use winapi::um::{synchapi, winnt}; @@ -81,8 +80,7 @@ impl Device { if Self::delete_for_name(&win_tun, &name_utf16).is_ok() { std::thread::sleep(std::time::Duration::from_millis(500)); } - let mut guid_bytes: [u8; 16] = [0u8; 16]; - rand::thread_rng().fill(&mut guid_bytes); + let guid_bytes: [u8; 16] = hash_guid(&name); let guid = u128::from_ne_bytes(guid_bytes); //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 @@ -154,7 +152,14 @@ impl Device { Ok(()) } } - +fn hash_guid(input: &str) -> [u8; 16] { + let mut hasher = sha2::Sha256::new(); + hasher.update(b"VNT"); + hasher.update(input.as_bytes()); + hasher.update(b"2024"); + let hash: [u8; 32] = hasher.finalize().into(); + hash[..16].try_into().unwrap() +} impl IFace for Device { fn version(&self) -> io::Result { let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };