diff --git a/vnt-cli/src/config/mod.rs b/vnt-cli/src/config/mod.rs index 1e75b6b..2d8d3f0 100644 --- a/vnt-cli/src/config/mod.rs +++ b/vnt-cli/src/config/mod.rs @@ -5,6 +5,7 @@ use std::str::FromStr; use serde::{Deserialize, Serialize}; use vnt::channel::punch::PunchModel; +use vnt::channel::UseChannelType; use vnt::cipher::CipherModel; use vnt::core::Config; @@ -24,7 +25,7 @@ pub struct FileConfig { pub mtu: Option, pub tcp: bool, pub ip: Option, - pub relay: bool, + pub use_channel: String, #[cfg(feature = "ip_proxy")] pub no_proxy: bool, pub server_encrypt: bool, @@ -58,14 +59,14 @@ impl Default for FileConfig { mtu: None, tcp: false, ip: None, - relay: false, + use_channel: "all".to_string(), #[cfg(feature = "ip_proxy")] no_proxy: false, server_encrypt: false, parallel: 1, cipher_model: "aes_gcm".to_string(), finger: false, - punch_model: "".to_string(), + punch_model: "all".to_string(), ports: None, cmd: false, first_latency: false, @@ -137,6 +138,8 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { let punch_model = PunchModel::from_str(&file_conf.punch_model) .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + let use_channel_type = UseChannelType::from_str(&file_conf.use_channel) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; let config = Config::new( #[cfg(any(target_os = "windows", target_os = "linux"))] file_conf.tap, @@ -152,7 +155,6 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { file_conf.mtu, file_conf.tcp, virtual_ip, - file_conf.relay, #[cfg(feature = "ip_proxy")] file_conf.no_proxy, file_conf.server_encrypt, @@ -163,6 +165,7 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { file_conf.ports, file_conf.first_latency, file_conf.device_name, + use_channel_type, ) .unwrap(); Ok((config, file_conf.cmd)) diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs index 3e0c8af..4b5181f 100644 --- a/vnt-cli/src/main.rs +++ b/vnt-cli/src/main.rs @@ -8,6 +8,7 @@ use getopts::Options; use common::args_parse::{ips_parse, out_ips_parse}; use vnt::channel::punch::PunchModel; +use vnt::channel::UseChannelType; use vnt::cipher::CipherModel; use vnt::core::{Config, Vnt}; @@ -57,6 +58,7 @@ fn main() { opts.optflag("", "cmd", "开启窗口输入"); opts.optflag("", "no-proxy", "关闭内置代理"); opts.optflag("", "first-latency", "优先延迟"); + opts.optflag("", "use-channel", "使用通道 relay/p2p,默认两者都使用"); opts.optopt("f", "", "配置文件", ""); //"后台运行时,查看其他设备列表" opts.optflag("", "list", "后台运行时,查看其他设备列表"); @@ -213,6 +215,7 @@ fn main() { } let tcp_channel = matches.opt_present("tcp"); let relay = matches.opt_present("relay"); + let parallel = matches.opt_get::("par").unwrap().unwrap_or(1); if parallel == 0 { println!("'--par {}' invalid", parallel); @@ -256,6 +259,17 @@ fn main() { .opt_get::("punch") .unwrap() .unwrap_or(PunchModel::All); + let use_channel_type = matches + .opt_get::("use-channel") + .unwrap() + .unwrap_or_else(||{ + if relay{ + UseChannelType::Relay + }else{ + UseChannelType::All + } + }); + let ports = matches .opt_get::("ports") .unwrap_or(None) @@ -280,7 +294,6 @@ fn main() { mtu, tcp_channel, virtual_ip, - relay, #[cfg(feature = "ip_proxy")] no_proxy, server_encrypt, @@ -291,6 +304,7 @@ fn main() { ports, first_latency, device_name, + use_channel_type, ) .unwrap(); (config, cmd) @@ -414,7 +428,6 @@ fn print_usage(program: &str, _opts: Options) { println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp"); println!(" --ip 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配"); - println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p"); println!(" --par 任务并行度(必须为正整数),默认值为1"); if !enums.is_empty() { println!( @@ -425,12 +438,13 @@ fn print_usage(program: &str, _opts: Options) { if !enums.is_empty() { println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启"); } - println!(" --punch 取值ipv4/ipv6,ipv4表示仅使用ipv4打洞"); + println!(" --punch 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞"); println!(" --ports 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担"); println!(" --cmd 开启交互式命令,使用此参数开启控制台输入"); #[cfg(feature = "ip_proxy")] println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发"); println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道"); + println!(" --use-channel 使用通道 relay/p2p/all,默认两者都使用"); println!(" --nic 虚拟网卡名称,windows下使用tap模式则必须指定此参数"); println!(); diff --git a/vnt-jni/src/config.rs b/vnt-jni/src/config.rs index a0ce208..d71536a 100644 --- a/vnt-jni/src/config.rs +++ b/vnt-jni/src/config.rs @@ -6,6 +6,7 @@ use jni::objects::JObject; use jni::JNIEnv; use vnt::channel::punch::PunchModel; +use vnt::channel::UseChannelType; use vnt::cipher::CipherModel; use vnt::core::Config; @@ -25,7 +26,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32); let tcp = env.get_field(&config, "tcp", "Z")?.z()?; let server_encrypt = env.get_field(&config, "serverEncrypt", "Z")?.z()?; - let relay = env.get_field(&config, "relay", "Z")?.z()?; + let use_channel = to_string(env, &config, "useChannel")?; let finger = env.get_field(&config, "finger", "Z")?.z()?; let first_latency = env.get_field(&config, "firstLatency", "Z")?.z()?; let in_ips = to_string_array(env, &config, "inIps")?; @@ -118,7 +119,6 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { mtu, tcp, ip, - relay, false, server_encrypt, 1, @@ -131,6 +131,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { device_name, #[cfg(target_os = "android")] device_fd, + UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(), ) { Ok(config) => config, Err(e) => { diff --git a/vnt/src/channel/context.rs b/vnt/src/channel/context.rs index 29ffcc9..9a001ab 100644 --- a/vnt/src/channel/context.rs +++ b/vnt/src/channel/context.rs @@ -11,7 +11,7 @@ use parking_lot::RwLock; use crate::channel::punch::NatType; use crate::channel::sender::{AcceptSocketSender, ChannelSender, PacketSender}; -use crate::channel::{Route, RouteKey}; +use crate::channel::{Route, RouteKey, UseChannelType}; use crate::handle::{ConnectStatus, CurrentDeviceInfo}; /// 传输通道上下文,持有udp socket、tcp socket和路由信息 @@ -21,14 +21,19 @@ pub struct Context { } impl Context { - pub fn new(main_udp_socket: Vec, first_latency: bool, is_tcp: bool) -> Self { + pub fn new( + main_udp_socket: Vec, + use_channel_type: UseChannelType, + first_latency: bool, + is_tcp: bool, + ) -> Self { let channel_num = main_udp_socket.len(); assert_ne!(channel_num, 0, "not channel"); let inner = ContextInner { main_udp_socket, sub_udp_socket: RwLock::new(Vec::with_capacity(64)), tcp_map: RwLock::new(HashMap::with_capacity(64)), - route_table: RouteTable::new(first_latency, channel_num), + route_table: RouteTable::new(use_channel_type, first_latency, channel_num), is_tcp, }; Self { @@ -123,14 +128,14 @@ impl ContextInner { loop { let status = if self.route_table.route_one(&cur.virtual_gateway).is_some() { //已连接 - if cur.status == ConnectStatus::Connected { + if cur.status.online() { return cur; } //状态变为已连接 ConnectStatus::Connected } else { //未连接 - if cur.status == ConnectStatus::Connecting { + if cur.status.offline() { return cur; } //状态变为未连接 @@ -246,12 +251,14 @@ pub struct RouteTable { RwLock)>)>>, first_latency: bool, channel_num: usize, + use_channel_type: UseChannelType, } impl RouteTable { - fn new(first_latency: bool, channel_num: usize) -> Self { + fn new(use_channel_type: UseChannelType, first_latency: bool, channel_num: usize) -> Self { Self { route_table: RwLock::new(HashMap::with_capacity(64)), + use_channel_type, first_latency, channel_num, } @@ -295,6 +302,20 @@ impl RouteTable { self.add_route_(id, route, false) } fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) { + // 限制通道类型 + match self.use_channel_type { + UseChannelType::Relay => { + if route.metric < 2 { + return; + } + } + UseChannelType::P2p => { + if route.metric != 1 { + return; + } + } + UseChannelType::All => {} + } let key = route.route_key(); let mut route_table = self.route_table.write(); let (_, list) = route_table diff --git a/vnt/src/channel/mod.rs b/vnt/src/channel/mod.rs index a263ae4..2b06a07 100644 --- a/vnt/src/channel/mod.rs +++ b/vnt/src/channel/mod.rs @@ -1,5 +1,6 @@ use std::io; use std::net::{SocketAddr, UdpSocket}; +use std::str::FromStr; use std::time::Duration; use crate::channel::context::Context; @@ -19,7 +20,40 @@ pub mod tcp_channel; pub mod udp_channel; const BUFFER_SIZE: usize = 1024 * 16; +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum UseChannelType { + Relay, + P2p, + All, +} +impl UseChannelType { + pub fn is_only_relay(&self) -> bool { + self == &UseChannelType::Relay + } + pub fn is_only_p2p(&self) -> bool { + self == &UseChannelType::P2p + } + pub fn is_all(&self) -> bool { + self == &UseChannelType::All + } +} +impl FromStr for UseChannelType { + type Err = String; + fn from_str(s: &str) -> Result { + match s.to_lowercase().trim() { + "relay" => Ok(UseChannelType::Relay), + "p2p" => Ok(UseChannelType::P2p), + "all" => Ok(UseChannelType::All), + _ => Err(format!("not match '{}', enum: relay/p2p/all", s)), + } + } +} +impl Default for UseChannelType { + fn default() -> Self { + UseChannelType::All + } +} #[derive(Copy, Clone, Eq, PartialEq)] pub enum Status { Cone, @@ -104,6 +138,7 @@ impl RouteKey { pub fn init_context( ports: Vec, + use_channel_type: UseChannelType, first_latency: bool, is_tcp: bool, ) -> io::Result<(Context, mio::net::TcpListener)> { @@ -123,7 +158,7 @@ pub fn init_context( main_channel.set_write_timeout(Some(Duration::from_secs(5)))?; udps.push(main_channel); } - let context = Context::new(udps, first_latency, is_tcp); + let context = Context::new(udps, use_channel_type, first_latency, is_tcp); let port = context.main_local_udp_port()?[0]; //监听v6+v4双栈,tcp通道使用异步io diff --git a/vnt/src/channel/punch.rs b/vnt/src/channel/punch.rs index a0d2aaf..adf172d 100644 --- a/vnt/src/channel/punch.rs +++ b/vnt/src/channel/punch.rs @@ -24,7 +24,8 @@ impl FromStr for PunchModel { match s.to_lowercase().trim() { "ipv4" => Ok(PunchModel::IPv4), "ipv6" => Ok(PunchModel::IPv6), - _ => Ok(PunchModel::All), + "all" => Ok(PunchModel::All), + _ => Err(format!("not match '{}', enum: ipv4/ipv6/all", s)), } } } diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 01cc1ad..9e1ddcb 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -15,7 +15,7 @@ use tun::device::IFace; use crate::channel::context::Context; use crate::channel::idle::Idle; use crate::channel::punch::{NatInfo, Punch}; -use crate::channel::{init_channel, init_context, Route, RouteKey}; +use crate::channel::{init_channel, init_context, Route, RouteKey, UseChannelType}; use crate::cipher::Cipher; #[cfg(feature = "server_encrypt")] use crate::cipher::RsaCipher; @@ -87,7 +87,12 @@ impl Vnt { } }); //通道上下文 - let (context, tcp_listener) = init_context(ports, config.first_latency, config.tcp)?; + let (context, tcp_listener) = init_context( + ports, + config.use_channel_type, + config.first_latency, + config.tcp, + )?; let local_ipv4 = nat::local_ipv4(); let local_ipv6 = nat::local_ipv6(); let udp_ports = context.main_local_udp_port()?; @@ -143,7 +148,7 @@ impl Vnt { config_info.clone(), nat_test.clone(), callback.clone(), - config.relay, + config.use_channel_type, punch_sender, peer_nat_info_map.clone(), external_route.clone(), @@ -192,8 +197,8 @@ impl Vnt { let nat_test = nat_test.clone(); let device_list = device_list.clone(); let current_device = current_device.clone(); - let relay = config.relay; - if !relay { + let use_channel_type = config.use_channel_type; + if !use_channel_type.is_only_relay() { // 定时nat探测 maintain::retrieve_nat_type( &scheduler, @@ -216,7 +221,7 @@ impl Vnt { config_info, punch, callback, - relay, + use_channel_type, ); }); } @@ -247,7 +252,7 @@ pub fn start( config_info: BaseConfigInfo, punch: Punch, callback: Call, - relay: bool, + use_channel_type: UseChannelType, ) { // 定时心跳 maintain::heartbeat( @@ -284,7 +289,7 @@ pub fn start( server_cipher.clone(), config_info.clone(), ); - if !relay { + if !use_channel_type.is_only_relay() { // 定时打洞 maintain::punch( &scheduler, diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index 4f7b815..920d157 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -4,6 +4,7 @@ use std::net::{Ipv4Addr, SocketAddr}; pub use conn::Vnt; use crate::channel::punch::PunchModel; +use crate::channel::UseChannelType; use crate::cipher::CipherModel; mod conn; @@ -24,7 +25,6 @@ pub struct Config { pub mtu: Option, pub tcp: bool, pub ip: Option, - pub relay: bool, #[cfg(feature = "ip_proxy")] pub no_proxy: bool, pub server_encrypt: bool, @@ -38,6 +38,7 @@ pub struct Config { pub device_name: Option, #[cfg(target_os = "android")] pub device_fd: i32, + pub use_channel_type: UseChannelType, } impl Config { @@ -55,7 +56,6 @@ impl Config { mtu: Option, tcp: bool, ip: Option, - relay: bool, #[cfg(feature = "ip_proxy")] no_proxy: bool, server_encrypt: bool, parallel: usize, @@ -66,6 +66,7 @@ impl Config { first_latency: bool, #[cfg(not(target_os = "android"))] device_name: Option, #[cfg(target_os = "android")] device_fd: i32, + use_channel_type: UseChannelType, ) -> io::Result { for x in stun_server.iter_mut() { if !x.contains(":") { @@ -96,7 +97,6 @@ impl Config { mtu, tcp, ip, - relay, #[cfg(feature = "ip_proxy")] no_proxy, server_encrypt, @@ -110,6 +110,7 @@ impl Config { device_name, #[cfg(target_os = "android")] device_fd, + use_channel_type, }) } } diff --git a/vnt/src/handle/recv_data/client.rs b/vnt/src/handle/recv_data/client.rs index 5470242..58cb730 100644 --- a/vnt/src/handle/recv_data/client.rs +++ b/vnt/src/handle/recv_data/client.rs @@ -15,7 +15,7 @@ use tun::Device; use crate::channel::context::Context; use crate::channel::punch::NatInfo; -use crate::channel::{Route, RouteKey}; +use crate::channel::{Route, RouteKey, UseChannelType}; use crate::cipher::Cipher; use crate::external_route::AllowExternalRoute; use crate::handle::recv_data::PacketHandler; @@ -35,7 +35,7 @@ use crate::protocol::{ pub struct ClientPacketHandler { device: Arc, client_cipher: Cipher, - relay: bool, + use_channel_type: UseChannelType, punch_sender: SyncSender<(Ipv4Addr, NatInfo)>, peer_nat_info_map: Arc>>, nat_test: NatTest, @@ -48,7 +48,7 @@ impl ClientPacketHandler { pub fn new( device: Arc, client_cipher: Cipher, - relay: bool, + use_channel_type: UseChannelType, punch_sender: SyncSender<(Ipv4Addr, NatInfo)>, peer_nat_info_map: Arc>>, nat_test: NatTest, @@ -58,7 +58,7 @@ impl ClientPacketHandler { Self { device, client_cipher, - relay, + use_channel_type, punch_sender, peer_nat_info_map, nat_test, @@ -189,7 +189,7 @@ impl ClientPacketHandler { context.route_table.add_route(source, route); } ControlPacket::PunchRequest => { - if self.relay { + if self.use_channel_type.is_only_relay() { return Ok(()); } //回应 @@ -203,7 +203,7 @@ impl ClientPacketHandler { context.route_table.add_route_if_absent(source, route); } ControlPacket::PunchResponse => { - if self.relay { + if self.use_channel_type.is_only_relay() { return Ok(()); } let route = Route::from(route_key, 1, 199); @@ -237,7 +237,7 @@ impl ClientPacketHandler { net_packet: NetPacket<&mut [u8]>, route_key: RouteKey, ) -> io::Result<()> { - if self.relay { + if self.use_channel_type.is_only_relay() { return Ok(()); } let source = net_packet.source(); diff --git a/vnt/src/handle/recv_data/mod.rs b/vnt/src/handle/recv_data/mod.rs index 13a9c90..5040ad6 100644 --- a/vnt/src/handle/recv_data/mod.rs +++ b/vnt/src/handle/recv_data/mod.rs @@ -12,7 +12,7 @@ use tun::Device; use crate::channel::context::Context; use crate::channel::handler::RecvChannelHandler; use crate::channel::punch::NatInfo; -use crate::channel::RouteKey; +use crate::channel::{RouteKey, UseChannelType}; use crate::cipher::Cipher; #[cfg(feature = "server_encrypt")] use crate::cipher::RsaCipher; @@ -60,7 +60,7 @@ impl RecvDataHandler { config_info: BaseConfigInfo, nat_test: NatTest, callback: Call, - relay: bool, + use_channel_type: UseChannelType, punch_sender: SyncSender<(Ipv4Addr, NatInfo)>, peer_nat_info_map: Arc>>, external_route: ExternalRoute, @@ -83,7 +83,7 @@ impl RecvDataHandler { let client = ClientPacketHandler::new( device.clone(), client_cipher, - relay, + use_channel_type, punch_sender, peer_nat_info_map, nat_test,