From af58c3990dba7385a87679cec5dca135dc2f70f5 Mon Sep 17 00:00:00 2001 From: lubeilin <1791778603@qq.com> Date: Sun, 5 Feb 2023 18:35:27 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=9B=B4=E6=96=B0=E5=AF=B9=E7=A7=B0NAT?= =?UTF-8?q?=E7=9A=84=E6=89=93=E6=B4=9E=E6=96=B9=E5=BC=8F=EF=BC=9B2.?= =?UTF-8?q?=E6=94=AF=E6=8C=81windows=E6=9C=8D=E5=8A=A1=EF=BC=9B3.=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=8D=8F=E8=AE=AE=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- switch-desktop/Cargo.toml | 12 +- switch-desktop/src/command/client.rs | 35 +++ switch-desktop/src/command/mod.rs | 2 + switch-desktop/src/command/server.rs | 157 ++++++++++++ switch-desktop/src/config/mod.rs | 100 ++++++++ switch-desktop/src/main.rs | 161 +++++++----- switch-desktop/src/windows/mod.rs | 229 +++++++++++++----- switch-desktop/src/windows/service.rs | 108 ++++++++- .../src/{ => windows}/windows_admin_check.rs | 0 switch-jni/src/lib.rs | 26 +- switch/Cargo.toml | 2 +- switch/proto/message.proto | 7 - switch/src/handle/mod.rs | 6 +- switch/src/handle/punch_handler.rs | 127 ++++------ switch/src/handle/registration_handler.rs | 54 ++--- switch/src/handle/tun_handler.rs | 4 +- switch/src/handle/udp_recv_handler.rs | 15 +- switch/src/lib.rs | 108 ++++++--- switch/src/proto/message.rs | 95 +------- switch/src/tun_device/mac.rs | 5 - 20 files changed, 865 insertions(+), 388 deletions(-) create mode 100644 switch-desktop/src/command/client.rs create mode 100644 switch-desktop/src/command/mod.rs create mode 100644 switch-desktop/src/command/server.rs create mode 100644 switch-desktop/src/config/mod.rs rename switch-desktop/src/{ => windows}/windows_admin_check.rs (100%) diff --git a/switch-desktop/Cargo.toml b/switch-desktop/Cargo.toml index b98a8a3..5ceebd1 100644 --- a/switch-desktop/Cargo.toml +++ b/switch-desktop/Cargo.toml @@ -15,10 +15,20 @@ log = "0.4.17" log4rs = "1.2.0" tokio = { version = "1.24.1", features = ["full"] } chrono = "0.4.23" + +serde = "1.0" +serde_yaml = "0.9" +crossbeam = "0.8.2" +lazy_static = "1.4.0" +parking_lot = "0.12.1" + +#parity-tokio-ipc = "0.9.0" +futures = "0.3" [target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies] sudo = "0.6.0" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] } -runas = "0.2.1" +#runas = "0.2.1" windows-service = "0.5.0" + diff --git a/switch-desktop/src/command/client.rs b/switch-desktop/src/command/client.rs new file mode 100644 index 0000000..b570b7a --- /dev/null +++ b/switch-desktop/src/command/client.rs @@ -0,0 +1,35 @@ +use std::io; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; +use std::time::Duration; + +pub struct CommandClient { + udp: UdpSocket, +} + +impl CommandClient { + pub fn new() -> io::Result { + let port = crate::config::read_command_port().unwrap(); + let udp = UdpSocket::bind("127.0.0.1:0")?; + udp.set_read_timeout(Some(Duration::from_secs(5)))?; + udp.connect(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new(127, 0, 0, 1), + port, + )))?; + Ok(Self { udp }) + } +} + +impl CommandClient { + pub fn list(&self) -> io::Result { + self.udp.send(b"list")?; + let mut buf = [0; 10240]; + let len = self.udp.recv(&mut buf)?; + Ok(String::from_utf8(buf[..len].to_vec()).unwrap()) + } + pub fn status(&self) -> io::Result { + self.udp.send(b"status")?; + let mut buf = [0; 10240]; + let len = self.udp.recv(&mut buf)?; + Ok(String::from_utf8(buf[..len].to_vec()).unwrap()) + } +} diff --git a/switch-desktop/src/command/mod.rs b/switch-desktop/src/command/mod.rs new file mode 100644 index 0000000..c07f47e --- /dev/null +++ b/switch-desktop/src/command/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod server; diff --git a/switch-desktop/src/command/server.rs b/switch-desktop/src/command/server.rs new file mode 100644 index 0000000..530e5bf --- /dev/null +++ b/switch-desktop/src/command/server.rs @@ -0,0 +1,157 @@ +use std::io; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; + +use std::sync::Arc; + +use console::style; + +use switch::handle::{PeerDeviceStatus, RouteType}; +use switch::Switch; + +pub struct CommandServer {} + +impl CommandServer { + pub fn new() -> Self { + Self {} + } +} + +impl CommandServer { + pub fn start(&self, switch: Arc) -> io::Result<()> { + let mut port = 21637 as u16; + let udp = loop { + match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new(127, 0, 0, 1), + port, + ))) { + Ok(udp) => { + break udp; + } + Err(e) => { + if e.kind() == io::ErrorKind::AddrInUse { + port += 1; + } else { + log::error!("创建udp失败 {:?}", e); + return Err(e); + } + } + } + }; + crate::config::update_command_port(port)?; + let mut buf = [0u8; 64]; + loop { + let (len, addr) = udp.recv_from(&mut buf)?; + match std::str::from_utf8(&buf[..len]) { + Ok(cmd) => { + if let Ok(out) = command(cmd, &switch) { + udp.send_to(out.as_bytes(), addr)?; + } + } + Err(e) => { + log::warn!("{:?}", e); + } + } + } + } +} +fn command(cmd: &str, switch: &Switch) -> io::Result { + let mut out_str = String::new(); + match cmd { + "list" => { + let server_rt = switch.server_rt(); + let device_list = switch.device_list(); + if device_list.is_empty() { + return Ok("No other devices found\n".to_string()); + } + for peer_device_info in device_list { + let route = switch.route(&peer_device_info.virtual_ip); + let str = if peer_device_info.status == PeerDeviceStatus::Online { + if route.route_type == RouteType::P2P { + let str = if route.rt >= 0 { + format!( + "[{}] {}(p2p delay:{}ms)\n", + peer_device_info.name, peer_device_info.virtual_ip, route.rt + ) + } else { + format!( + "[{}] {}(p2p)", + peer_device_info.name, peer_device_info.virtual_ip + ) + }; + style(str).green().to_string() + } else { + let str = if server_rt >= 0 { + format!( + "[{}] {}(relay delay:{}ms)\n", + peer_device_info.name, + peer_device_info.virtual_ip, + server_rt * 2 + ) + } else { + format!( + "[{}] {}(relay)\n", + peer_device_info.name, peer_device_info.virtual_ip + ) + }; + style(str).blue().to_string() + } + } else { + let str = format!( + "[{}] {}(Offline)\n", + peer_device_info.name, peer_device_info.virtual_ip + ); + style(str).red().to_string() + }; + out_str.push_str(&str); + } + } + "status" => { + let server_rt = switch.server_rt(); + let current_device = switch.current_device(); + let str = format!("Virtual ip:{}\n", style(current_device.virtual_ip).green()); + out_str.push_str(&str); + let str = format!( + "Virtual gateway:{}\n", + style(current_device.virtual_gateway).green() + ); + out_str.push_str(&str); + let str = format!( + "Connection status :{}\n", + style(format!("{:?}", switch.connection_status())).green() + ); + out_str.push_str(&str); + let str = format!( + "Relay server :{}\n", + style(current_device.connect_server).green() + ); + out_str.push_str(&str); + if server_rt >= 0 { + let str = format!("Delay of relay server :{}ms\n", style(server_rt).green()); + out_str.push_str(&str); + } + } + "help" | "h" => { + let str = format!("Options: \n"); + out_str.push_str(&str); + let str = format!( + "{} , Query the virtual IP of other devices\n", + style("list").green() + ); + out_str.push_str(&str); + let str = format!("{} , View current device status\n", style("status").green()); + out_str.push_str(&str); + let str = format!("{} , Exit the program\n", style("exit").green()); + out_str.push_str(&str); + } + "exit" => { + switch.stop_async(); + } + _ => { + let str = format!("command '{}' not fount. \n", style(cmd).red()); + out_str.push_str(&str); + let str = format!("Try to enter: '{}'\n", style("help").green()); + out_str.push_str(&str); + } + } + Ok(out_str) +} diff --git a/switch-desktop/src/config/mod.rs b/switch-desktop/src/config/mod.rs new file mode 100644 index 0000000..9c2e758 --- /dev/null +++ b/switch-desktop/src/config/mod.rs @@ -0,0 +1,100 @@ +use std::fs::File; +use std::io; +use std::io::{Read, Write}; +use std::path::PathBuf; + +use lazy_static::lazy_static; +use parking_lot::Mutex; +use serde::{Deserialize, Serialize}; + +lazy_static! { + static ref CONFIG: Mutex> = Mutex::new(None); + static ref SWITCH_HOME_PATH: Mutex> = Mutex::new(None); +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ArgsConfig { + pub token: String, + pub name: Option, + pub command_port: Option, +} + +impl ArgsConfig { + pub fn new(token: String, name: Option) -> Self { + Self { + token, + name, + command_port: None, + } + } +} + +pub fn save_config(config: ArgsConfig) -> io::Result<()> { + let config_path = dirs::home_dir().unwrap().join(".switch").join("config"); + save_config_(config, config_path) +} + +fn save_config_(config: ArgsConfig, config_path: PathBuf) -> io::Result<()> { + let str = serde_yaml::to_string(&config).unwrap(); + let mut file = File::create(config_path)?; + file.write_all(str.as_bytes()) +} + +pub fn update_command_port(port: u16) -> io::Result<()> { + let home_lock = SWITCH_HOME_PATH.lock(); + if let Some(home) = home_lock.clone() { + drop(home_lock); + let config_path = home.join("config"); + if let Some(mut config) = read_config() { + config.command_port = Some(port); + return save_config_(config, config_path); + } + } + Err(io::Error::new(io::ErrorKind::Other, "not found")) +} + +pub fn read_command_port() -> io::Result { + let home = dirs::home_dir().unwrap().join(".switch"); + let config = read_config_(home)?; + Ok(config.command_port.unwrap()) +} + +pub fn read_config() -> Option { + let mut lock = CONFIG.lock(); + let c = lock.clone(); + if c.is_some() { + return c; + } + if let Some(home) = SWITCH_HOME_PATH.lock().clone() { + match read_config_(home) { + Ok(config) => { + lock.replace(config.clone()); + Some(config) + } + Err(e) => { + log::error!("{:?}", e); + None + } + } + } else { + None + } +} + +pub fn set_home(home: PathBuf) { + SWITCH_HOME_PATH.lock().replace(home); +} + +fn read_config_(home: PathBuf) -> io::Result { + let config_path = home.join("config"); + let mut file = File::open(config_path)?; + let mut str = String::new(); + file.read_to_string(&mut str)?; + match serde_yaml::from_str::(&str) { + Ok(config) => Ok(config), + Err(e) => { + log::warn!("{:?}", e); + Err(io::Error::new(io::ErrorKind::Other, "config error")) + } + } +} diff --git a/switch-desktop/src/main.rs b/switch-desktop/src/main.rs index fa1065c..4f2a2d1 100644 --- a/switch-desktop/src/main.rs +++ b/switch-desktop/src/main.rs @@ -1,19 +1,23 @@ +use std::io; +use std::path::PathBuf; + use clap::Parser; use console::style; -use switch::*; -use switch::handle::{PeerDeviceStatus, RouteType}; -#[cfg(windows)] -mod windows_admin_check; +use switch::handle::{PeerDeviceStatus, RouteType}; +use switch::*; + +mod command; +mod config; #[cfg(windows)] mod windows; #[derive(Parser, Debug)] #[command( -author = "Lu Beilin", -version, -about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信" + author = "Lu Beilin", + version, + about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信" )] struct Args { /// 32位字符 @@ -29,24 +33,52 @@ struct Args { name: Option, } -fn log_init() { - let home = dirs::home_dir().unwrap().join(".switch"); +fn log_init_service(home: PathBuf) -> io::Result<()> { if !home.exists() { - std::fs::create_dir(&home).expect(" Failed to create '.switch' directory"); + std::fs::create_dir(&home)?; } - let stderr = log4rs::append::console::ConsoleAppender::builder().target(log4rs::append::console::Target::Stderr).build(); let logfile = log4rs::append::file::FileAppender::builder() // Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html .encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new( "{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n", ))) - .build(home.join("switch.log")) - .unwrap(); - let config = log4rs::Config::builder() + .build(home.join("switch-service.log"))?; + match log4rs::Config::builder() + .appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile))) + .build( + log4rs::config::Root::builder() + .appender("logfile") + .build(log::LevelFilter::Info), + ) { + Ok(config) => { + let _ = log4rs::init_config(config); + } + Err(_) => {} + } + Ok(()) +} + +fn log_init() -> io::Result<()> { + let home = dirs::home_dir().unwrap().join(".switch"); + if !home.exists() { + std::fs::create_dir(&home)?; + } + let stderr = log4rs::append::console::ConsoleAppender::builder() + .target(log4rs::append::console::Target::Stderr) + .build(); + let logfile = log4rs::append::file::FileAppender::builder() + // Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html + .encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new( + "{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n", + ))) + .build(home.join("switch.log"))?; + match log4rs::Config::builder() .appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile))) .appender( log4rs::config::Appender::builder() - .filter(Box::new(log4rs::filter::threshold::ThresholdFilter::new(log::LevelFilter::Error))) + .filter(Box::new(log4rs::filter::threshold::ThresholdFilter::new( + log::LevelFilter::Error, + ))) .build("stderr", Box::new(stderr)), ) .build( @@ -54,53 +86,57 @@ fn log_init() { .appender("logfile") .appender("stderr") .build(log::LevelFilter::Info), - ) - .unwrap(); - let _ = log4rs::init_config(config); + ) { + Ok(config) => { + let _ = log4rs::init_config(config); + } + Err(_) => {} + } + Ok(()) } +#[cfg(windows)] +fn main() { + let args: Vec<_> = std::env::args().collect(); + if args.len() == 3 && args[1] == windows::SERVICE_FLAG { + //以服务的方式启动 + let _ = log_init_service(PathBuf::from(&args[2])); + config::set_home(PathBuf::from(&args[2])); + log::info!("config {:?}", PathBuf::from(&args[2])); + log::info!("config {:?}", config::read_config()); + windows::service::start(); + return; + } else { + let _ = log_init(); + windows::main0(); + } + // println!("{}", style("starting...").green()); +} + +#[cfg(any(target_os = "linux", target_os = "macos"))] fn main() { log_init(); let args = Args::parse(); - #[cfg(windows)] - if !windows_admin_check::is_app_elevated() { - let args: Vec<_> = std::env::args().collect(); - println!("{}", style("正在启动管理员权限执行...").red()); - if let Some(absolute_path) = std::env::current_exe() - .ok() - .and_then(|p| p.to_str().map(|p| p.to_string())) - { - let _ = runas::Command::new(&absolute_path) - .args(&args[1..]) - .status() - .expect("failed to execute"); - } else { - panic!("failed to execute") - } - return; - } - - #[cfg(any(unix))] if sudo::RunningAs::Root != sudo::check() { println!("{}", style("需要使用root权限执行...").red()); sudo::escalate_if_needed().unwrap(); } println!("{}", style("starting...").green()); + start(args.token, args.name); +} + +pub fn start(token: String, name: Option) { let mac_address = mac_address::get_mac_address().unwrap().unwrap().to_string(); - let switch = match Config::new(args.token, mac_address, args.name, || {}) { - Ok(config) => { - match Switch::start(config) { - Ok(switch) => { - switch - } - Err(e) => { - log::error!("{:?}",e); - return; - } + let switch = match Config::new(token, mac_address, name, || {}) { + Ok(config) => match Switch::start(config) { + Ok(switch) => switch, + Err(e) => { + log::error!("{:?}", e); + return; } - } + }, Err(e) => { - log::error!("{:?}",e); + log::error!("{:?}", e); return; } }; @@ -155,21 +191,38 @@ fn command(cmd: &str, switch: &Switch) -> Result<(), ()> { if peer_device_info.status == PeerDeviceStatus::Online { if route.route_type == RouteType::P2P { let str = if route.rt >= 0 { - format!("[{}] {}(p2p delay:{}ms)", peer_device_info.name, peer_device_info.virtual_ip, route.rt) + format!( + "[{}] {}(p2p delay:{}ms)", + peer_device_info.name, peer_device_info.virtual_ip, route.rt + ) } else { - format!("[{}] {}(p2p)", peer_device_info.name, peer_device_info.virtual_ip) + format!( + "[{}] {}(p2p)", + peer_device_info.name, peer_device_info.virtual_ip + ) }; println!("{}", style(str).green()); } else { let str = if server_rt >= 0 { - format!("[{}] {}(relay delay:{}ms)", peer_device_info.name, peer_device_info.virtual_ip, server_rt * 2) + format!( + "[{}] {}(relay delay:{}ms)", + peer_device_info.name, + peer_device_info.virtual_ip, + server_rt * 2 + ) } else { - format!("[{}] {}(relay)", peer_device_info.name, peer_device_info.virtual_ip) + format!( + "[{}] {}(relay)", + peer_device_info.name, peer_device_info.virtual_ip + ) }; println!("{}", style(str).blue()); } } else { - let str = format!("[{}] {}(Offline)", peer_device_info.name, peer_device_info.virtual_ip); + let str = format!( + "[{}] {}(Offline)", + peer_device_info.name, peer_device_info.virtual_ip + ); println!("{}", style(str).red()); } } diff --git a/switch-desktop/src/windows/mod.rs b/switch-desktop/src/windows/mod.rs index 9971b97..9f4c066 100644 --- a/switch-desktop/src/windows/mod.rs +++ b/switch-desktop/src/windows/mod.rs @@ -1,7 +1,20 @@ +use std::{io, thread}; +use std::ffi::OsString; +use std::path::PathBuf; +use std::time::Duration; + use clap::Parser; use console::style; +use windows_service::Error; +use windows_service::service::{ + ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType, ServiceState, ServiceType, +}; +use windows_service::service_manager::{ServiceManager, ServiceManagerAccess}; + +use crate::config; pub mod service; +mod windows_admin_check; #[derive(Parser, Debug)] #[command( @@ -17,13 +30,13 @@ struct Args { /// Only devices with the same token can communicate with each other. /// It is recommended to use uuid to ensure uniqueness #[arg(long)] - token: String, + token: Option, /// 给设备一个名称,为空时默认用系统版本信息 #[arg(long)] name: Option, - /// 安装服务,安装后可以后台运行 + /// 安装服务,安装后可以后台运行,需要指定安装路径 #[arg(long)] - install: bool, + install: Option, /// 卸载服务 #[arg(long)] uninstall: bool, @@ -32,72 +45,165 @@ struct Args { #[arg(long)] start: bool, #[arg(long)] - /// 停止,安装服务后,使用--stop停止服务 + /// 停止,安装服务后,使用 --stop停止服务 stop: bool, - + /// 启动服务后,使用 --list 查看设备列表 + #[arg(long)] + list: bool, + /// 启动服务后,使用 --status 查看设备状态 + #[arg(long)] + status: bool, } -const SERVICE_FLAG: &'static str = "start_switch_service_"; -const SERVICE_NAME: &'static str = "switch-service"; +pub const SERVICE_FLAG: &'static str = "start_switch_service_"; +pub const SERVICE_NAME: &'static str = "switch-service"; +pub const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS; pub fn main0() { - let args: Vec<_> = std::env::args().collect(); - if args.len() == 2 && args[1] == SERVICE_FLAG { - //以服务的方式启动 - service::start(); - } let args = Args::parse(); - if args.install { - if let Err(e) = install() { - log::error!("{:?}",e); - }else{ - println!("{}",style("安装成功").green()) + if args.list || args.status { + match service_state() { + Ok(state) => { + if state == ServiceState::Running { + let command_client = crate::command::client::CommandClient::new().unwrap(); + let out = if args.list { + command_client.list().unwrap() + } else if args.status { + command_client.status().unwrap() + } else { + "".to_string() + }; + println!("{}", out); + } else { + println!("服务未启动") + } + } + Err(e) => { + println!("{:?}", e); + } } - pause(); return; } - if args.uninstall { + if !windows_admin_check::is_app_elevated() { + println!("{}", style("请使用管理员权限运行").red()); + return; + } + if let Some(path) = args.install { + let path: PathBuf = path.into(); + if !path.exists() { + std::fs::create_dir_all(&path).unwrap(); + } + if !path.is_dir() { + println!("参数必须为文件目录"); + } else { + if let Err(e) = install(path) { + log::error!("{:?}", e); + } else { + println!("{}", style("安装成功").green()) + } + } + } else if args.uninstall { if let Err(e) = uninstall() { - log::error!("{:?}",e); - }else{ - println!("{}",style("卸载成功").green()) + log::error!("{:?}", e); + } else { + println!("{}", style("卸载成功").green()) } - pause(); - return; - } - if args.start { - if let Err(e) = start() { - log::error!("{:?}",e); - // 在当前进程启动 + } else if args.start { + match service_state() { + Ok(state) => { + if state == ServiceState::Stopped { + if args.token.is_none() { + println!("{}", style("需要参数 --token").red()); + } else { + let token = args.token.clone().unwrap(); + config::save_config(config::ArgsConfig::new( + token.clone(), + args.name.clone(), + )) + .unwrap(); + match start() { + Ok(_) => { + //需要检查启动状态 + println!("{}", style("启动成功").green()) + } + Err(e) => { + match e { + Error::Winapi(ref e) => { + if let Some(code) = e.raw_os_error() { + if code == 1060 { + //指定的服务未安装。 + println!( + "{}", + style("服务未安装,在当前进程启动").red() + ); + crate::start(token, args.name); + return; + } + } + } + _ => {} + } + log::error!("{:?}", e); + } + } + } + } else { + println!("服务未停止"); + } + } + Err(e) => { + println!("{:?}", e); + } } - pause(); + } else if args.stop { + match stop() { + Ok(_) => { + println!("{}", style("停止成功").green()) + } + Err(e) => { + log::error!("{:?}", e); + } + } + } else { + println!("使用参数 -h 查看帮助") } + pause(); } fn pause() { - println!("按任意键退出..."); - std::io::stdin().read_u8().unwrap(); + println!("{}", style("按任意键退出...").green()); + use console::Term; + let term = Term::stdout(); + let _ = term.read_char().unwrap(); } - -fn install() -> Result<(), windows_service::Error> { - use std::ffi::OsString; - use windows_service::{ - service::{ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType, ServiceType}, - service_manager::{ServiceManager, ServiceManagerAccess}, - }; - +fn install(path: PathBuf) -> Result<(), Error> { let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE; let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; - let service_binary_path = std::env::current_exe().unwrap(); + let current_exe_path = std::env::current_exe().unwrap(); + let service_path = path.join("switch-service.exe"); + std::fs::copy(current_exe_path, service_path.as_path()).unwrap(); + if let Err(e) = std::fs::copy("wintun.dll", path.join("wintun.dll").as_path()) { + if e.kind() == io::ErrorKind::NotFound { + println!("Not fount 'wintun.dll'. Please put 'wintun.dll' in the current directory"); + std::process::exit(0); + } else { + panic!("{:?}", e) + } + } + let mut launch_arguments = Vec::new(); + launch_arguments.push(OsString::from(SERVICE_FLAG)); + launch_arguments.push(OsString::from( + dirs::home_dir().unwrap().join(".switch").to_str().unwrap(), + )); let service_info = ServiceInfo { name: OsString::from(SERVICE_NAME), display_name: OsString::from("switch service"), service_type: ServiceType::OWN_PROCESS, start_type: ServiceStartType::OnDemand, error_control: ServiceErrorControl::Normal, - executable_path: service_binary_path.into(), - launch_arguments: vec![OsString::from(SERVICE_FLAG); 1], + executable_path: service_path.into(), + launch_arguments, dependencies: vec![], account_name: None, // run as System account_password: None, @@ -107,13 +213,7 @@ fn install() -> Result<(), windows_service::Error> { Ok(()) } -fn uninstall() -> Result<(), windows_service::Error> { - use std::{thread, time::Duration}; - use windows_service::{ - service::{ServiceAccess, ServiceState}, - service_manager::{ServiceManager, ServiceManagerAccess}, - }; - +fn uninstall() -> Result<(), Error> { let manager_access = ServiceManagerAccess::CONNECT; let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; @@ -131,14 +231,27 @@ fn uninstall() -> Result<(), windows_service::Error> { Ok(()) } -fn start() -> Result<(), windows_service::Error> { - use std::env; - use windows_service::{ - service::ServiceAccess, - service_manager::{ServiceManager, ServiceManagerAccess}, - }; +fn start() -> Result<(), Error> { let manager_access = ServiceManagerAccess::CONNECT; let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::START)?; - service.start(&[]) -} \ No newline at end of file + service.start(&[""]) +} + +fn service_state() -> Result { + let manager_access = ServiceManagerAccess::CONNECT; + let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; + + let service_access = ServiceAccess::QUERY_STATUS; + let service = service_manager.open_service(SERVICE_NAME, service_access)?; + let service_status = service.query_status()?; + return Ok(service_status.current_state); +} + +fn stop() -> Result<(), Error> { + let manager_access = ServiceManagerAccess::CONNECT; + let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; + let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::STOP)?; + service.stop()?; + Ok(()) +} diff --git a/switch-desktop/src/windows/service.rs b/switch-desktop/src/windows/service.rs index d21b4a7..e5b0972 100644 --- a/switch-desktop/src/windows/service.rs +++ b/switch-desktop/src/windows/service.rs @@ -2,12 +2,110 @@ // extern crate windows_service; use std::ffi::OsString; -use windows_service::{define_windows_service, service_dispatcher}; +use std::sync::Arc; +use std::thread; +use std::time::Duration; + + +use windows_service::service::{ + ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, +}; +use windows_service::service_control_handler::ServiceControlHandlerResult; +use windows_service::{define_windows_service, service_control_handler, service_dispatcher}; + +use switch::{Config, Switch}; + +use crate::windows::config::read_config; define_windows_service!(ffi_service_main, switch_service_main); -pub fn switch_service_main(arguments: Vec) { +pub fn switch_service_main(_arguments: Vec) { + thread::spawn(|| match service_main() { + Ok(_) => {} + Err(e) => { + log::warn!("{:?}", e); + } + }); +} +fn service_main() -> windows_service::Result<()> { + let parker = crossbeam::sync::Parker::new(); + let un_parker = parker.unparker().clone(); + let event_handler = move |control_event| -> ServiceControlHandlerResult { + match control_event { + // Notifies a service to report its current status information to the service + // control manager. Always return NoError even if not implemented. + ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, + + // Handle stop + ServiceControl::Stop => { + log::info!("handler 服务停止"); + un_parker.unpark(); + ServiceControlHandlerResult::NoError + } + _ => ServiceControlHandlerResult::NotImplemented, + } + }; + + // Register system service event handler. + // The returned status handle should be used to report service status changes to the system. + let status_handle = + service_control_handler::register(crate::windows::SERVICE_NAME, event_handler)?; + + // Tell the system that service is running + status_handle.set_service_status(ServiceStatus { + service_type: crate::windows::SERVICE_TYPE, + current_state: ServiceState::Running, + controls_accepted: ServiceControlAccept::STOP, + exit_code: ServiceExitCode::Win32(0), + checkpoint: 0, + wait_hint: Duration::default(), + process_id: None, + })?; + if let Some(config) = read_config() { + let mac_address = mac_address::get_mac_address().unwrap().unwrap().to_string(); + let un_parker = parker.unparker().clone(); + match Config::new(config.token, mac_address, config.name, move || { + un_parker.unpark(); + }) { + Ok(config) => match Switch::start(config) { + Ok(switch) => { + log::info!("switch-service服务启动"); + let switch = Arc::new(switch); + let command_server = crate::command::server::CommandServer::new(); + let switch1 = switch.clone(); + thread::spawn(move || { + if let Err(e) = command_server.start(switch1) { + log::warn!("{:?}", e); + } + }); + parker.park(); + switch.stop_async(); + thread::sleep(Duration::from_secs(1)); + log::info!("switch-service服务停止"); + } + Err(e) => { + log::error!("{:?}", e); + } + }, + Err(e) => { + log::error!("{:?}", e); + } + }; + } else { + log::info!("配置文件为空"); + } + status_handle.set_service_status(ServiceStatus { + service_type: crate::windows::SERVICE_TYPE, + current_state: ServiceState::Stopped, + controls_accepted: ServiceControlAccept::empty(), + exit_code: ServiceExitCode::Win32(0), + checkpoint: 0, + wait_hint: Duration::default(), + process_id: None, + }) +} + +pub fn start() { + log::info!("以服务的方式启动"); + service_dispatcher::start("switch-service", ffi_service_main).unwrap(); } -pub fn start(){ - service_dispatcher::start("switch-service",ffi_service_main).unwrap(); -} \ No newline at end of file diff --git a/switch-desktop/src/windows_admin_check.rs b/switch-desktop/src/windows/windows_admin_check.rs similarity index 100% rename from switch-desktop/src/windows_admin_check.rs rename to switch-desktop/src/windows/windows_admin_check.rs diff --git a/switch-jni/src/lib.rs b/switch-jni/src/lib.rs index ba430f2..dc9ce82 100644 --- a/switch-jni/src/lib.rs +++ b/switch-jni/src/lib.rs @@ -1,12 +1,12 @@ use std::net::{IpAddr, Ipv4Addr}; use jni::errors::Error; -use jni::JNIEnv; use jni::objects::{JClass, JObject, JString, JValue}; use jni::sys::{jbyte, jint, jintArray, jlong, jobject, jobjectArray, jsize}; +use jni::JNIEnv; -use switch::{Config, Switch}; use switch::handle::{CurrentDeviceInfo, PeerDeviceInfo, Route}; +use switch::{Config, Switch}; fn to_string_not_null(env: &JNIEnv, config: JObject, name: &str) -> Result { let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?; @@ -46,14 +46,14 @@ fn start(env: &JNIEnv, config: JObject) -> Result, Error> { let token = to_string_not_null(&env, config, "token")?; let mac_address = to_string_not_null(&env, config, "macAddress")?; let name = to_string(&env, config, "name")?; - let config = match Config::new(token, mac_address, name,||{}) { - Ok(config) => { config } + let config = match Config::new(token, mac_address, name, || {}) { + Ok(config) => config, Err(e) => { env.throw_new( "Ljava/lang/RuntimeException", format!("switch start failed {:?}", e), ) - .expect("throw"); + .expect("throw"); return Ok(None); } }; @@ -66,7 +66,7 @@ fn start(env: &JNIEnv, config: JObject) -> Result, Error> { "Ljava/lang/RuntimeException", format!("switch start failed {:?}", e), ) - .expect("throw"); + .expect("throw"); } } Ok(None) @@ -178,9 +178,11 @@ fn device_list(env: &JNIEnv, device_list: Vec) -> Result) -> Result Self { + pub fn new(virtual_ip: Ipv4Addr, name: String, status: u8) -> Self { Self { virtual_ip, name, @@ -70,7 +68,7 @@ impl From for PeerDeviceStatus { fn from(value: u8) -> Self { match value { 0 => PeerDeviceStatus::Online, - _ => PeerDeviceStatus::Offline + _ => PeerDeviceStatus::Offline, } } } diff --git a/switch/src/handle/punch_handler.rs b/switch/src/handle/punch_handler.rs index a0f110c..1d48e4c 100644 --- a/switch/src/handle/punch_handler.rs +++ b/switch/src/handle/punch_handler.rs @@ -1,10 +1,9 @@ +use std::{io, thread}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; -use std::thread; use std::time::Duration; -use dashmap::DashMap; -use lazy_static::lazy_static; use protobuf::Message; +use rand::prelude::SliceRandom; use tokio::sync::mpsc::{Receiver, Sender}; use tokio::sync::mpsc::error::TrySendError; use tokio::sync::watch; @@ -12,14 +11,11 @@ use tokio::sync::watch; use crate::{CurrentDeviceInfo, DEVICE_LIST, handle::NAT_INFO, handle::NatInfo}; use crate::error::*; use crate::handle::{ApplicationStatus, DIRECT_ROUTE_TABLE}; -use crate::proto::message::{NatType, Punch, Step}; +use crate::proto::message::{NatType, Punch}; use crate::protocol::{control_packet, NetPacket, Protocol, turn_packet, Version}; use crate::protocol::control_packet::PunchRequestPacket; use crate::protocol::turn_packet::TurnPacket; -lazy_static! { - pub static ref STEP_MAP: DashMap = DashMap::new(); -} /// 每一种类型一个通道,减少相互干扰 pub fn bounded() -> ( PunchSender, @@ -94,7 +90,7 @@ impl PunchSender { } fn handle( - status_watch: &watch::Receiver, + _status_watch: &watch::Receiver, udp: &UdpSocket, punch_list: Vec, buf: &[u8], @@ -108,58 +104,43 @@ fn handle( // println!("punch {:?}", punch); match punch.nat_type.enum_value_or_default() { NatType::Symmetric => { - match punch.step.enum_value_or_default() { - Step::Step1 | Step::Step2 | Step::Step3 => { - //预测范围发送 - for pub_ip in punch.public_ip_list { - let pub_ip = Ipv4Addr::from(pub_ip); - for range in 0..punch.public_port_range + 1 { - if counter & 10 == 10 { - if status_watch.has_changed()? { - return Ok(()); - } - } - let right_port = ((punch.public_port + range) & 0xFFFF) as u16; - let left_port = - ((0xFFFF + punch.public_port - range) & 0xFFFF) as u16; - if right_port != 0 { - // println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port))); - udp.send_to( - buf, - SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)), - )?; - select_sleep(&mut counter); - } - if left_port != 0 && range != 0 { - // println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port))); - if left_port == right_port { - break; - } - udp.send_to( - buf, - SocketAddr::V4(SocketAddrV4::new(pub_ip, left_port)), - )?; - select_sleep(&mut counter); - } - } - } - } - Step::Step4 => { - //全范围发送 - for pub_ip in punch.public_ip_list { - let pub_ip = Ipv4Addr::from(pub_ip); - for port in 1..0xFFFF { - if counter & 10 == 10 { - if status_watch.has_changed()? { - return Ok(()); - } - } - udp.send_to(buf, SocketAddr::V4(SocketAddrV4::new(pub_ip, port)))?; - select_sleep(&mut counter); - } + // 碰撞概率 p = 1 - e^(-(k^2+k)/(2n)) n = max_port-min_port 关键词:生日攻击 + let mut send_f = |min_port: u16, max_port: u16, k: usize| -> io::Result<()> { + let mut nums: Vec = (min_port..max_port).collect(); + let mut rng = rand::thread_rng(); + nums.shuffle(&mut rng); + for pub_ip in &punch.public_ip_list { + let pub_ip = Ipv4Addr::from(*pub_ip); + for port in &nums[..k] { + udp.send_to(buf, SocketAddr::V4(SocketAddrV4::new(pub_ip, *port)))?; + select_sleep(&mut counter); } } + Ok(()) + }; + if punch.public_port_range < 600 { + //端口变化不大时,在预测的范围内随机发送 + //如果公网端口在这个范围的话,碰撞的概率最低为70%; + let min_port = if punch.public_port > punch.public_port_range { + punch.public_port - punch.public_port_range + } else { + 1 + }; + let max_port = if punch.public_port + punch.public_port_range > 65535 { + 65535 + } else { + punch.public_port + punch.public_port_range + }; + let k = if max_port - min_port > 60 { + 60 + } else { + max_port - min_port + }; + send_f(min_port as u16, max_port as u16, k as usize)?; } + // 全端口范围,随机取600个端口发送 + // 取600个端口碰撞的概率为 93.6%,理论上成功的概率还是很高的 + send_f(1, 65535, 600)?; } NatType::Cone => { for pub_ip in punch.public_ip_list { @@ -269,23 +250,6 @@ async fn res_symmetric_handle_loop( } } } - for punch in &list { - let dest = Ipv4Addr::from(punch.virtual_ip); - match punch.step.enum_value_or_default() { - Step::Step1 => { - STEP_MAP.insert(dest, Step::Step2); - } - Step::Step2 => { - STEP_MAP.insert(dest, Step::Step3); - } - Step::Step3 => { - STEP_MAP.insert(dest, Step::Step4); - } - Step::Step4 => { - STEP_MAP.insert(dest, Step::Step1); - } - } - } if let Err(e) = handle(&status_watch,&udp, list, packet.buffer()) { log::warn!("{:?}",e) } @@ -381,7 +345,11 @@ async fn handle_loop( fn select_sleep(counter: &mut u64) { *counter += 1; - thread::sleep(Duration::from_millis(1)); + if *counter & 10 == 10 { + thread::sleep(Duration::from_millis(2)); + } else { + thread::sleep(Duration::from_millis(1)); + } } fn punch_request_handle(udp: &UdpSocket, cur_info: &CurrentDeviceInfo) -> Result<()> { @@ -406,12 +374,7 @@ fn send_punch(udp: &UdpSocket, cur_info: &CurrentDeviceInfo, nat_info: NatInfo) let ip = peer_info.virtual_ip; //只向ip比自己大的发起打洞,避免双方同时发起打洞浪费流量 if ip > cur_info.virtual_ip && !DIRECT_ROUTE_TABLE.contains_key(&ip) { - let step = if let Some(step) = STEP_MAP.get(&ip) { - *step - } else { - Step::Step1 - }; - let bytes = punch_packet(cur_info.virtual_ip, nat_info.clone(), ip, step)?; + let bytes = punch_packet(cur_info.virtual_ip, nat_info.clone(), ip)?; udp.send_to(&bytes, cur_info.connect_server)?; } } @@ -422,12 +385,10 @@ fn punch_packet( virtual_ip: Ipv4Addr, nat_info: NatInfo, dest: Ipv4Addr, - step: Step, ) -> Result> { let mut punch_reply = Punch::new(); punch_reply.reply = false; punch_reply.virtual_ip = u32::from_be_bytes(virtual_ip.octets()); - punch_reply.step = protobuf::EnumOrUnknown::new(step); punch_reply.public_ip_list = nat_info.public_ips; punch_reply.public_port = nat_info.public_port as u32; punch_reply.public_port_range = nat_info.public_port_range as u32; diff --git a/switch/src/handle/registration_handler.rs b/switch/src/handle/registration_handler.rs index 3a7cf8f..b98ccfb 100644 --- a/switch/src/handle/registration_handler.rs +++ b/switch/src/handle/registration_handler.rs @@ -11,8 +11,8 @@ use protobuf::Message; use crate::error::*; use crate::handle::ConnectStatus; use crate::proto::message::{RegistrationRequest, RegistrationResponse}; -use crate::protocol::{error_packet, NetPacket, Protocol, service_packet, Version}; use crate::protocol::error_packet::InErrorPacket; +use crate::protocol::{service_packet, NetPacket, Protocol, Version}; lazy_static::lazy_static! { static ref REQUEST:RwLock> = parking_lot::const_rwlock(None); @@ -29,7 +29,8 @@ pub fn registration( name: String, ) -> Result { // todo 和服务器通信加密 - let request_packet = registration_request_packet(token.clone(), mac_address.clone(), name.clone(), false)?; + let request_packet = + registration_request_packet(token.clone(), mac_address.clone(), name.clone(), false)?; let buf = request_packet.buffer(); let mut counter = 0; let mut recv_buf = [0u8; 10240]; @@ -68,30 +69,20 @@ pub fn registration( } } Protocol::Error => { - return match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload()) { - Ok(e) => { - match e { - InErrorPacket::TokenError => { - Err(Error::Stop("token错误".to_string())) - } - InErrorPacket::Disconnect => { - Err(Error::Stop("断开连接".to_string())) - } - InErrorPacket::OtherError(e) => { - match e.message() { - Ok(str) => { - Err(Error::Stop(str)) - } - Err(e) => { - Err(Error::Stop(format!("{:?}", e))) - } - } - } - } - } - Err(e) => { - Err(Error::Stop(format!("{:?}", e))) - } + return match InErrorPacket::new( + net_packet.transport_protocol(), + net_packet.payload(), + ) { + Ok(e) => match e { + InErrorPacket::TokenError => Err(Error::Stop("token错误".to_string())), + InErrorPacket::Disconnect => Err(Error::Stop("断开连接".to_string())), + InErrorPacket::AddressExhausted => Err(Error::Stop("地址用尽".to_string())), + InErrorPacket::OtherError(e) => match e.message() { + Ok(str) => Err(Error::Stop(str)), + Err(e) => Err(Error::Stop(format!("{:?}", e))), + }, + }, + Err(e) => Err(Error::Stop(format!("{:?}", e))), }; } _ => { @@ -101,7 +92,12 @@ pub fn registration( } } -fn registration_request_packet(token: String, mac_address: String, name: String, is_fast: bool) -> Result>> { +fn registration_request_packet( + token: String, + mac_address: String, + name: String, + is_fast: bool, +) -> Result>> { let mut request = RegistrationRequest::new(); request.token = token; request.mac_address = mac_address; @@ -123,8 +119,8 @@ pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result< let new = Local::now().timestamp_millis(); if new - last < 2000 || REGISTRATION_TIME - .compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed) - .is_err() + .compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed) + .is_err() { //短时间不重复注册 return Ok(()); diff --git a/switch/src/handle/tun_handler.rs b/switch/src/handle/tun_handler.rs index 002668a..570d2dc 100644 --- a/switch/src/handle/tun_handler.rs +++ b/switch/src/handle/tun_handler.rs @@ -10,12 +10,12 @@ use packet::icmp::Kind; use packet::ip::ipv4; use packet::ip::ipv4::packet::IpV4Packet; -use crate::ApplicationStatus; use crate::error::*; use crate::handle::{CurrentDeviceInfo, DIRECT_ROUTE_TABLE}; -use crate::protocol::{NetPacket, Protocol, Version}; use crate::protocol::turn_packet::TurnPacket; +use crate::protocol::{NetPacket, Protocol, Version}; use crate::tun_device::TunReader; +use crate::ApplicationStatus; /// 是否在一个网段 fn check_dest(dest: Ipv4Addr, cur_info: &CurrentDeviceInfo) -> bool { diff --git a/switch/src/handle/udp_recv_handler.rs b/switch/src/handle/udp_recv_handler.rs index ec2d506..ef06650 100644 --- a/switch/src/handle/udp_recv_handler.rs +++ b/switch/src/handle/udp_recv_handler.rs @@ -176,7 +176,9 @@ pub async fn udp_other_recv_start( { tokio::spawn(async move { match other_loop(status_watch, udp, receiver, current_device, sender).await { - Ok(_) => {} + Ok(_) => { + log::info!("udp子处理线程停止"); + } Err(e) => { log::warn!("{:?}", e); } @@ -237,14 +239,20 @@ fn other_handle( let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?; crate::handle::init_nat_info(response.public_ip, response.public_port as u16); CONNECTION_STATUS.store(ConnectStatus::Connected); - //todo 重连之后ip可能会发生改变(目前2分钟内未重连则会释放ip),需要更新本地ip(或者保证重连ip不变) + //需要保证重连ip不变 } service_packet::Protocol::UpdateDeviceList => { let device_list = DeviceList::parse_from_bytes(net_packet.payload())?; let ip_list = device_list .device_info_list .into_iter() - .map(|info| PeerDeviceInfo::new(Ipv4Addr::from(info.virtual_ip), info.name, info.device_status as u8)) + .map(|info| { + PeerDeviceInfo::new( + Ipv4Addr::from(info.virtual_ip), + info.name, + info.device_status as u8, + ) + }) .collect(); let mut dev = DEVICE_LIST.lock(); if dev.0 < device_list.epoch || device_list.epoch - dev.0 > u32::MAX >> 2 { @@ -337,7 +345,6 @@ fn other_handle( punch_reply.reply = true; punch_reply.virtual_ip = u32::from_be_bytes(current_device.virtual_ip.octets()); - punch_reply.step = punch.step; if let Err(_) = sender.try_send(punch) { return Ok(()); } diff --git a/switch/src/lib.rs b/switch/src/lib.rs index 895f63e..0485c88 100644 --- a/switch/src/lib.rs +++ b/switch/src/lib.rs @@ -1,8 +1,8 @@ -use std::borrow::Borrow; + use std::io; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket}; +use std::sync::atomic::{Ordering}; use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; use crossbeam::atomic::AtomicCell; use crossbeam::sync::WaitGroup; @@ -11,8 +11,11 @@ use tokio::sync::watch; use error::*; -use crate::handle::{ApplicationStatus, ConnectStatus, CurrentDeviceInfo, DEVICE_LIST, DIRECT_ROUTE_TABLE, PeerDeviceInfo, Route, RouteType, SERVER_RT}; use crate::handle::registration_handler::CONNECTION_STATUS; +use crate::handle::{ + ApplicationStatus, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, Route, RouteType, + DEVICE_LIST, DIRECT_ROUTE_TABLE, SERVER_RT, +}; pub mod error; pub mod handle; @@ -30,8 +33,15 @@ pub struct Config { } impl Config { - pub fn new(token: String, mac_address: String, name: Option, abnormal_call: F) -> Result where - F: FnOnce() + Send + 'static { + pub fn new( + token: String, + mac_address: String, + name: Option, + abnormal_call: F, + ) -> Result + where + F: FnOnce() + Send + 'static, + { if token.is_empty() || token.len() > 64 { return Err(Error::Stop("token invalid".to_string())); } @@ -42,7 +52,12 @@ impl Config { if name.is_empty() || name.len() > 64 { return Err(Error::Stop("name invalid".to_string())); } - Ok(Self { token, mac_address, name, abnormal_call }) + Ok(Self { + token, + mac_address, + name, + abnormal_call, + }) } else { let info = os_info::get(); let name = if info.version() != &os_info::Version::Unknown { @@ -50,7 +65,12 @@ impl Config { } else { format!("{}", info.os_type()) }; - Ok(Self { token, mac_address, name, abnormal_call }) + Ok(Self { + token, + mac_address, + name, + abnormal_call, + }) } } } @@ -63,8 +83,10 @@ pub struct Switch { } impl Switch { - pub fn start(config: Config) -> Result where - F: FnOnce() + Send + 'static { + pub fn start(config: Config) -> Result + where + F: FnOnce() + Send + 'static, + { let runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() @@ -81,6 +103,9 @@ impl Switch { Self::call_stop(self.status_sender); self.wait_group.wait(); } + pub fn stop_async(&self) { + Self::call_stop(self.status_sender.clone()); + } pub fn current_device(&self) -> &CurrentDeviceInfo { &self.current_device } @@ -115,14 +140,12 @@ impl Switch { let status = lock.send_replace(ApplicationStatus::Stopping); return status == ApplicationStatus::Starting; } - pub async fn start_(config: Config) -> Result where - F: FnOnce() + Send + 'static { + pub async fn start_(config: Config) -> Result + where + F: FnOnce() + Send + 'static, + { // let server_address = "nat1.wherewego.top:29876" - let server_address = "127.0.0.1:29876" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(); + let server_address = "127.0.0.1:29876".to_socket_addrs().unwrap().next().unwrap(); let mut port = 101 as u16; let udp = loop { match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(0), port))) { @@ -140,13 +163,24 @@ impl Switch { } }; //注册 - let response = - handle::registration_handler::registration(&udp, server_address, config.token, config.mac_address, config.name)?; + let response = handle::registration_handler::registration( + &udp, + server_address, + config.token, + config.mac_address, + config.name, + )?; { let ip_list = response .device_info_list .into_iter() - .map(|info| PeerDeviceInfo::new(Ipv4Addr::from(info.virtual_ip), info.name, info.device_status as u8)) + .map(|info| { + PeerDeviceInfo::new( + Ipv4Addr::from(info.virtual_ip), + info.name, + info.device_status as u8, + ) + }) .collect(); let mut dev = DEVICE_LIST.lock(); dev.0 = response.epoch; @@ -155,8 +189,7 @@ impl Switch { let virtual_ip = Ipv4Addr::from(response.virtual_ip); let virtual_gateway = Ipv4Addr::from(response.virtual_gateway); let virtual_netmask = Ipv4Addr::from(response.virtual_netmask); - let (status_sender, status_receiver) = - watch::channel(ApplicationStatus::Starting); + let (status_sender, status_receiver) = watch::channel(ApplicationStatus::Starting); let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address); let wait_group = WaitGroup::new(); @@ -168,15 +201,20 @@ impl Switch { let wait_group1 = wait_group.clone(); let status_sender1 = status_sender.clone(); let call1 = call.clone(); - handle::heartbeat_handler::start(status_receiver.clone(), udp, current_device, move || { - if Self::call_stop(status_sender1) { - if let Some(call) = call1.take() { - call(); + handle::heartbeat_handler::start( + status_receiver.clone(), + udp, + current_device, + move || { + if Self::call_stop(status_sender1) { + if let Some(call) = call1.take() { + call(); + } } - } - drop(wait_group1); - }) - .await; + drop(wait_group1); + }, + ) + .await; } //初始化nat数据 handle::init_nat_info(response.public_ip, response.public_port as u16); @@ -210,7 +248,7 @@ impl Switch { drop(wait_group1); }, ) - .await; + .await; let udp1 = udp.try_clone()?; let wait_group1 = wait_group.clone(); let status_sender1 = status_sender.clone(); @@ -230,7 +268,7 @@ impl Switch { drop(wait_group1); }, ) - .await; + .await; } //打洞处理 { @@ -252,7 +290,7 @@ impl Switch { drop(wait_group1); }, ) - .await; + .await; let udp1 = udp.try_clone()?; let wait_group1 = wait_group.clone(); let status_sender1 = status_sender.clone(); @@ -271,7 +309,7 @@ impl Switch { drop(wait_group1); }, ) - .await; + .await; let udp1 = udp.try_clone()?; let wait_group1 = wait_group.clone(); let status_sender1 = status_sender.clone(); @@ -290,7 +328,7 @@ impl Switch { drop(wait_group1); }, ) - .await; + .await; } //tun数据处理 { @@ -311,7 +349,7 @@ impl Switch { drop(wait_group1); }, ) - .await; + .await; } Ok(Switch { current_device, diff --git a/switch/src/proto/message.rs b/switch/src/proto/message.rs index 1f3a625..b335bb3 100644 --- a/switch/src/proto/message.rs +++ b/switch/src/proto/message.rs @@ -747,8 +747,6 @@ pub struct Punch { pub nat_type: ::protobuf::EnumOrUnknown, // @@protoc_insertion_point(field:Punch.reply) pub reply: bool, - // @@protoc_insertion_point(field:Punch.step) - pub step: ::protobuf::EnumOrUnknown, // special fields // @@protoc_insertion_point(special_field:Punch.special_fields) pub special_fields: ::protobuf::SpecialFields, @@ -766,7 +764,7 @@ impl Punch { } fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(7); + let mut fields = ::std::vec::Vec::with_capacity(6); let mut oneofs = ::std::vec::Vec::with_capacity(0); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( "virtual_ip", @@ -798,11 +796,6 @@ impl Punch { |m: &Punch| { &m.reply }, |m: &mut Punch| { &mut m.reply }, )); - fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( - "step", - |m: &Punch| { &m.step }, - |m: &mut Punch| { &mut m.step }, - )); ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( "Punch", fields, @@ -842,9 +835,6 @@ impl ::protobuf::Message for Punch { 48 => { self.reply = is.read_bool()?; }, - 56 => { - self.step = is.read_enum_or_unknown()?; - }, tag => { ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; }, @@ -873,9 +863,6 @@ impl ::protobuf::Message for Punch { if self.reply != false { my_size += 1 + 1; } - if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) { - my_size += ::protobuf::rt::int32_size(7, self.step.value()); - } my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); self.special_fields.cached_size().set(my_size as u32); my_size @@ -900,9 +887,6 @@ impl ::protobuf::Message for Punch { if self.reply != false { os.write_bool(6, self.reply)?; } - if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) { - os.write_enum(7, ::protobuf::EnumOrUnknown::value(&self.step))?; - } os.write_unknown_fields(self.special_fields.unknown_fields())?; ::std::result::Result::Ok(()) } @@ -926,7 +910,6 @@ impl ::protobuf::Message for Punch { self.public_port_range = 0; self.nat_type = ::protobuf::EnumOrUnknown::new(NatType::Symmetric); self.reply = false; - self.step = ::protobuf::EnumOrUnknown::new(Step::Step1); self.special_fields.clear(); } @@ -938,7 +921,6 @@ impl ::protobuf::Message for Punch { public_port_range: 0, nat_type: ::protobuf::EnumOrUnknown::from_i32(0), reply: false, - step: ::protobuf::EnumOrUnknown::from_i32(0), special_fields: ::protobuf::SpecialFields::new(), }; &instance @@ -1016,68 +998,6 @@ impl NatType { } } -#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)] -// @@protoc_insertion_point(enum:Step) -pub enum Step { - // @@protoc_insertion_point(enum_value:Step.Step1) - Step1 = 0, - // @@protoc_insertion_point(enum_value:Step.Step2) - Step2 = 1, - // @@protoc_insertion_point(enum_value:Step.Step3) - Step3 = 2, - // @@protoc_insertion_point(enum_value:Step.Step4) - Step4 = 3, -} - -impl ::protobuf::Enum for Step { - const NAME: &'static str = "Step"; - - fn value(&self) -> i32 { - *self as i32 - } - - fn from_i32(value: i32) -> ::std::option::Option { - match value { - 0 => ::std::option::Option::Some(Step::Step1), - 1 => ::std::option::Option::Some(Step::Step2), - 2 => ::std::option::Option::Some(Step::Step3), - 3 => ::std::option::Option::Some(Step::Step4), - _ => ::std::option::Option::None - } - } - - const VALUES: &'static [Step] = &[ - Step::Step1, - Step::Step2, - Step::Step3, - Step::Step4, - ]; -} - -impl ::protobuf::EnumFull for Step { - fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor { - static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new(); - descriptor.get(|| file_descriptor().enum_by_package_relative_name("Step").unwrap()).clone() - } - - fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor { - let index = *self as usize; - Self::enum_descriptor().value_by_index(index) - } -} - -impl ::std::default::Default for Step { - fn default() -> Self { - Step::Step1 - } -} - -impl Step { - fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData { - ::protobuf::reflect::GeneratedEnumDescriptorData::new::("Step") - } -} - static file_descriptor_proto_data: &'static [u8] = b"\ \n\rmessage.proto\"y\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\ \x20\x01(\tR\x05token\x12\x1f\n\x0bmac_address\x18\x02\x20\x01(\tR\nmacA\ @@ -1093,16 +1013,14 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x1d\n\nvirtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\x12#\n\rdevice_statu\ s\x18\x03\x20\x01(\rR\x0cdeviceStatus\"Y\n\nDeviceList\x12\x14\n\x05epoc\ h\x18\x01\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x02\x20\ - \x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xef\x01\n\x05Punch\x12\ + \x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xd4\x01\n\x05Punch\x12\ \x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvirtualIp\x12$\n\x0epublic_ip_\ list\x18\x02\x20\x03(\x07R\x0cpublicIpList\x12\x1f\n\x0bpublic_port\x18\ \x03\x20\x01(\rR\npublicPort\x12*\n\x11public_port_range\x18\x04\x20\x01\ (\rR\x0fpublicPortRange\x12#\n\x08nat_type\x18\x05\x20\x01(\x0e2\x08.Nat\ - TypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\x01(\x08R\x05reply\x12\ - \x19\n\x04step\x18\x07\x20\x01(\x0e2\x05.StepR\x04step*\"\n\x07NatType\ - \x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01*2\n\x04Step\x12\t\n\ - \x05Step1\x10\0\x12\t\n\x05Step2\x10\x01\x12\t\n\x05Step3\x10\x02\x12\t\ - \n\x05Step4\x10\x03b\x06proto3\ + TypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\x01(\x08R\x05reply*\"\n\ + \x07NatType\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01b\x06proto\ + 3\ "; /// `FileDescriptorProto` object which was a source for this generated file @@ -1126,9 +1044,8 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { messages.push(DeviceInfo::generated_message_descriptor_data()); messages.push(DeviceList::generated_message_descriptor_data()); messages.push(Punch::generated_message_descriptor_data()); - let mut enums = ::std::vec::Vec::with_capacity(2); + let mut enums = ::std::vec::Vec::with_capacity(1); enums.push(NatType::generated_enum_descriptor_data()); - enums.push(Step::generated_enum_descriptor_data()); ::protobuf::reflect::GeneratedFileDescriptor::new_generated( file_descriptor_proto(), deps, diff --git a/switch/src/tun_device/mac.rs b/switch/src/tun_device/mac.rs index 3d9f232..4c5b9a1 100644 --- a/switch/src/tun_device/mac.rs +++ b/switch/src/tun_device/mac.rs @@ -1,11 +1,6 @@ - - use std::net::Ipv4Addr; - use std::process::Command; - - use tun::Device; use crate::tun_device::{TunReader, TunWriter};