diff --git a/switch-desktop/Cargo.toml b/switch-desktop/Cargo.toml index 7853580..9d4adc5 100644 --- a/switch-desktop/Cargo.toml +++ b/switch-desktop/Cargo.toml @@ -23,8 +23,8 @@ crossbeam = "0.8.2" lazy_static = "1.4.0" parking_lot = "0.12.1" -#parity-tokio-ipc = "0.9.0" -#futures = "0.3" +fd-lock = "3.0.10" + os_info = "3.5.1" [target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies] sudo = "0.6.0" diff --git a/switch-desktop/src/command/client.rs b/switch-desktop/src/command/client.rs index d62431c..765588c 100644 --- a/switch-desktop/src/command/client.rs +++ b/switch-desktop/src/command/client.rs @@ -64,6 +64,7 @@ impl CommandClient { } } } + #[cfg(any(unix))] pub fn stop(&self) -> io::Result { self.udp.send(b"stop")?; let mut buf = [0; 10240]; diff --git a/switch-desktop/src/command/mod.rs b/switch-desktop/src/command/mod.rs index 78be5dc..ab99755 100644 --- a/switch-desktop/src/command/mod.rs +++ b/switch-desktop/src/command/mod.rs @@ -1,3 +1,59 @@ +use std::io; +use console::style; +use crate::console_out; + pub mod client; pub mod server; pub mod entity; + +pub enum CommandEnum { + Route, + List, + ListAll, + Status, + #[cfg(any(unix))] + Stop, +} + +pub fn command(cmd: CommandEnum) { + if let Err(e) = command_(cmd) { + println!("{}:{:?}", style("连接后台服务错误(Connection background service error)").red(), e); + } +} + +fn command_(cmd: CommandEnum) -> io::Result<()> { + match client::CommandClient::new() { + Ok(command_client) => { + match cmd { + CommandEnum::Route => { + let list = command_client.route()?; + console_out::console_route_table(list); + } + CommandEnum::List => { + let list = command_client.list()?; + console_out::console_device_list(list); + } + CommandEnum::ListAll => { + let list = command_client.list()?; + console_out::console_device_list_all(list); + } + CommandEnum::Status => { + let status = command_client.status()?; + console_out::console_status(status); + } + #[cfg(any(unix))] + CommandEnum::Stop => { + command_client.stop()?; + } + } + } + Err(e) => { + log::error!("{:?}",e); + println!( + "{}:{:?}", + style("连接后台服务错误(Connection background service error)").red(), e + ); + } + }; + Ok(()) +} diff --git a/switch-desktop/src/command/server.rs b/switch-desktop/src/command/server.rs index 036114f..3791585 100644 --- a/switch-desktop/src/command/server.rs +++ b/switch-desktop/src/command/server.rs @@ -2,7 +2,6 @@ use std::io; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; use std::sync::Arc; -use console::style; use switch::core::Switch; use crate::command::entity::{DeviceItem, RouteItem, Status}; diff --git a/switch-desktop/src/config/log_config.rs b/switch-desktop/src/config/log_config.rs index ca09594..579e966 100644 --- a/switch-desktop/src/config/log_config.rs +++ b/switch-desktop/src/config/log_config.rs @@ -1,33 +1,19 @@ use std::io; -use std::path::PathBuf; - -pub fn log_init_service(home: PathBuf) -> io::Result<()> { - if !home.exists() { - std::fs::create_dir(&home)?; - } - 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-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(()) +use crate::config::SWITCH_HOME_PATH; +#[cfg(target_os = "windows")] +pub fn log_service_init() -> io::Result<()> { + log_init_("switch-service.log") } - pub fn log_init() -> io::Result<()> { - let home = dirs::home_dir().unwrap().join(".switch"); + log_init_("switch.log") +} +pub fn log_init_(file_name:&str) -> io::Result<()> { + let home = SWITCH_HOME_PATH.lock().clone(); + let home = if let Some(home) = home { + home + } else { + return Err(io::Error::new(io::ErrorKind::Other, "not found")); + }; if !home.exists() { std::fs::create_dir(&home)?; } @@ -39,7 +25,7 @@ pub fn log_init() -> io::Result<()> { .encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new( "{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n", ))) - .build(home.join("switch.log"))?; + .build(home.join(file_name))?; match log4rs::Config::builder() .appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile))) .appender( diff --git a/switch-desktop/src/config/mod.rs b/switch-desktop/src/config/mod.rs index ed6b435..588ddda 100644 --- a/switch-desktop/src/config/mod.rs +++ b/switch-desktop/src/config/mod.rs @@ -1,4 +1,4 @@ -use std::fs::File; +use std::fs::{File, OpenOptions}; use std::io; use std::io::{Read, Write}; use std::net::{SocketAddr, ToSocketAddrs}; @@ -7,11 +7,12 @@ use std::path::PathBuf; use lazy_static::lazy_static; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; -use crate::{BaseArgs, StartArgs}; + +use crate::StartArgs; pub mod log_config; -pub struct BaseConfig { +pub struct StartConfig { pub name: String, pub token: String, pub server: SocketAddr, @@ -19,7 +20,7 @@ pub struct BaseConfig { pub device_id: String, } -pub fn default_config(start_args: StartArgs) -> Result { +pub fn default_config(start_args: StartArgs) -> Result { let args_config = read_config(); if args_config.is_none() && start_args.token.is_none() { return Err("找不到token(Token not found)".to_string()); @@ -33,10 +34,11 @@ pub fn default_config(start_args: StartArgs) -> Result { } let name = start_args.name.unwrap_or_else(|| { if let Some(c) = &args_config { - c.name.clone() - } else { - os_info::get().to_string() + if !c.name.is_empty() { + return c.name.clone(); + } } + os_info::get().to_string() }); let name = name.trim(); let name = if name.len() > 64 { @@ -65,7 +67,7 @@ pub fn default_config(start_args: StartArgs) -> Result { return c.server.clone(); } } - "nat1.wherewego.top:29875".to_string() + "nat1.wherewego.top:29871".to_string() }).to_socket_addrs() { Ok(mut server) => { if let Some(addr) = server.next() { @@ -90,7 +92,7 @@ pub fn default_config(start_args: StartArgs) -> Result { if nat_test_server.is_empty() { return Err("NAT检测服务地址错误(NAT detection service address error)".to_string()); } - let base_config = BaseConfig { + let base_config = StartConfig { name, token, server, @@ -102,7 +104,7 @@ pub fn default_config(start_args: StartArgs) -> Result { lazy_static! { static ref CONFIG: Mutex> = Mutex::new(None); - static ref SWITCH_HOME_PATH: Mutex> = Mutex::new(None); + pub static ref SWITCH_HOME_PATH: Mutex> = Mutex::new(None); } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -120,6 +122,8 @@ pub struct ArgsConfig { pub nat_test_server: Vec, #[serde(default = "default_str")] pub device_id: String, + #[serde(default = "default_pid")] + pub pid: u32, } fn default_version() -> String { @@ -134,6 +138,10 @@ fn default_resource_vec() -> Vec { vec![] } +fn default_pid() -> u32 { + 0 +} + impl ArgsConfig { pub fn new(token: String, name: String, server: String, nat_test_server: Vec, device_id: String) -> Self { Self { @@ -144,21 +152,49 @@ impl ArgsConfig { server, nat_test_server, device_id, + pid: 0, } } } +use fd_lock::RwLock; +pub fn lock_config() -> io::Result> { + let config_path = SWITCH_HOME_PATH.lock().clone().unwrap().join("config"); + Ok(RwLock::new(File::open(config_path)?)) +} pub fn save_config(config: ArgsConfig) -> io::Result<()> { - let config_path = dirs::home_dir().unwrap().join(".switch").join("config"); + let config_path = SWITCH_HOME_PATH.lock().clone().unwrap().join("config"); save_config_(config, config_path) } fn save_config_(config: ArgsConfig, config_path: PathBuf) -> io::Result<()> { + let mut config_lock = CONFIG.lock(); + config_lock.take(); let str = serde_yaml::to_string(&config).unwrap(); let mut file = File::create(config_path)?; file.write_all(str.as_bytes()) } +pub fn update_pid(pid: u32) -> 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.pid = pid; + return save_config_(config, config_path); + } + } + Err(io::Error::new(io::ErrorKind::Other, "not found")) +} + +#[cfg(any(unix))] +pub fn read_pid() -> io::Result { + let home = SWITCH_HOME_PATH.lock().clone().unwrap(); + let config = read_config_(home)?; + Ok(config.pid) +} + pub fn update_command_port(port: u16) -> io::Result<()> { let home_lock = SWITCH_HOME_PATH.lock(); if let Some(home) = home_lock.clone() { @@ -173,9 +209,13 @@ pub fn update_command_port(port: u16) -> io::Result<()> { } pub fn read_command_port() -> io::Result { - let home = dirs::home_dir().unwrap().join(".switch"); + let home = SWITCH_HOME_PATH.lock().clone().unwrap(); let config = read_config_(home)?; - Ok(config.command_port.unwrap()) + if let Some(p) = config.command_port { + Ok(p) + } else { + Err(io::Error::new(io::ErrorKind::Other, "not fount config")) + } } pub fn read_config() -> Option { @@ -206,7 +246,11 @@ pub fn set_home(home: PathBuf) { fn read_config_(home: PathBuf) -> io::Result { let config_path = home.join("config"); - let mut file = File::open(config_path)?; + let mut file = if config_path.exists() { + File::open(config_path)? + } else { + OpenOptions::new().read(true).write(true).truncate(false).create(true).open(config_path)? + }; let mut str = String::new(); file.read_to_string(&mut str)?; match serde_yaml::from_str::(&str) { diff --git a/switch-desktop/src/console_out/mod.rs b/switch-desktop/src/console_out/mod.rs index 0c5c7aa..514e0ce 100644 --- a/switch-desktop/src/console_out/mod.rs +++ b/switch-desktop/src/console_out/mod.rs @@ -1,8 +1,5 @@ -use std::net::Ipv4Addr; use console::style; -use switch::Route; - use crate::command::entity::{DeviceItem, RouteItem, Status}; pub mod table; diff --git a/switch-desktop/src/console_out/table.rs b/switch-desktop/src/console_out/table.rs index 7db54b8..a7d325e 100644 --- a/switch-desktop/src/console_out/table.rs +++ b/switch-desktop/src/console_out/table.rs @@ -1,8 +1,4 @@ -const NODE: &str = "+"; -const EDGE: &str = "-"; -const HIGH: &str = "|"; -const SPACE: &str = " "; -const EMPTY: &str = ""; +use console::style; pub fn println_table(table: Vec>) { if table.is_empty() { @@ -11,16 +7,23 @@ pub fn println_table(table: Vec>) { let mut width_list = vec![0; table[0].len()]; for in_list in table.iter() { for (index, item) in in_list.iter().enumerate() { - let width = console::measure_text_width(item)+6; + let width = console::measure_text_width(item) + 6; if width_list[index] < width { width_list[index] = width; } } } + let mut head = true; for in_list in table { for (index, item) in in_list.iter().enumerate() { - print!("{item:width$}", item = item, width = width_list[index]); + if head { + print!("{item:width$}", item = item, width = width_list[index]); + } else { + let str = format!("{item:width$}", item = item, width = width_list[index]); + print!("{}", style(str).green()); + } } + head = false; println!() } } \ No newline at end of file diff --git a/switch-desktop/src/main.rs b/switch-desktop/src/main.rs index 29582b1..00a17fe 100644 --- a/switch-desktop/src/main.rs +++ b/switch-desktop/src/main.rs @@ -1,19 +1,18 @@ -use std::io; -use std::net::{SocketAddr, ToSocketAddrs}; -use std::path::PathBuf; - use clap::{Parser, Subcommand}; use console::style; -use switch::core::{Config, Switch}; -use switch::handle::PeerDeviceStatus; -use crate::config::log_config::{log_init, log_init_service}; +use switch::core::Switch; + +use crate::config::log_config::log_init; +#[cfg(target_os = "windows")] +use crate::config::log_config::log_service_init; mod command; mod config; -#[cfg(windows)] +#[cfg(target_os = "windows")] mod windows; +#[cfg(any(unix))] mod unix; mod console_out; @@ -24,70 +23,6 @@ version, about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信" )] pub struct BaseArgs { - // /// 不超过64个字符 - // /// 相同token的设备之间才能通信。 - // /// 建议使用uuid保证唯一性。 - // /// No more than 64 characters - // /// Only devices with the same token can communicate with each other. - // /// It is recommended to use uuid to ensure uniqueness - // #[arg(long)] - // token: Option, - // /// 给设备一个名称,为空时默认用系统版本信息 - // /// Give the device a name. If it is blank, the system version information will be used by default - // #[arg(long)] - // name: Option, - // /// 设备唯一标识,为空时默认使用MAC地址,不超过64个字符 - // /// Unique identification of the device. If it is blank, the MAC address is used by default. No more than 64 characters - // #[arg(long)] - // device_id: Option, - // /// 注册和中继服务器地址 - // /// Register and relay server address - // #[arg(long)] - // server: Option, - // /// NAT检测服务地址,使用逗号分隔 - // /// NAT detection service address. Use comma to separate - // #[arg(long)] - // nat_test_server: Option, - // /// 开机自启动 - // /// Software automatically start up at boot. - // #[cfg(windows)] - // #[arg(long)] - // auto: bool, - // #[arg(long)] - // start: bool, - // - // // /// 启动,启动时可以附加参数 --token,如果没有token,则会读取配置文件中上一次使用的token - // // /// 安装服务后,会以服务的方式在后台启动,此时可以关闭命令行窗口 - // // /// When starting, you can attach the parameter -- token. If there is no token, the last token used in the configuration file will be read. After installing the service, it will be started in the background as a service. At this time, you can close the command line window - // // #[arg(subcommand)] - // // start111: Option, - // #[arg(long)] - // /// 停止,启动服务后,使用 --stop停止服务 - // /// Stop. After starting the service, use -- stop to stop the service - // stop: bool, - // /// 启动服务后,使用 --list 查看设备列表 - // /// After starting the service, use -- list to view the device list - // #[arg(long)] - // list: bool, - // /// 启动服务后,使用 --status 查看设备状态 - // /// After starting the service, use -- status to view the device status - // #[arg(long)] - // status: bool, - // /// 启动服务后,使用 --route 查看所有路由 - // /// After starting the service, use -- route to View all routes - // #[arg(long)] - // route: bool, - // - // /// 安装服务,安装后可以后台运行,需要指定安装路径 - // /// The installation service can run in the background after installation, and the installation path needs to be specified - // #[cfg(windows)] - // #[arg(long)] - // install: Option, - // /// 卸载服务 - // /// Uninstall service - // #[cfg(windows)] - // #[arg(long)] - // uninstall: bool, #[clap(subcommand)] command: Commands, @@ -101,14 +36,14 @@ enum Commands { Stop, /// 安装服务 /// Install service - #[cfg(windows)] + #[cfg(target_os = "windows")] Install(InstallArgs), /// 卸载服务 /// Uninstall service - #[cfg(windows)] + #[cfg(target_os = "windows")] Uninstall, /// 配置 - #[cfg(windows)] + #[cfg(target_os = "windows")] Config(ConfigArgs), /// 查看路由 /// View route @@ -151,8 +86,16 @@ pub struct StartArgs { /// NAT detection service address. Use comma to separate #[arg(long)] nat_test_server: Option, + /// 命令服务,开启后可以在其他进程使用 route、list等命令查看信息 + /// 程序使用后台运行时需要增加此参数 + /// Command service. After it is enabled, you can use route, list and other commands in other processes to view information. + /// This parameter needs to be added when the program is running in the background + #[cfg(any(unix))] + #[arg(long)] + command_server: bool, } +#[cfg(target_os = "windows")] #[derive(Parser, Debug)] pub struct InstallArgs { /// 安装路径 @@ -165,16 +108,13 @@ pub struct InstallArgs { auto: bool, } +#[cfg(target_os = "windows")] #[derive(Parser, Debug)] pub struct ConfigArgs { /// 服务开机自启动 /// Autostart on system startup #[arg(long)] auto: bool, - /// 取消服务开机自启动 - /// started manually - #[arg(long)] - not_auto: bool, } @@ -183,9 +123,9 @@ 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])); + config::set_home(std::path::PathBuf::from(&args[2])); + let _ = log_service_init(); + log::info!("config {:?}", std::path::PathBuf::from(&args[2])); log::info!("config {:?}", config::read_config()); windows::service::start(); return; @@ -200,34 +140,14 @@ fn main() { #[cfg(any(target_os = "linux", target_os = "macos"))] fn main() { + let home = dirs::home_dir().unwrap().join(".switch"); + config::set_home(home); let _ = log_init(); - let args = Args::parse(); - if sudo::RunningAs::Root != sudo::check() { - println!( - "{}", - style("需要使用root权限执行(Need to execute with root permission)...").red() - ); - sudo::escalate_if_needed().unwrap(); - } - println!("{}", style("starting...").green()); - start(args.token, args.name); + let args = BaseArgs::parse(); + unix::main0(args); } -pub fn start(token: String, name: String, server_address: SocketAddr, nat_test_server: Vec, device_id: String) { - let config = Config::new( - token, - device_id, - name, - server_address, - nat_test_server, - ); - let switch = match Switch::start(config) { - Ok(switch) => switch, - Err(e) => { - log::error!("{:?}", e); - return; - } - }; +pub fn console_listen(switch: &Switch) { use console::Term; let term = Term::stdout(); println!("{}", style("started").green()); @@ -247,6 +167,10 @@ pub fn start(token: String, name: String, server_address: SocketAddr, nat_test_s ); match term.read_line() { Ok(cmd) => { + if cmd.is_empty() { + log::warn!("非正常返回"); + return; + } if command(cmd.trim(), &switch).is_err() { println!("{}", style("stopping").red()); if let Err(e) = switch.stop() { @@ -256,17 +180,17 @@ pub fn start(token: String, name: String, server_address: SocketAddr, nat_test_s } } Err(e) => { - println!("read_line:{:?}", e); + log::error!("read_line:{:?}", e); println!("{}", style("stopping...").red()); if let Err(e) = switch.stop() { - println!("stop:{:?}", e); + log::error!("stop:{:?}", e); } + std::thread::sleep(std::time::Duration::from_secs(1)); break; } } } println!("{}", style("stopped").red()); - std::process::exit(1); } diff --git a/switch-desktop/src/unix/mod.rs b/switch-desktop/src/unix/mod.rs index e69de29..dd0880a 100644 --- a/switch-desktop/src/unix/mod.rs +++ b/switch-desktop/src/unix/mod.rs @@ -0,0 +1,139 @@ +use std::sync::Arc; + +use console::style; + +use switch::core::{Config, Switch}; + +use crate::{BaseArgs, Commands, config}; +use crate::command::{command, CommandEnum}; + + +pub fn main0(base_args: BaseArgs) { + match base_args.command { + Commands::Start(args) => { + let open_command_server = args.command_server; + match config::default_config(args) { + Ok(start_config) => { + if sudo::RunningAs::Root != sudo::check() { + println!( + "{}", + style("需要使用root权限执行(Need to execute with root permission)...").red() + ); + sudo::escalate_if_needed().unwrap(); + } + + let config = Config::new( + start_config.token.clone(), + start_config.device_id.clone(), + start_config.name.clone(), + start_config.server, + start_config.nat_test_server.clone(), + ); + let nat_test_server = start_config.nat_test_server.iter().map(|v| v.to_string()).collect::>(); + let args_config = config::ArgsConfig::new( + start_config.token.clone(), + start_config.name.clone(), + start_config.server.to_string(), + nat_test_server, + start_config.device_id.clone(), + ); + let mut lock = match config::lock_config() { + Ok(lock) => { + lock + } + Err(e) => { + log::error!("{:?}",e); + return; + } + }; + let lock_guard = match lock.try_write() { + Ok(lock) => { + lock + } + Err(_) => { + println!("{}", style("文件被重复打开").red()); + return; + } + }; + if let Err(e) = config::save_config(args_config) { + log::error!("{:?}",e); + return; + } + let switch = match Switch::start(config) { + Ok(switch) => { + switch + } + Err(e) => { + log::error!("{:?}", e); + return; + } + }; + let switch = Arc::new(switch); + let command_server = crate::command::server::CommandServer::new(); + if open_command_server { + if let Err(e) = config::update_pid(std::process::id()) { + log::error!("{:?}", e); + } + let switch1 = switch.clone(); + let handle = std::thread::spawn(move || { + if let Err(e) = command_server.start(switch1) { + log::error!("{:?}", e); + } + }); + crate::console_listen(&switch); + if let Err(e) = handle.join() { + log::error!("后台任务异常{:?}",e); + } else { + log::info!("后台任务结束"); + } + } else { + crate::console_listen(&switch); + log::info!("前台任务结束"); + } + drop(lock_guard) + } + Err(e) => { + log::error!("{:?}", e); + } + } + } + Commands::Stop => { + if sudo::RunningAs::Root != sudo::check() { + println!( + "{}", + style("需要使用root权限执行(Need to execute with root permission)...").red() + ); + sudo::escalate_if_needed().unwrap(); + } + command(CommandEnum::Stop); + if let Ok(pid) = config::read_pid() { + if pid != 0 { + let kill_cmd = format!("kill {}", pid); + let kill_out = std::process::Command::new("sh") + .arg("-c") + .arg(&kill_cmd) + .output() + .expect("sh exec error!"); + if !kill_out.status.success() { + println!("cmd:{:?},err:{:?}", kill_cmd, kill_out); + return; + } + } + } + println!("stopped") + } + Commands::Route => { + command(CommandEnum::Route); + } + Commands::List { all } => { + if all { + command(CommandEnum::ListAll); + } else { + command(CommandEnum::List); + } + } + Commands::Status => { + command(CommandEnum::Status); + } + } +} \ No newline at end of file diff --git a/switch-desktop/src/windows/mod.rs b/switch-desktop/src/windows/mod.rs index bd7381b..45c61a1 100644 --- a/switch-desktop/src/windows/mod.rs +++ b/switch-desktop/src/windows/mod.rs @@ -2,7 +2,6 @@ use std::ffi::OsString; use std::path::PathBuf; use std::time::Duration; use std::{io, thread}; -use std::net::ToSocketAddrs; use console::style; @@ -11,9 +10,10 @@ use windows_service::service::{ }; use windows_service::service_manager::{ServiceManager, ServiceManagerAccess}; use windows_service::Error; +use switch::core::{Config, Switch}; -use crate::{BaseArgs, Commands, config, console_out}; -use crate::config::BaseConfig; +use crate::{BaseArgs, Commands, config}; +use crate::command::{command, CommandEnum}; pub mod service; mod windows_admin_check; @@ -22,46 +22,6 @@ pub const SERVICE_FLAG: &'static str = "start_switch_service_v1_"; pub const SERVICE_NAME: &'static str = "switch-service-v1"; pub const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS; -fn command(cmd: &str) { - if let Err(e) = command_(cmd) { - println!("{}:{:?}", style("连接服务错误(Connection service error)").red(), e); - } -} - -fn command_(cmd: &str) -> io::Result<()> { - match crate::command::client::CommandClient::new() { - Ok(command_client) => { - match cmd { - "route" => { - let list = command_client.route()?; - console_out::console_route_table(list); - } - "list" => { - let list = command_client.list()?; - console_out::console_device_list(list); - } - "list-all" => { - let list = command_client.list()?; - console_out::console_device_list_all(list); - } - "status" => { - let status = command_client.status()?; - console_out::console_status(status); - } - _ => {} - } - } - Err(e) => { - log::error!("{:?}",e); - println!( - "{}:{:?}", - style("连接服务错误(Connection service error)").red(), e - ); - } - }; - Ok(()) -} - fn admin_check() -> bool { if !windows_admin_check::is_app_elevated() { println!( @@ -97,22 +57,24 @@ pub fn main0(base_args: BaseArgs) { return; } match config::default_config(args) { - Ok(base_config) => { + Ok(start_config) => { match service_state() { Ok(state) => { if state == ServiceState::Stopped { - config::save_config(config::ArgsConfig::new( - base_config.token.clone(), - base_config.name.clone(), - base_config.server.to_string(), - base_config.nat_test_server.iter().map(|v| v.to_string()).collect::>(), - base_config.device_id.clone(), - )) - .unwrap(); + if let Err(e) = config::save_config(config::ArgsConfig::new( + start_config.token.clone(), + start_config.name.clone(), + start_config.server.to_string(), + start_config.nat_test_server.iter().map(|v| v.to_string()).collect::>(), + start_config.device_id.clone(), + )) { + log::error!("{:?}",e); + return; + } match start() { Ok(_) => { //需要检查启动状态 - std::thread::sleep(std::time::Duration::from_secs(2)); + thread::sleep(Duration::from_secs(2)); println!("{}", style("启动成功(Start successfully)").green()) } Err(e) => { @@ -133,7 +95,38 @@ pub fn main0(base_args: BaseArgs) { "{}", style("服务未安装,在当前进程启动(The service is not installed and started in the current process)").red() ); - crate::start(base_config.token, base_config.name, base_config.server, base_config.nat_test_server, base_config.device_id); + let config = Config::new( + start_config.token, + start_config.device_id, + start_config.name, + start_config.server, + start_config.nat_test_server, + ); + let mut lock = match config::lock_config() { + Ok(lock) => lock, + Err(e) => { + log::error!("{:?}",e); + return; + } + }; + let lock_guard = match lock.try_write() { + Ok(lock) => { + lock + } + Err(_) => { + println!("{}", style("程序文件被重复打开").red()); + return; + } + }; + match Switch::start(config) { + Ok(switch) => { + crate::console_listen(&switch); + } + Err(e) => { + log::error!("{:?}", e); + } + } + drop(lock_guard); return; } } @@ -154,6 +147,9 @@ pub fn main0(base_args: BaseArgs) { if not_started() { return; } + if admin_check() { + return; + } match stop() { Ok(_) => { println!("{}", style("停止成功(Stopped successfully)").green()) @@ -165,6 +161,9 @@ pub fn main0(base_args: BaseArgs) { pause(); } Commands::Install(args) => { + if admin_check() { + return; + } let path: PathBuf = args.path.into(); if !path.exists() { std::fs::create_dir_all(&path).unwrap(); @@ -181,6 +180,9 @@ pub fn main0(base_args: BaseArgs) { pause(); } Commands::Uninstall => { + if admin_check() { + return; + } if let Err(e) = uninstall() { log::error!("{:?}", e); } else { @@ -188,28 +190,35 @@ pub fn main0(base_args: BaseArgs) { } pause(); } - Commands::Config(args) => {} + Commands::Config(args) => { + if let Err(e) = change(args.auto) { + log::error!("{:?}", e); + } else { + println!("{}", style("配置成功(Config succeeded)").green()) + } + pause(); + } Commands::Route => { if not_started() { return; } - command("route"); + command(CommandEnum::Route); } Commands::List { all } => { if not_started() { return; } if all { - command("list-all"); + command(CommandEnum::ListAll); } else { - command("list"); + command(CommandEnum::List); } } Commands::Status => { if not_started() { return; } - command("status"); + command(CommandEnum::Status); } } } @@ -265,6 +274,39 @@ fn install(path: PathBuf, auto: bool) -> Result<(), Error> { Ok(()) } +fn change(auto: bool) -> Result<(), Error> { + let manager_access = ServiceManagerAccess::CONNECT; + let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; + + let service_access = ServiceAccess::QUERY_CONFIG | ServiceAccess::CHANGE_CONFIG; + let service = service_manager.open_service(SERVICE_NAME, service_access)?; + let config = service.query_config()?; + let start_type = if auto { + ServiceStartType::AutoStart + } else { + ServiceStartType::OnDemand + }; + 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: config.display_name, + service_type: ServiceType::OWN_PROCESS, + start_type, + error_control: config.error_control, + executable_path: config.executable_path, + launch_arguments, + dependencies: config.dependencies, + account_name: None, // run as System + account_password: None, + }; + service.change_config(&service_info)?; + Ok(()) +} + fn uninstall() -> Result<(), Error> { let manager_access = ServiceManagerAccess::CONNECT; let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; @@ -278,7 +320,6 @@ fn uninstall() -> Result<(), Error> { // Wait for service to stop thread::sleep(Duration::from_secs(1)); } - service.delete()?; Ok(()) } diff --git a/switch-desktop/src/windows/service.rs b/switch-desktop/src/windows/service.rs index 52abad9..8331943 100644 --- a/switch-desktop/src/windows/service.rs +++ b/switch-desktop/src/windows/service.rs @@ -2,16 +2,20 @@ // extern crate windows_service; use std::ffi::OsString; +use std::net::ToSocketAddrs; use std::sync::Arc; use std::thread; use std::time::Duration; -use std::net::ToSocketAddrs; + +use windows_service::{define_windows_service, service_control_handler, service_dispatcher}; 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::core::{Config, Switch}; + +use crate::config; use crate::windows::config::read_config; define_windows_service!(ffi_service_main, switch_service_main); @@ -19,7 +23,7 @@ pub fn switch_service_main(_arguments: Vec) { thread::spawn(|| match service_main() { Ok(_) => {} Err(e) => { - log::warn!("{:?}", e); + log::error!("{:?}", e); } }); } @@ -58,10 +62,15 @@ fn service_main() -> windows_service::Result<()> { wait_hint: Duration::default(), process_id: None, })?; - if let Ok(switch) = start_switch() { - parker.park(); - if let Err(e) = switch.stop() { - log::warn!("switch stop:{:?}",e) + match start_switch() { + Ok(switch) => { + parker.park(); + if let Err(e) = switch.stop() { + log::warn!("switch stop:{:?}",e) + } + } + Err(e) => { + log::error!("{:?}",e); } } status_handle.set_service_status(ServiceStatus { @@ -79,7 +88,7 @@ fn start_switch() -> switch::Result> { if let Some(config) = read_config() { let device_id = config.device_id; if device_id.trim().is_empty() { - return Err(switch::error::Error::Stop("MAC address error".to_string())); + return Err(switch::error::Error::Stop("Device id error".to_string())); } let server_address = if let Some(server_address) = config.server .to_socket_addrs()? @@ -88,11 +97,10 @@ fn start_switch() -> switch::Result> { } else { return Err(switch::error::Error::Stop("server address error".to_string())); }; - let mut nat_test_server = config.nat_test_server.iter() + let nat_test_server = config.nat_test_server.iter() .flat_map(|a| a.to_socket_addrs()) .flatten() .collect::>(); - ; if nat_test_server.is_empty() { return Err(switch::error::Error::Stop("nat test server address error".to_string())); } @@ -108,8 +116,11 @@ fn start_switch() -> switch::Result> { let command_server = crate::command::server::CommandServer::new(); let switch1 = switch.clone(); thread::spawn(move || { + if let Err(e) = config::update_pid(std::process::id()) { + log::error!("{:?}", e); + } if let Err(e) = command_server.start(switch1) { - log::warn!("{:?}", e); + log::error!("{:?}", e); } }); Ok(switch) diff --git a/switch/Cargo.toml b/switch/Cargo.toml index 7c8f5e9..1d760ef 100644 --- a/switch/Cargo.toml +++ b/switch/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] packet = { path = "./packet" } -nat_traversal = { path = "./p2p_channel" } +p2p_channel = { path = "./p2p_channel" } bytes = "1.3.0" log = "0.4.17" libc = "0.2.137" @@ -26,7 +26,7 @@ chrono = "0.4.23" #lazy_static = "1.4.0" #moka = "0.9.6" protobuf = "3.2.0" -local-ip-address = "0.5.2" +local-ip-address = "0.4.9" #mio = {version = "0.8.6",features = ["os-poll", "net"]} #tokio = { version = "1.24.1", features = ["full"] } diff --git a/switch/p2p_channel b/switch/p2p_channel index 4a971a3..d75c050 160000 --- a/switch/p2p_channel +++ b/switch/p2p_channel @@ -1 +1 @@ -Subproject commit 4a971a34dd9890f6e7ec732015f2cf4790200dc9 +Subproject commit d75c05048298dfc35d0502d8944cba1c4859fe48 diff --git a/switch/rust-tun/Cargo.toml b/switch/rust-tun/Cargo.toml index f08cd94..7568382 100644 --- a/switch/rust-tun/Cargo.toml +++ b/switch/rust-tun/Cargo.toml @@ -15,31 +15,11 @@ libc = "0.2" thiserror = "1" [target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "android"))'.dependencies] -tokio = { version = "1", features = ["net", "macros"], optional = true } -tokio-util = { version = "0.6", features = ["codec"], optional = true } bytes = { version = "1", optional = true } byteorder = { version = "1", optional = true } -# This is only for the `ready` macro. -futures-core = { version = "0.3", optional = true } + [target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] ioctl = { version = "0.6", package = "ioctl-sys" } -[dev-dependencies] -packet = "0.1" -futures = "0.3" -[features] -async = ["tokio", "tokio-util", "bytes", "byteorder", "futures-core"] - -[[example]] -name = "read-async" -required-features = [ "async", "tokio/rt-multi-thread" ] - -[[example]] -name = "read-async-codec" -required-features = [ "async", "tokio/rt-multi-thread" ] - -[[example]] -name = "ping-tun" -required-features = [ "async", "tokio/rt-multi-thread" ] diff --git a/switch/rust-tun/README.md b/switch/rust-tun/README.md deleted file mode 100644 index ae24a9e..0000000 --- a/switch/rust-tun/README.md +++ /dev/null @@ -1,106 +0,0 @@ -TUN interfaces [![Crates.io](https://img.shields.io/crates/v/tun.svg)](https://crates.io/crates/tun) ![tun](https://docs.rs/tun/badge.svg) ![WTFPL](http://img.shields.io/badge/license-WTFPL-blue.svg) -============== -This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform. - -Usage ------ -First, add the following to your `Cargo.toml`: - -```toml -[dependencies] -tun = "0.5" -``` - -Next, add this to your crate root: - -```rust -extern crate tun; -``` - -If you want to use the TUN interface with mio/tokio, you need to enable the `async` feature: - -```toml -[dependencies] -tun = { version = "0.5", features = ["async"] } -``` - -Example -------- -The following example creates and configures a TUN interface and starts reading -packets from it. - -```rust -use std::io::Read; - -extern crate tun; - -fn main() { - let mut config = tun::Configuration::default(); - config.address((10, 0, 0, 1)) - .netmask((255, 255, 255, 0)) - .up(); - - #[cfg(target_os = "linux")] - config.platform(|config| { - config.packet_information(true); - }); - - let mut dev = tun::create(&config).unwrap(); - let mut buf = [0; 4096]; - - loop { - let amount = dev.read(&mut buf).unwrap(); - println!("{:?}", &buf[0 .. amount]); - } -} -``` - -Platforms -========= -Not every platform is supported. - -Linux ------ -You will need the `tun` module to be loaded and root is required to create -interfaces. - -macOS ------ -It just werks, but you have to set up routing manually. - -iOS ----- -You can pass the file descriptor of the TUN device to `rust-tun` to create the interface. - -Here is an example to create the TUN device on iOS and pass the `fd` to `rust-tun`: -```swift -// Swift -class PacketTunnelProvider: NEPacketTunnelProvider { - override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { - let tunnelNetworkSettings = createTunnelSettings() // Configure TUN address, DNS, mtu, routing... - setTunnelNetworkSettings(tunnelNetworkSettings) { [weak self] error in - let tunFd = self?.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32 - DispatchQueue.global(qos: .default).async { - start_tun(tunFd) - } - completionHandler(nil) - } - } -} -``` - -```rust -#[no_mangle] -pub extern "C" fn start_tun(fd: std::os::raw::c_int) { - let mut rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(async { - let mut cfg = tun::Configuration::default(); - cfg.raw_fd(fd); - let mut tun = tun::create_as_async(&cfg).unwrap(); - let mut framed = tun.into_framed(); - while let Some(packet) = framed.next().await { - ... - } - }); -} -``` diff --git a/switch/rust-tun/examples/ping-tun.rs b/switch/rust-tun/examples/ping-tun.rs deleted file mode 100644 index a7a7c41..0000000 --- a/switch/rust-tun/examples/ping-tun.rs +++ /dev/null @@ -1,78 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -use futures::{SinkExt, StreamExt}; -use packet::{builder::Builder, icmp, ip, Packet}; -use tun::{self, Configuration, TunPacket}; - -#[tokio::main] -async fn main() { - let mut config = Configuration::default(); - - config - .address((10, 0, 0, 1)) - .netmask((255, 255, 255, 0)) - .up(); - - #[cfg(target_os = "linux")] - config.platform(|config| { - config.packet_information(true); - }); - - let dev = tun::create_as_async(&config).unwrap(); - - let mut framed = dev.into_framed(); - - while let Some(packet) = framed.next().await { - match packet { - Ok(pkt) => match ip::Packet::new(pkt.get_bytes()) { - Ok(ip::Packet::V4(pkt)) => match icmp::Packet::new(pkt.payload()) { - Ok(icmp) => match icmp.echo() { - Ok(icmp) => { - let reply = ip::v4::Builder::default() - .id(0x42) - .unwrap() - .ttl(64) - .unwrap() - .source(pkt.destination()) - .unwrap() - .destination(pkt.source()) - .unwrap() - .icmp() - .unwrap() - .echo() - .unwrap() - .reply() - .unwrap() - .identifier(icmp.identifier()) - .unwrap() - .sequence(icmp.sequence()) - .unwrap() - .payload(icmp.payload()) - .unwrap() - .build() - .unwrap(); - framed.send(TunPacket::new(reply)).await.unwrap(); - } - _ => {} - }, - _ => {} - }, - Err(err) => println!("Received an invalid packet: {:?}", err), - _ => {} - }, - Err(err) => panic!("Error: {:?}", err), - } - } -} diff --git a/switch/rust-tun/examples/read-async-codec.rs b/switch/rust-tun/examples/read-async-codec.rs deleted file mode 100644 index 211ab50..0000000 --- a/switch/rust-tun/examples/read-async-codec.rs +++ /dev/null @@ -1,61 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -use bytes::BytesMut; -use futures::StreamExt; -use packet::{ip::Packet, Error}; -use tokio_util::codec::{Decoder, FramedRead}; - -pub struct IPPacketCodec; - -impl Decoder for IPPacketCodec { - type Item = Packet; - type Error = Error; - - fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { - if buf.is_empty() { - return Ok(None); - } - - let buf = buf.split_to(buf.len()); - Ok(match Packet::no_payload(buf) { - Ok(pkt) => Some(pkt), - Err(err) => { - println!("error {:?}", err); - None - } - }) - } -} - -#[tokio::main] -async fn main() { - let mut config = tun::Configuration::default(); - - config - .address((10, 0, 0, 1)) - .netmask((255, 255, 255, 0)) - .up(); - - let dev = tun::create_as_async(&config).unwrap(); - - let mut stream = FramedRead::new(dev, IPPacketCodec); - - while let Some(packet) = stream.next().await { - match packet { - Ok(pkt) => println!("pkt: {:#?}", pkt), - Err(err) => panic!("Error: {:?}", err), - } - } -} diff --git a/switch/rust-tun/examples/read-async.rs b/switch/rust-tun/examples/read-async.rs deleted file mode 100644 index 9fe9def..0000000 --- a/switch/rust-tun/examples/read-async.rs +++ /dev/null @@ -1,42 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -use futures::StreamExt; -use packet::ip::Packet; - -#[tokio::main] -async fn main() { - let mut config = tun::Configuration::default(); - - config - .address((10, 0, 0, 1)) - .netmask((255, 255, 255, 0)) - .up(); - - #[cfg(target_os = "linux")] - config.platform(|config| { - config.packet_information(true); - }); - - let dev = tun::create_as_async(&config).unwrap(); - - let mut stream = dev.into_framed(); - - while let Some(packet) = stream.next().await { - match packet { - Ok(pkt) => println!("pkt: {:#?}", Packet::unchecked(pkt.get_bytes())), - Err(err) => panic!("Error: {:?}", err), - } - } -} diff --git a/switch/rust-tun/examples/read.rs b/switch/rust-tun/examples/read.rs deleted file mode 100644 index 63ffd53..0000000 --- a/switch/rust-tun/examples/read.rs +++ /dev/null @@ -1,37 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -use std::io::Read; - -fn main() { - let mut config = tun::Configuration::default(); - - config - .address((10, 0, 0, 1)) - .netmask((255, 255, 255, 0)) - .up(); - - #[cfg(target_os = "linux")] - config.platform(|config| { - config.packet_information(true); - }); - - let mut dev = tun::create(&config).unwrap(); - let mut buf = [0; 4096]; - - loop { - let amount = dev.read(&mut buf).unwrap(); - println!("{:?}", &buf[0..amount]); - } -} diff --git a/switch/rust-tun/src/async/codec.rs b/switch/rust-tun/src/async/codec.rs deleted file mode 100644 index 04ead89..0000000 --- a/switch/rust-tun/src/async/codec.rs +++ /dev/null @@ -1,149 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -use std::io; - -use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt}; -use bytes::{BufMut, Bytes, BytesMut}; -use tokio_util::codec::{Decoder, Encoder}; - -/// A packet protocol IP version -#[derive(Debug)] -enum PacketProtocol { - IPv4, - IPv6, - Other(u8), -} - -// Note: the protocol in the packet information header is platform dependent. -impl PacketProtocol { - #[cfg(any(target_os = "linux", target_os = "android"))] - fn into_pi_field(&self) -> Result { - match self { - PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16), - PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16), - PacketProtocol::Other(_) => Err(io::Error::new( - io::ErrorKind::Other, - "neither an IPv4 or IPv6 packet", - )), - } - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - fn into_pi_field(&self) -> Result { - match self { - PacketProtocol::IPv4 => Ok(libc::PF_INET as u16), - PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16), - PacketProtocol::Other(_) => Err(io::Error::new( - io::ErrorKind::Other, - "neither an IPv4 or IPv6 packet", - )), - } - } -} - -/// A Tun Packet to be sent or received on the TUN interface. -#[derive(Debug)] -pub struct TunPacket(PacketProtocol, Bytes); - -/// Infer the protocol based on the first nibble in the packet buffer. -fn infer_proto(buf: &[u8]) -> PacketProtocol { - match buf[0] >> 4 { - 4 => PacketProtocol::IPv4, - 6 => PacketProtocol::IPv6, - p => PacketProtocol::Other(p), - } -} - -impl TunPacket { - /// Create a new `TunPacket` based on a byte slice. - pub fn new(bytes: Vec) -> TunPacket { - let proto = infer_proto(&bytes); - TunPacket(proto, Bytes::from(bytes)) - } - - /// Return this packet's bytes. - pub fn get_bytes(&self) -> &[u8] { - &self.1 - } - - pub fn into_bytes(self) -> Bytes { - self.1 - } -} - -/// A TunPacket Encoder/Decoder. -pub struct TunPacketCodec(bool, i32); - -impl TunPacketCodec { - /// Create a new `TunPacketCodec` specifying whether the underlying - /// tunnel Device has enabled the packet information header. - pub fn new(pi: bool, mtu: i32) -> TunPacketCodec { - TunPacketCodec(pi, mtu) - } -} - -impl Decoder for TunPacketCodec { - type Item = TunPacket; - type Error = io::Error; - - fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { - if buf.is_empty() { - return Ok(None); - } - - let mut pkt = buf.split_to(buf.len()); - - // reserve enough space for the next packet - if self.0 { - buf.reserve(self.1 as usize + 4); - } else { - buf.reserve(self.1 as usize); - } - - // if the packet information is enabled we have to ignore the first 4 bytes - if self.0 { - let _ = pkt.split_to(4); - } - - let proto = infer_proto(pkt.as_ref()); - Ok(Some(TunPacket(proto, pkt.freeze()))) - } -} - -impl Encoder for TunPacketCodec { - type Error = io::Error; - - fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> { - dst.reserve(item.get_bytes().len() + 4); - match item { - TunPacket(proto, bytes) if self.0 => { - // build the packet information header comprising of 2 u16 - // fields: flags and protocol. - let mut buf = Vec::::with_capacity(4); - - // flags is always 0 - buf.write_u16::(0).unwrap(); - // write the protocol as network byte order - buf.write_u16::(proto.into_pi_field()?) - .unwrap(); - - dst.put_slice(&buf); - dst.put(bytes); - } - TunPacket(_, bytes) => dst.put(bytes), - } - Ok(()) - } -} diff --git a/switch/rust-tun/src/async/device.rs b/switch/rust-tun/src/async/device.rs deleted file mode 100644 index 5ac89fd..0000000 --- a/switch/rust-tun/src/async/device.rs +++ /dev/null @@ -1,201 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -use std::io; -use std::io::{IoSlice, Read, Write}; - -use core::pin::Pin; -use core::task::{Context, Poll}; -use futures_core::ready; -use tokio::io::unix::AsyncFd; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; -use tokio_util::codec::Framed; - -use crate::device::Device as D; -use crate::platform::{Device, Queue}; -use crate::r#async::codec::*; - -/// An async TUN device wrapper around a TUN device. -pub struct AsyncDevice { - inner: AsyncFd, -} - -impl AsyncDevice { - /// Create a new `AsyncDevice` wrapping around a `Device`. - pub fn new(device: Device) -> io::Result { - device.set_nonblock()?; - Ok(AsyncDevice { - inner: AsyncFd::new(device)?, - }) - } - /// Returns a shared reference to the underlying Device object - pub fn get_ref(&self) -> &Device { - self.inner.get_ref() - } - - /// Returns a mutable reference to the underlying Device object - pub fn get_mut(&mut self) -> &mut Device { - self.inner.get_mut() - } - - /// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface) - pub fn into_framed(mut self) -> Framed { - let pi = self.get_mut().has_packet_information(); - let codec = TunPacketCodec::new(pi, self.inner.get_ref().mtu().unwrap_or(1504)); - Framed::new(self, codec) - } -} - -impl AsyncRead for AsyncDevice { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf, - ) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?; - let rbuf = buf.initialize_unfilled(); - match guard.try_io(|inner| inner.get_mut().read(rbuf)) { - Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))), - Err(_wb) => continue, - } - } - } -} - -impl AsyncWrite for AsyncDevice { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; - match guard.try_io(|inner| inner.get_mut().write(buf)) { - Ok(res) => return Poll::Ready(res), - Err(_wb) => continue, - } - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; - match guard.try_io(|inner| inner.get_mut().flush()) { - Ok(res) => return Poll::Ready(res), - Err(_wb) => continue, - } - } - } - - fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_write_vectored( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - bufs: &[IoSlice<'_>], - ) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; - match guard.try_io(|inner| inner.get_mut().write_vectored(bufs)) { - Ok(res) => return Poll::Ready(res), - Err(_wb) => continue, - } - } - } - - fn is_write_vectored(&self) -> bool { - true - } -} - -/// An async TUN device queue wrapper around a TUN device queue. -pub struct AsyncQueue { - inner: AsyncFd, -} - -impl AsyncQueue { - /// Create a new `AsyncQueue` wrapping around a `Queue`. - pub fn new(queue: Queue) -> io::Result { - queue.set_nonblock()?; - Ok(AsyncQueue { - inner: AsyncFd::new(queue)?, - }) - } - /// Returns a shared reference to the underlying Queue object - pub fn get_ref(&self) -> &Queue { - self.inner.get_ref() - } - - /// Returns a mutable reference to the underlying Queue object - pub fn get_mut(&mut self) -> &mut Queue { - self.inner.get_mut() - } - - /// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface) - pub fn into_framed(mut self) -> Framed { - let pi = self.get_mut().has_packet_information(); - let codec = TunPacketCodec::new(pi, 1504); - Framed::new(self, codec) - } -} - -impl AsyncRead for AsyncQueue { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut ReadBuf, - ) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?; - let rbuf = buf.initialize_unfilled(); - match guard.try_io(|inner| inner.get_mut().read(rbuf)) { - Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))), - Err(_wb) => continue, - } - } - } -} - -impl AsyncWrite for AsyncQueue { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; - match guard.try_io(|inner| inner.get_mut().write(buf)) { - Ok(res) => return Poll::Ready(res), - Err(_wb) => continue, - } - } - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?; - match guard.try_io(|inner| inner.get_mut().flush()) { - Ok(res) => return Poll::Ready(res), - Err(_wb) => continue, - } - } - } - - fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} diff --git a/switch/rust-tun/src/async/mod.rs b/switch/rust-tun/src/async/mod.rs deleted file mode 100644 index b9be373..0000000 --- a/switch/rust-tun/src/async/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -//! Async specific modules. - -use crate::error; - -use crate::configuration::Configuration; -use crate::platform::create; - -mod device; -pub use self::device::{AsyncDevice, AsyncQueue}; - -mod codec; -pub use self::codec::{TunPacket, TunPacketCodec}; - -/// Create a TUN device with the given name. -pub fn create_as_async(configuration: &Configuration) -> Result { - let device = create(&configuration)?; - AsyncDevice::new(device).map_err(|err| err.into()) -} diff --git a/switch/rust-tun/src/device.rs b/switch/rust-tun/src/device.rs index cab8432..5faaf56 100644 --- a/switch/rust-tun/src/device.rs +++ b/switch/rust-tun/src/device.rs @@ -12,15 +12,14 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::io::{Read, Write}; use std::net::Ipv4Addr; use crate::configuration::Configuration; use crate::error::*; /// A TUN device. -pub trait Device: Read + Write { - type Queue: Read + Write; +pub trait Device { + type Queue ; /// Reconfigure the device. fn configure(&mut self, config: &Configuration) -> Result<()> { @@ -91,5 +90,5 @@ pub trait Device: Read + Write { fn set_mtu(&mut self, value: i32) -> Result<()>; /// Get a device queue. - fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>; + fn queue(&self, index: usize) -> Option<&Self::Queue>; } diff --git a/switch/rust-tun/src/lib.rs b/switch/rust-tun/src/lib.rs index 3cb65c2..5989013 100644 --- a/switch/rust-tun/src/lib.rs +++ b/switch/rust-tun/src/lib.rs @@ -27,27 +27,6 @@ pub use crate::configuration::{Configuration, Layer}; pub mod platform; pub use crate::platform::create; -#[cfg(all( - feature = "async", - any( - target_os = "linux", - target_os = "macos", - target_os = "ios", - target_os = "android" - ) -))] -pub mod r#async; -#[cfg(all( - feature = "async", - any( - target_os = "linux", - target_os = "macos", - target_os = "ios", - target_os = "android" - ) -))] -pub use r#async::*; - pub fn configure() -> Configuration { Configuration::default() } diff --git a/switch/rust-tun/src/platform/android/device.rs b/switch/rust-tun/src/platform/android/device.rs deleted file mode 100644 index 5dd2c80..0000000 --- a/switch/rust-tun/src/platform/android/device.rs +++ /dev/null @@ -1,214 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. -#![allow(unused_variables)] - -use std::io::{self, Read, Write}; -use std::net::Ipv4Addr; -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; -use std::sync::Arc; - -use crate::configuration::Configuration; -use crate::device::Device as D; -use crate::error::*; -use crate::platform::posix::{self, Fd}; - -/// A TUN device for Android. -pub struct Device { - queue: Queue, -} - -impl Device { - /// Create a new `Device` for the given `Configuration`. - pub fn new(config: &Configuration) -> Result { - let fd = match config.raw_fd { - Some(raw_fd) => raw_fd, - _ => return Err(Error::InvalidConfig), - }; - let device = { - let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?; - - Device { - queue: Queue { tun: tun }, - } - }; - Ok(device) - } - - /// Split the interface into a `Reader` and `Writer`. - pub fn split(self) -> (posix::Reader, posix::Writer) { - let fd = Arc::new(self.queue.tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) - } - - /// Return whether the device has packet information - pub fn has_packet_information(&self) -> bool { - self.queue.has_packet_information() - } - - /// Set non-blocking mode - pub fn set_nonblock(&self) -> io::Result<()> { - self.queue.set_nonblock() - } -} - -impl Read for Device { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.queue.tun.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.queue.tun.read_vectored(bufs) - } -} - -impl Write for Device { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.queue.tun.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.queue.tun.flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.queue.tun.write_vectored(bufs) - } -} - -impl D for Device { - type Queue = Queue; - - fn name(&self) -> &str { - return ""; - } - - fn set_name(&mut self, value: &str) -> Result<()> { - Err(Error::NotImplemented) - } - - fn enabled(&mut self, value: bool) -> Result<()> { - Ok(()) - } - - fn address(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_address(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn destination(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn broadcast(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn netmask(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn mtu(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_mtu(&mut self, value: i32) -> Result<()> { - Ok(()) - } - - fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> { - if index > 0 { - return None; - } - - Some(&mut self.queue) - } -} - -impl AsRawFd for Device { - fn as_raw_fd(&self) -> RawFd { - self.queue.as_raw_fd() - } -} - -impl IntoRawFd for Device { - fn into_raw_fd(self) -> RawFd { - self.queue.into_raw_fd() - } -} - -pub struct Queue { - tun: Fd, -} - -impl Queue { - pub fn has_packet_information(&self) -> bool { - // on Android this is always the case - false - } - - pub fn set_nonblock(&self) -> io::Result<()> { - self.tun.set_nonblock() - } -} - -impl AsRawFd for Queue { - fn as_raw_fd(&self) -> RawFd { - self.tun.as_raw_fd() - } -} - -impl IntoRawFd for Queue { - fn into_raw_fd(self) -> RawFd { - self.tun.into_raw_fd() - } -} - -impl Read for Queue { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.tun.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.tun.read_vectored(bufs) - } -} - -impl Write for Queue { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.tun.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.tun.flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.tun.write_vectored(bufs) - } -} diff --git a/switch/rust-tun/src/platform/android/mod.rs b/switch/rust-tun/src/platform/android/mod.rs deleted file mode 100644 index 923e14f..0000000 --- a/switch/rust-tun/src/platform/android/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -//! Android specific functionality. - -mod device; -pub use self::device::{Device, Queue}; - -use crate::configuration::Configuration as C; -use crate::error::*; - -/// Android-only interface configuration. -#[derive(Copy, Clone, Default, Debug)] -pub struct Configuration {} - -/// Create a TUN device with the given name. -pub fn create(configuration: &C) -> Result { - Device::new(&configuration) -} diff --git a/switch/rust-tun/src/platform/ios/device.rs b/switch/rust-tun/src/platform/ios/device.rs deleted file mode 100644 index b079d42..0000000 --- a/switch/rust-tun/src/platform/ios/device.rs +++ /dev/null @@ -1,214 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. -#![allow(unused_variables)] - -use std::io::{self, Read, Write}; -use std::net::Ipv4Addr; -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; -use std::sync::Arc; - -use crate::configuration::Configuration; -use crate::device::Device as D; -use crate::error::*; -use crate::platform::posix::{self, Fd}; - -/// A TUN device for iOS. -pub struct Device { - queue: Queue, -} - -impl Device { - /// Create a new `Device` for the given `Configuration`. - pub fn new(config: &Configuration) -> Result { - let fd = match config.raw_fd { - Some(raw_fd) => raw_fd, - _ => return Err(Error::InvalidConfig), - }; - let mut device = unsafe { - let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?; - - Device { - queue: Queue { tun: tun }, - } - }; - Ok(device) - } - - /// Split the interface into a `Reader` and `Writer`. - pub fn split(self) -> (posix::Reader, posix::Writer) { - let fd = Arc::new(self.queue.tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) - } - - /// Return whether the device has packet information - pub fn has_packet_information(&self) -> bool { - self.queue.has_packet_information() - } - - /// Set non-blocking mode - pub fn set_nonblock(&self) -> io::Result<()> { - self.queue.set_nonblock() - } -} - -impl Read for Device { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.queue.tun.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.queue.tun.read_vectored(bufs) - } -} - -impl Write for Device { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.queue.tun.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.queue.tun.flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.queue.tun.write_vectored(bufs) - } -} - -impl D for Device { - type Queue = Queue; - - fn name(&self) -> &str { - return ""; - } - - fn set_name(&mut self, value: &str) -> Result<()> { - Err(Error::NotImplemented) - } - - fn enabled(&mut self, value: bool) -> Result<()> { - Ok(()) - } - - fn address(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_address(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn destination(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn broadcast(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn netmask(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> { - Ok(()) - } - - fn mtu(&self) -> Result { - Err(Error::NotImplemented) - } - - fn set_mtu(&mut self, value: i32) -> Result<()> { - Ok(()) - } - - fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> { - if index > 0 { - return None; - } - - Some(&mut self.queue) - } -} - -impl AsRawFd for Device { - fn as_raw_fd(&self) -> RawFd { - self.queue.as_raw_fd() - } -} - -impl IntoRawFd for Device { - fn into_raw_fd(self) -> RawFd { - self.queue.into_raw_fd() - } -} - -pub struct Queue { - tun: Fd, -} - -impl Queue { - pub fn has_packet_information(&self) -> bool { - // on ios this is always the case - true - } - - pub fn set_nonblock(&self) -> io::Result<()> { - self.tun.set_nonblock() - } -} - -impl AsRawFd for Queue { - fn as_raw_fd(&self) -> RawFd { - self.tun.as_raw_fd() - } -} - -impl IntoRawFd for Queue { - fn into_raw_fd(self) -> RawFd { - self.tun.into_raw_fd() - } -} - -impl Read for Queue { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.tun.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.tun.read_vectored(bufs) - } -} - -impl Write for Queue { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.tun.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.tun.flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.tun.write_vectored(bufs) - } -} diff --git a/switch/rust-tun/src/platform/ios/mod.rs b/switch/rust-tun/src/platform/ios/mod.rs deleted file mode 100644 index ea46855..0000000 --- a/switch/rust-tun/src/platform/ios/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 -// -// Copyleft (ↄ) meh. | http://meh.schizofreni.co -// -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. -// -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -// -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -//! iOS specific functionality. - -mod device; -pub use self::device::{Device, Queue}; - -use crate::configuration::Configuration as C; -use crate::error::*; - -/// iOS-only interface configuration. -#[derive(Copy, Clone, Default, Debug)] -pub struct Configuration {} - -/// Create a TUN device with the given name. -pub fn create(configuration: &C) -> Result { - Device::new(&configuration) -} diff --git a/switch/rust-tun/src/platform/linux/device.rs b/switch/rust-tun/src/platform/linux/device.rs index 1b078ae..8d0085d 100644 --- a/switch/rust-tun/src/platform/linux/device.rs +++ b/switch/rust-tun/src/platform/linux/device.rs @@ -13,10 +13,10 @@ // 0. You just DO WHAT THE FUCK YOU WANT TO. use std::ffi::{CStr, CString}; -use std::io::{self, Read, Write}; +use std::io; use std::mem; use std::net::Ipv4Addr; -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use std::os::unix::io::AsRawFd; use std::ptr; use std::sync::Arc; use std::vec::Vec; @@ -77,10 +77,10 @@ impl Device { req.ifru.flags = device_type | if config.platform.packet_information { - 0 - } else { - IFF_NO_PI - } + 0 + } else { + IFF_NO_PI + } | if queues_num > 1 { IFF_MULTI_QUEUE } else { 0 }; for _ in 0..queues_num { @@ -92,7 +92,7 @@ impl Device { } queues.push(Queue { - tun, + tun: Arc::new(tun), pi_enabled: config.platform.packet_information, }); } @@ -126,45 +126,40 @@ impl Device { req } - /// Make the device persistent. - pub fn persist(&mut self) -> Result<()> { - unsafe { - if tunsetpersist(self.as_raw_fd(), &1) < 0 { - Err(io::Error::last_os_error().into()) - } else { - Ok(()) - } - } - } + // /// Make the device persistent. + // pub fn persist(&mut self) -> Result<()> { + // unsafe { + // if tunsetpersist(self.as_raw_fd(), &1) < 0 { + // Err(io::Error::last_os_error().into()) + // } else { + // Ok(()) + // } + // } + // } - /// Set the owner of the device. - pub fn user(&mut self, value: i32) -> Result<()> { - unsafe { - if tunsetowner(self.as_raw_fd(), &value) < 0 { - Err(io::Error::last_os_error().into()) - } else { - Ok(()) - } - } - } - - /// Set the group of the device. - pub fn group(&mut self, value: i32) -> Result<()> { - unsafe { - if tunsetgroup(self.as_raw_fd(), &value) < 0 { - Err(io::Error::last_os_error().into()) - } else { - Ok(()) - } - } - } - pub fn split(mut self) -> (posix::Reader, posix::Writer) { - let queue = self.queues.swap_remove(0); - let fd = Arc::new(queue.tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) - } + // /// Set the owner of the device. + // pub fn user(&mut self, value: i32) -> Result<()> { + // unsafe { + // if tunsetowner(self.as_raw_fd(), &value) < 0 { + // Err(io::Error::last_os_error().into()) + // } else { + // Ok(()) + // } + // } + // } + // + // /// Set the group of the device. + // pub fn group(&mut self, value: i32) -> Result<()> { + // unsafe { + // if tunsetgroup(self.as_raw_fd(), &value) < 0 { + // Err(io::Error::last_os_error().into()) + // } else { + // Ok(()) + // } + // } + // } /// Return whether the device has packet information - pub fn has_packet_information(&mut self) -> bool { + pub fn has_packet_information(&self) -> bool { self.queues[0].has_packet_information() } @@ -174,30 +169,6 @@ impl Device { } } -impl Read for Device { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.queues[0].read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.queues[0].read_vectored(bufs) - } -} - -impl Write for Device { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.queues[0].write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.queues[0].flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.queues[0].write_vectored(bufs) - } -} - impl D for Device { type Queue = Queue; @@ -377,73 +348,29 @@ impl D for Device { } } - fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> { - self.queues.get_mut(index) - } -} - -impl AsRawFd for Device { - fn as_raw_fd(&self) -> RawFd { - self.queues[0].as_raw_fd() - } -} - -impl IntoRawFd for Device { - fn into_raw_fd(mut self) -> RawFd { - // It is Ok to swap the first queue with the last one, because the self will be dropped afterwards - let queue = self.queues.swap_remove(0); - queue.into_raw_fd() + fn queue(&self, index: usize) -> Option<&Self::Queue> { + self.queues.get(index) } } pub struct Queue { - tun: Fd, + tun: Arc, pi_enabled: bool, } impl Queue { - pub fn has_packet_information(&mut self) -> bool { + pub fn has_packet_information(&self) -> bool { self.pi_enabled } pub fn set_nonblock(&self) -> io::Result<()> { self.tun.set_nonblock() } -} - -impl Read for Queue { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.tun.read(buf) + pub fn reader(&self) -> posix::Reader { + posix::Reader(self.tun.clone()) } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.tun.read_vectored(bufs) - } -} - -impl Write for Queue { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.tun.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.tun.flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.tun.write_vectored(bufs) - } -} - -impl AsRawFd for Queue { - fn as_raw_fd(&self) -> RawFd { - self.tun.as_raw_fd() - } -} - -impl IntoRawFd for Queue { - fn into_raw_fd(self) -> RawFd { - self.tun.into_raw_fd() + pub fn writer(&self) -> posix::Writer { + posix::Writer(self.tun.clone()) } } diff --git a/switch/rust-tun/src/platform/macos/device.rs b/switch/rust-tun/src/platform/macos/device.rs index 879e1ad..9b3bf62 100644 --- a/switch/rust-tun/src/platform/macos/device.rs +++ b/switch/rust-tun/src/platform/macos/device.rs @@ -14,15 +14,15 @@ #![allow(unused_variables)] use std::ffi::CStr; -use std::io::{self, Read, Write}; +use std::io; use std::mem; use std::net::Ipv4Addr; -use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use std::os::unix::io::AsRawFd; use std::ptr; use std::sync::Arc; use libc; -use libc::{c_char, c_uint, c_void, sockaddr, socklen_t, AF_INET, SOCK_DGRAM}; +use libc::{AF_INET, c_char, c_uint, c_void, SOCK_DGRAM, sockaddr, socklen_t}; use crate::configuration::{Configuration, Layer}; use crate::device::Device as D; @@ -121,7 +121,7 @@ impl Device { name: CStr::from_ptr(name.as_ptr() as *const c_char) .to_string_lossy() .into(), - queue: Queue { tun: tun }, + queue: Queue { tun: Arc::new(tun) }, ctl: ctl, } }; @@ -165,11 +165,11 @@ impl Device { } } - /// Split the interface into a `Reader` and `Writer`. - pub fn split(self) -> (posix::Reader, posix::Writer) { - let fd = Arc::new(self.queue.tun); - (posix::Reader(fd.clone()), posix::Writer(fd.clone())) - } + // /// Split the interface into a `Reader` and `Writer`. + // pub fn split(self) -> (posix::Reader, posix::Writer) { + // let fd = Arc::new(self.queue.tun); + // (posix::Reader(fd.clone()), posix::Writer(fd.clone())) + // } /// Return whether the device has packet information pub fn has_packet_information(&self) -> bool { @@ -182,29 +182,29 @@ impl Device { } } -impl Read for Device { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.queue.tun.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.queue.tun.read_vectored(bufs) - } -} - -impl Write for Device { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.queue.tun.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.queue.tun.flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.queue.tun.write_vectored(bufs) - } -} +// impl Read for Device { +// fn read(&mut self, buf: &mut [u8]) -> io::Result { +// self.queue.tun.read(buf) +// } +// +// fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { +// self.queue.tun.read_vectored(bufs) +// } +// } +// +// impl Write for Device { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// self.queue.tun.write(buf) +// } +// +// fn flush(&mut self) -> io::Result<()> { +// self.queue.tun.flush() +// } +// +// fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { +// self.queue.tun.write_vectored(bufs) +// } +// } impl D for Device { type Queue = Queue; @@ -365,29 +365,29 @@ impl D for Device { } } - fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> { + fn queue(&self, index: usize) -> Option<&Self::Queue> { if index > 0 { return None; } - Some(&mut self.queue) + Some(&self.queue) } } -impl AsRawFd for Device { - fn as_raw_fd(&self) -> RawFd { - self.queue.as_raw_fd() - } -} - -impl IntoRawFd for Device { - fn into_raw_fd(self) -> RawFd { - self.queue.into_raw_fd() - } -} +// impl AsRawFd for Device { +// fn as_raw_fd(&self) -> RawFd { +// self.queue.as_raw_fd() +// } +// } +// +// impl IntoRawFd for Device { +// fn into_raw_fd(self) -> RawFd { +// self.queue.into_raw_fd() +// } +// } pub struct Queue { - tun: Fd, + tun: Arc, } impl Queue { @@ -399,40 +399,47 @@ impl Queue { pub fn set_nonblock(&self) -> io::Result<()> { self.tun.set_nonblock() } -} -impl AsRawFd for Queue { - fn as_raw_fd(&self) -> RawFd { - self.tun.as_raw_fd() + pub fn reader(&self) -> posix::Reader { + posix::Reader(self.tun.clone()) + } + pub fn writer(&self) -> posix::Writer { + posix::Writer(self.tun.clone()) } } -impl IntoRawFd for Queue { - fn into_raw_fd(self) -> RawFd { - self.tun.into_raw_fd() - } -} +// impl AsRawFd for Queue { +// fn as_raw_fd(&self) -> RawFd { +// self.tun.as_raw_fd() +// } +// } +// +// impl IntoRawFd for Queue { +// fn into_raw_fd(self) -> RawFd { +// self.tun.into_raw_fd() +// } +// } -impl Read for Queue { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.tun.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { - self.tun.read_vectored(bufs) - } -} - -impl Write for Queue { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.tun.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.tun.flush() - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { - self.tun.write_vectored(bufs) - } -} +// impl Read for Queue { +// fn read(&mut self, buf: &mut [u8]) -> io::Result { +// self.tun.read(buf) +// } +// +// fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { +// self.tun.read_vectored(bufs) +// } +// } +// +// impl Write for Queue { +// fn write(&mut self, buf: &[u8]) -> io::Result { +// self.tun.write(buf) +// } +// +// fn flush(&mut self) -> io::Result<()> { +// self.tun.flush() +// } +// +// fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { +// self.tun.write_vectored(bufs) +// } +// } diff --git a/switch/rust-tun/src/platform/posix/split.rs b/switch/rust-tun/src/platform/posix/split.rs index 7364102..d09ed68 100644 --- a/switch/rust-tun/src/platform/posix/split.rs +++ b/switch/rust-tun/src/platform/posix/split.rs @@ -12,22 +12,24 @@ // // 0. You just DO WHAT THE FUCK YOU WANT TO. -use std::io::{self, Read, Write}; +use std::io; use std::mem; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd,RawFd}; use std::sync::Arc; use crate::platform::posix::Fd; use libc; /// Read-only end for a file descriptor. +#[derive(Clone)] pub struct Reader(pub(crate) Arc); /// Write-only end for a file descriptor. +#[derive(Clone)] pub struct Writer(pub(crate) Arc); -impl Read for Reader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { +impl Reader { + pub fn read(&self, buf: &mut [u8]) -> io::Result { unsafe { let amount = libc::read(self.0.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len()); @@ -39,7 +41,7 @@ impl Read for Reader { } } - fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + pub fn read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { unsafe { let mut msg: libc::msghdr = mem::zeroed(); // msg.msg_name: NULL @@ -57,8 +59,8 @@ impl Read for Reader { } } -impl Write for Writer { - fn write(&mut self, buf: &[u8]) -> io::Result { +impl Writer { + pub fn write(&self, buf: &[u8]) -> io::Result { unsafe { let amount = libc::write(self.0.as_raw_fd(), buf.as_ptr() as *const _, buf.len()); @@ -70,11 +72,8 @@ impl Write for Writer { } } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + pub fn write_vectored(&self, bufs: &[io::IoSlice<'_>]) -> io::Result { unsafe { let mut msg: libc::msghdr = mem::zeroed(); // msg.msg_name = NULL @@ -90,6 +89,22 @@ impl Write for Writer { Ok(n as usize) } } + pub fn write_all(&self, mut buf: &[u8]) -> io::Result<()> { + while !buf.is_empty() { + match self.write(buf) { + Ok(0) => { + return Err(io::Error::new( + io::ErrorKind::WriteZero, + "failed to write whole buffer", + )); + } + Ok(n) => buf = &buf[n..], + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } } impl AsRawFd for Reader { @@ -97,9 +112,9 @@ impl AsRawFd for Reader { self.0.as_raw_fd() } } - -impl AsRawFd for Writer { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} +// +// impl AsRawFd for Writer { +// fn as_raw_fd(&self) -> RawFd { +// self.0.as_raw_fd() +// } +// } diff --git a/switch/src/core/mod.rs b/switch/src/core/mod.rs index b80128e..322d212 100644 --- a/switch/src/core/mod.rs +++ b/switch/src/core/mod.rs @@ -4,9 +4,9 @@ use std::sync::Arc; use crossbeam::atomic::AtomicCell; use crossbeam_skiplist::SkipMap; use parking_lot::Mutex; -use nat_traversal::boot::Boot; -use nat_traversal::channel::{Channel, Route, RouteKey}; -use nat_traversal::punch::NatInfo; +use p2p_channel::boot::Boot; +use p2p_channel::channel::{Channel, Route, RouteKey}; +use p2p_channel::punch::NatInfo; use crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tun_handler}; use crate::nat::NatTest; use crate::tun_device; @@ -28,7 +28,7 @@ pub struct Switch { impl Switch { pub fn start(config: Config) -> crate::Result { - let (mut channel, punch, idle) = Boot::new::(100, 9000, 0)?; + let (mut channel, punch, idle) = Boot::new::(80, 15000, 0)?; let response = registration_handler::registration(&mut channel, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone())?; let register = Arc::new(registration_handler::Register::new(channel.sender()?, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone())); let device_list: Arc)>> = Arc::new(Mutex::new((0, Vec::new()))); @@ -109,7 +109,7 @@ impl Switch { self.nat_channel.route_to_id(route_key) } pub fn route_table(&self) -> Vec<(Ipv4Addr, Route)> { - self.nat_channel.route_list() + self.nat_channel.route_table() } pub fn stop(&self) -> io::Result<()> { self.tun_reader.close(); diff --git a/switch/src/handle/heartbeat_handler.rs b/switch/src/handle/heartbeat_handler.rs index ed49c7a..7f91fcc 100644 --- a/switch/src/handle/heartbeat_handler.rs +++ b/switch/src/handle/heartbeat_handler.rs @@ -7,10 +7,10 @@ use chrono::Local; use crossbeam::atomic::AtomicCell; use parking_lot::Mutex; use rand::prelude::SliceRandom; -use nat_traversal::channel::Route; -use nat_traversal::channel::sender::Sender; -use nat_traversal::idle::Idle; +use p2p_channel::channel::Route; +use p2p_channel::channel::sender::Sender; +use p2p_channel::idle::Idle; use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, Version}; @@ -26,9 +26,11 @@ pub fn start_idle(idle: Idle, sender: Sender) { fn start_idle_(idle: Idle, sender: Sender) -> io::Result<()> { loop { - let (idle_status, peer_ip, route) = idle.next_idle()?; - log::warn!("peer_ip:{:?},route:{:?},idle_status:{:?}",peer_ip,route,idle_status); - sender.remove_route(&peer_ip); + let (idle_status, peer_ips, route) = idle.next_idle()?; + log::warn!("peer_ip:{:?},route:{:?},idle_status:{:?}",peer_ips,route,idle_status); + for peer_ip in peer_ips { + sender.remove_route(&peer_ip); + } } } @@ -68,7 +70,7 @@ fn start_heartbeat_(sender: Sender, device_list: Arc, device_list: Arc u16::MAX >> 2 { + if dev.0 != device_list_t.epoch as u16 { dev.0 = device_list_t.epoch as u16; dev.1 = ip_list; } @@ -357,7 +357,7 @@ impl RecvHandler { net_packet.set_source(current_device.virtual_ip()); net_packet.set_destination(source); net_packet.set_payload(&bytes); - if !peer_nat_info.local_ip.is_unspecified() { + if !peer_nat_info.local_ip.is_unspecified() && peer_nat_info.local_port != 0 { let mut packet = NetPacket::new([0u8; 12])?; packet.set_version(Version::V1); packet.first_set_ttl(1); diff --git a/switch/src/handle/registration_handler.rs b/switch/src/handle/registration_handler.rs index 50b43fa..e6ed5d2 100644 --- a/switch/src/handle/registration_handler.rs +++ b/switch/src/handle/registration_handler.rs @@ -5,8 +5,8 @@ use std::time::Duration; use chrono::Local; use protobuf::Message; -use nat_traversal::channel::Channel; -use nat_traversal::channel::sender::Sender; +use p2p_channel::channel::Channel; +use p2p_channel::channel::sender::Sender; use crate::error::*; use crate::proto::message::{RegistrationRequest, RegistrationResponse}; diff --git a/switch/src/handle/tun_handler.rs b/switch/src/handle/tun_handler.rs index e0d3af4..ca2ae07 100644 --- a/switch/src/handle/tun_handler.rs +++ b/switch/src/handle/tun_handler.rs @@ -4,7 +4,7 @@ use std::net::Ipv4Addr; use std::sync::Arc; use crossbeam::atomic::AtomicCell; -use nat_traversal::channel::sender::Sender; +use p2p_channel::channel::sender::Sender; use packet::icmp::icmp::IcmpPacket; use packet::icmp::Kind; use packet::ip::ipv4; @@ -59,8 +59,8 @@ fn handle(sender: &Sender, data: &mut [u8], tun_writer: &TunWriter, cu net_packet.set_destination(dest_ip); net_packet.set_payload(ipv4_packet.buffer); //优先发到直连到地址 - if sender.send_to_id(&net_packet.buffer()[..(4 + 8 + data_len)], &dest_ip).is_err() { - sender.send_to_addr(&net_packet.buffer()[..(4 + 8 + data_len)], current_device.connect_server)?; + if sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip).is_err() { + sender.send_to_addr(&net_packet.buffer()[..(12 + data_len)], current_device.connect_server)?; } return Ok(()); } @@ -76,6 +76,7 @@ pub fn start(sender: Sender, }); } +#[cfg(target_os = "windows")] fn start_(sender: Sender, tun_reader: TunReader, tun_writer: TunWriter, @@ -94,4 +95,26 @@ fn start_(sender: Sender, } } } +} + +#[cfg(any(target_os = "linux",target_os = "macos"))] +fn start_(sender: Sender, + tun_reader: TunReader, + tun_writer: TunWriter, + current_device: Arc>, ) -> io::Result<()> { + let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?; + net_packet.set_version(Version::V1); + net_packet.set_protocol(Protocol::Ipv4Turn); + net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into()); + net_packet.set_ttl(MAX_TTL); + let mut buf = [0; 4096]; + loop { + let data = tun_reader.read(&mut buf)?; + match handle(&sender, data, &tun_writer, current_device.load(), &mut net_packet) { + Ok(_) => {} + Err(e) => { + log::warn!("{:?}", e) + } + } + } } \ No newline at end of file diff --git a/switch/src/lib.rs b/switch/src/lib.rs index d01196f..faa979c 100644 --- a/switch/src/lib.rs +++ b/switch/src/lib.rs @@ -1,25 +1,7 @@ use crate::error::Error; -// use std::io; -// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; -// use std::sync::atomic::Ordering; -// use std::sync::Arc; -// use std::time::Duration; -// -// use crossbeam::atomic::AtomicCell; -// use crossbeam::sync::WaitGroup; -// use parking_lot::Mutex; -// use tokio::sync::watch; -// -// use error::*; -// -// use crate::handle::registration_handler::CONNECTION_STATUS; -// use crate::handle::{ -// ApplicationStatus, ConnectStatus, CurrentDeviceInfo, NatInfo, PeerDeviceInfo, Route, RouteType, -// DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, SERVER_RT, -// }; -// use crate::nat::channel::NatChannel; -pub use nat_traversal::channel::{Route, RouteKey}; + +pub use p2p_channel::channel::{Route, RouteKey}; pub type Result = std::result::Result; @@ -30,339 +12,3 @@ pub mod proto; pub mod protocol; pub mod tun_device; pub mod core; - -// -// #[derive(Clone, Debug)] -// pub struct Config { -// pub token: String, -// pub mac_address: String, -// pub name: String, -// pub server_address: SocketAddr, -// pub nat_test_server: Vec, -// pub abnormal_call: F, -// } -// -// impl Config { -// pub fn new( -// token: String, -// mac_address: String, -// name: Option, -// server_address: SocketAddr, -// nat_test_server: Vec, -// abnormal_call: F, -// ) -> Result -// where -// F: FnOnce() + Send + 'static, -// { -// if token.is_empty() || token.len() > 64 { -// return Err(Error::Stop("token invalid".to_string())); -// } -// if mac_address.len() != 12 + 5 { -// return Err(Error::Stop("mac_address invalid".to_string())); -// } -// if let Some(name) = name { -// if name.is_empty() || name.len() > 64 { -// return Err(Error::Stop("name invalid".to_string())); -// } -// Ok(Self { -// token, -// mac_address, -// name, -// server_address, -// nat_test_server, -// abnormal_call, -// }) -// } else { -// let info = os_info::get(); -// let name = if info.version() != &os_info::Version::Unknown { -// format!("{} {}", info.os_type(), info.version()) -// } else { -// format!("{}", info.os_type()) -// }; -// Ok(Self { -// token, -// mac_address, -// name, -// server_address, -// nat_test_server, -// abnormal_call, -// }) -// } -// } -// } -// -// pub struct Switch { -// current_device: CurrentDeviceInfo, -// status_sender: Arc>>, -// wait_group: WaitGroup, -// runtime: Option, -// } -// -// impl Switch { -// pub fn start(config: Config) -> Result -// where -// F: FnOnce() + Send + 'static, -// { -// let runtime = tokio::runtime::Builder::new_multi_thread() -// .enable_all() -// .build() -// .unwrap(); -// todo!() -// // return match runtime.block_on(Switch::start_(config)) { -// // Ok(mut switch) => { -// // switch.runtime = Some(runtime); -// // Ok(switch) -// // } -// // Err(e) => Err(e), -// // }; -// } -// pub fn stop(self) { -// 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 -// } -// pub fn nat_info(&self) -> Option { -// NAT_INFO.lock().clone() -// } -// pub fn server_rt(&self) -> i64 { -// SERVER_RT.load(Ordering::Relaxed) -// } -// pub fn connection_status(&self) -> ConnectStatus { -// CONNECTION_STATUS.load() -// } -// pub fn device_list(&self) -> Vec { -// let device_list_lock = DEVICE_LIST.lock(); -// let (_epoch, device_list) = device_list_lock.clone(); -// drop(device_list_lock); -// device_list -// } -// pub fn route(&self, ip: &Ipv4Addr) -> Route { -// if let Some(route_ref) = DIRECT_ROUTE_TABLE.get(ip) { -// route_ref.value().clone() -// } else { -// let mut route = Route::new(self.current_device.connect_server); -// route.route_type = RouteType::ServerRelay; -// route.rt = self.server_rt() * 2; -// route.recv_time = -1; -// route -// } -// } -// } -// -// impl Switch { -// fn call_stop(status_sender: Arc>>) -> bool { -// let lock = status_sender.lock(); -// let status = lock.send_replace(ApplicationStatus::Stopping); -// return status == ApplicationStatus::Starting; -// } -// // pub async fn start_(config: Config) -> Result -// // where -// // F: FnOnce() + Send + 'static, -// // { -// // // let server_address = "nat1.wherewego.top:29876" -// // // let server_address = "nat1.wherewego.top:29875".to_socket_addrs().unwrap().next().unwrap(); -// // let server_address = config.server_address; -// // let nat_channel = NatChannel::new(server_address,100,).await?; -// // //注册 -// // 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, -// // ) -// // }) -// // .collect(); -// // let mut dev = DEVICE_LIST.lock(); -// // dev.0 = response.epoch; -// // dev.1 = ip_list; -// // } -// // 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 current_device = -// // CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address); -// // let wait_group = WaitGroup::new(); -// // let status_sender = Arc::new(parking_lot::const_mutex(status_sender)); -// // let call = Arc::new(AtomicCell::new(Some(config.abnormal_call))); -// // //心跳线程 -// // { -// // let udp = udp.try_clone()?; -// // 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(); -// // } -// // } -// // drop(wait_group1); -// // }, -// // ) -// // .await; -// // } -// // //初始化nat数据 -// // handle::init_nat_test_addr(config.nat_test_server); -// // handle::init_nat_info(response.public_ip, response.public_port as u16); -// // // tun服务 -// // let (tun_writer, tun_reader) = -// // tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway)?; -// // // 打洞数据通道 -// // let (punch_sender, cone_receiver, req_symmetric_receiver, res_symmetric_receiver) = -// // handle::punch_handler::bounded(); -// // //udp数据处理 -// // { -// // // 低优先级的udp数据通道 -// // let (sender, receiver) = tokio::sync::mpsc::channel(50); -// // let udp1 = udp.try_clone()?; -// // let wait_group1 = wait_group.clone(); -// // let status_sender1 = status_sender.clone(); -// // let call1 = call.clone(); -// // handle::udp_recv_handler::udp_recv_start( -// // status_receiver.clone(), -// // udp1, -// // server_address, -// // sender, -// // tun_writer, -// // current_device, -// // move || { -// // if Self::call_stop(status_sender1) { -// // if let Some(call) = call1.take() { -// // call(); -// // } -// // } -// // drop(wait_group1); -// // }, -// // ) -// // .await; -// // let udp1 = udp.try_clone()?; -// // let wait_group1 = wait_group.clone(); -// // let status_sender1 = status_sender.clone(); -// // let call1 = call.clone(); -// // handle::udp_recv_handler::udp_other_recv_start( -// // status_receiver.clone(), -// // udp1, -// // receiver, -// // current_device, -// // punch_sender, -// // move || { -// // if Self::call_stop(status_sender1) { -// // if let Some(call) = call1.take() { -// // call(); -// // } -// // } -// // drop(wait_group1); -// // }, -// // ) -// // .await; -// // } -// // //打洞处理 -// // { -// // let udp1 = udp.try_clone()?; -// // let wait_group1 = wait_group.clone(); -// // let status_sender1 = status_sender.clone(); -// // let call1 = call.clone(); -// // handle::punch_handler::cone_handler_start( -// // status_receiver.clone(), -// // cone_receiver, -// // udp1, -// // current_device, -// // move || { -// // if Self::call_stop(status_sender1) { -// // if let Some(call) = call1.take() { -// // call(); -// // } -// // } -// // drop(wait_group1); -// // }, -// // ) -// // .await; -// // let udp1 = udp.try_clone()?; -// // let wait_group1 = wait_group.clone(); -// // let status_sender1 = status_sender.clone(); -// // let call1 = call.clone(); -// // handle::punch_handler::req_symmetric_handler_start( -// // status_receiver.clone(), -// // req_symmetric_receiver, -// // udp1, -// // current_device, -// // move || { -// // if Self::call_stop(status_sender1) { -// // if let Some(call) = call1.take() { -// // call(); -// // } -// // } -// // drop(wait_group1); -// // }, -// // ) -// // .await; -// // let udp1 = udp.try_clone()?; -// // let wait_group1 = wait_group.clone(); -// // let status_sender1 = status_sender.clone(); -// // let call1 = call.clone(); -// // handle::punch_handler::res_symmetric_handler_start( -// // status_receiver.clone(), -// // res_symmetric_receiver, -// // udp1, -// // current_device, -// // move || { -// // if Self::call_stop(status_sender1) { -// // if let Some(call) = call1.take() { -// // call(); -// // } -// // } -// // drop(wait_group1); -// // }, -// // ) -// // .await; -// // } -// // //tun数据处理 -// // { -// // let wait_group1 = wait_group.clone(); -// // let status_sender1 = status_sender.clone(); -// // let call1 = call.clone(); -// // handle::tun_handler::handler_start( -// // status_receiver.clone(), -// // udp, -// // tun_reader, -// // current_device, -// // move || { -// // if Self::call_stop(status_sender1) { -// // if let Some(call) = call1.take() { -// // call(); -// // } -// // } -// // drop(wait_group1); -// // }, -// // ) -// // .await; -// // } -// // Ok(Switch { -// // current_device, -// // status_sender, -// // wait_group, -// // runtime: None, -// // }) -// // } -// } diff --git a/switch/src/nat/check.rs b/switch/src/nat/check.rs index 6e7bcd7..d53f2e9 100644 --- a/switch/src/nat/check.rs +++ b/switch/src/nat/check.rs @@ -2,7 +2,7 @@ use std::collections::HashSet; use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; use std::time::Duration; use std::{io, thread}; -use nat_traversal::punch::NatType; +use p2p_channel::punch::NatType; // #[derive(Debug, Copy, Clone, PartialEq)] diff --git a/switch/src/nat/mod.rs b/switch/src/nat/mod.rs index ebea25c..2a3b03b 100644 --- a/switch/src/nat/mod.rs +++ b/switch/src/nat/mod.rs @@ -1,7 +1,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; use parking_lot::Mutex; -use nat_traversal::punch::{NatInfo, NatType}; +use p2p_channel::punch::{NatInfo, NatType}; use crate::proto::message::PunchNatType; pub mod check; diff --git a/switch/src/protocol/mod.rs b/switch/src/protocol/mod.rs index 339f2d6..30d9b51 100644 --- a/switch/src/protocol/mod.rs +++ b/switch/src/protocol/mod.rs @@ -86,6 +86,7 @@ impl Into for Protocol { } pub const MAX_TTL: u8 = 0b1111; +pub const MAX_SOURCE: u8 = 0b11110000; #[derive(Copy, Clone)] pub struct NetPacket { @@ -152,10 +153,10 @@ impl + AsMut<[u8]>> NetPacket { self.buffer.as_mut()[3] = ttl << 4 | ttl; } pub fn set_ttl(&mut self, ttl: u8) { - self.buffer.as_mut()[3] = MAX_TTL & ttl; + self.buffer.as_mut()[3] = (self.buffer.as_mut()[3] & MAX_SOURCE) | (MAX_TTL & ttl); } pub fn set_source_ttl(&mut self, source_ttl: u8) { - self.buffer.as_mut()[3] = (source_ttl << 4) | self.buffer.as_ref()[3]; + self.buffer.as_mut()[3] = (source_ttl << 4) | (MAX_TTL & self.buffer.as_ref()[3]); } pub fn set_source(&mut self, source: Ipv4Addr) { self.buffer.as_mut()[4..8].copy_from_slice(&source.octets()); diff --git a/switch/src/tun_device/linux.rs b/switch/src/tun_device/linux.rs index d86f553..ea59b63 100644 --- a/switch/src/tun_device/linux.rs +++ b/switch/src/tun_device/linux.rs @@ -1,5 +1,8 @@ use crate::tun_device::{TunReader, TunWriter}; use std::net::Ipv4Addr; +use std::sync::Arc; +use tun::Device; +use parking_lot::Mutex; pub fn create_tun( address: Ipv4Addr, @@ -13,17 +16,20 @@ pub fn create_tun( .address(address) .netmask(netmask) .mtu(1420) + // .queues(2) .up(); + // + // config.platform(|config| { + // config.packet_information(true); + // }); - config.platform(|config| { - config.packet_information(true); - }); - - let mut dev = tun::create(&config).unwrap(); + let dev = tun::create(&config).unwrap(); let packet_information = dev.has_packet_information(); - let (reader, writer) = dev.split(); + let queue = dev.queue(0).unwrap(); + let reader = queue.reader(); + let writer = queue.writer(); Ok(( - TunWriter(writer, packet_information), + TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))), TunReader(reader, packet_information), )) } diff --git a/switch/src/tun_device/mac.rs b/switch/src/tun_device/mac.rs index 4c5b9a1..4be2718 100644 --- a/switch/src/tun_device/mac.rs +++ b/switch/src/tun_device/mac.rs @@ -1,7 +1,9 @@ use std::net::Ipv4Addr; use std::process::Command; - +use std::io; use tun::Device; +use parking_lot::Mutex; +use std::sync::Arc; use crate::tun_device::{TunReader, TunWriter}; @@ -20,33 +22,7 @@ pub fn create_tun( .up(); let dev = tun::create(&config).unwrap(); - let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", dev.name(), address, gateway); - let route_add_str: String = format!( - "sudo route -n add -net {:?} -netmask {:?} {:?}", - address, netmask, gateway - ); - let up_eth_out = Command::new("sh") - .arg("-c") - .arg(up_eth_str) - .output() - .expect("sh exec error!"); - if !up_eth_out.status.success() { - return Err(crate::error::Error::Stop(format!( - "设置地址失败:{:?}", - up_eth_out - ))); - } - let if_config_out = Command::new("sh") - .arg("-c") - .arg(route_add_str) - .output() - .expect("sh exec error!"); - if !if_config_out.status.success() { - return Err(crate::error::Error::Stop(format!( - "设置路由失败:{:?}", - if_config_out - ))); - } + config_ip(dev.name(), address, netmask, gateway)?; // println!("{:?}", if_config_out); // let cmd_str: String = " ifconfig|grep flags=8051|awk -F ':' '{print $1}'|tail -1".to_string(); // @@ -60,9 +36,36 @@ pub fn create_tun( // } // println!("{:?}", cmd_str_out); let packet_information = dev.has_packet_information(); - let (reader, writer) = dev.split(); + let queue = dev.queue(0).unwrap(); + let reader = queue.reader(); + let writer = queue.writer(); Ok(( - TunWriter(writer, packet_information), + TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))), TunReader(reader, packet_information), )) } + +pub(crate) fn config_ip(name: &str, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> { + let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, address, gateway); + let route_add_str: String = format!( + "sudo route -n add -net {:?} -netmask {:?} {:?}", + address, netmask, gateway + ); + let up_eth_out = Command::new("sh") + .arg("-c") + .arg(up_eth_str) + .output() + .expect("sh exec error!"); + if !up_eth_out.status.success() { + return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", up_eth_out))); + } + let if_config_out = Command::new("sh") + .arg("-c") + .arg(route_add_str) + .output() + .expect("sh exec error!"); + if !if_config_out.status.success() { + return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", if_config_out))); + } + Ok(()) +} diff --git a/switch/src/tun_device/unix.rs b/switch/src/tun_device/unix.rs index 04f4145..1d66659 100644 --- a/switch/src/tun_device/unix.rs +++ b/switch/src/tun_device/unix.rs @@ -1,13 +1,21 @@ use std::io; -use std::io::{Read, Write}; +use std::sync::Arc; use bytes::BufMut; use tun::platform::posix::{Reader, Writer}; +use std::net::Ipv4Addr; +use std::os::unix::io::AsRawFd; +#[cfg(any(target_os = "linux", target_os = "android"))] +use tun::platform::linux::Device; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use tun::platform::macos::Device; +use parking_lot::Mutex; +#[derive(Clone)] pub struct TunReader(pub(crate) Reader, pub(crate) bool); impl TunReader { - pub fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> io::Result<&mut [u8]> { + pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> io::Result<&mut [u8]> { let len = self.0.read(buf)?; if self.1 { Ok(&mut buf[4..len]) @@ -15,12 +23,22 @@ impl TunReader { Ok(&mut buf[..len]) } } + pub fn close(&self) { + unsafe { + let raw = self.0.as_raw_fd(); + if raw >= 0 { + libc::close(raw); + } + } + } } -pub struct TunWriter(pub(crate) Writer, pub(crate) bool); + +#[derive(Clone)] +pub struct TunWriter(pub(crate) Writer, pub(crate) bool, pub(crate) Arc>); impl TunWriter { - pub fn write(&mut self, packet: &[u8]) -> io::Result<()> { + pub fn write(&self, packet: &[u8]) -> io::Result<()> { if self.1 { let mut buf = Vec::::with_capacity(4 + packet.len()); buf.put_u16(0); @@ -34,4 +52,23 @@ impl TunWriter { self.0.write_all(packet) } } + pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr, + gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> { + let mut config = tun::Configuration::default(); + use tun::Device; + config + .destination(gateway) + .address(address) + .netmask(netmask) + .mtu(1420) + // .queues(2) + .up(); + let mut dev = self.2.lock(); + if let Err(e) = dev.configure(&config) { + return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e))); + } + #[cfg(target_os = "macos")] + crate::tun_device::mac::config_ip(dev.name(), address, netmask, gateway); + return Ok(()); + } } diff --git a/switch/src/tun_device/windows.rs b/switch/src/tun_device/windows.rs index 720064f..38674e3 100644 --- a/switch/src/tun_device/windows.rs +++ b/switch/src/tun_device/windows.rs @@ -3,10 +3,11 @@ use std::net::Ipv4Addr; use std::sync::Arc; use libloading::Library; +use parking_lot::Mutex; use wintun::{Adapter, Packet, Session}; #[derive(Clone)] -pub struct TunWriter(Arc, u32); +pub struct TunWriter(Arc, Arc>); impl TunWriter { pub fn write(&self, buf: &[u8]) -> io::Result<()> { @@ -22,10 +23,11 @@ impl TunWriter { } pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr, old_netmask: Ipv4Addr, old_gateway: Ipv4Addr) -> io::Result<()> { - if let Err(e) = delete_route(self.1, old_netmask, old_gateway) { + let index = self.1.lock(); + if let Err(e) = delete_route(*index, old_netmask, old_gateway) { log::warn!("{:?}",e); } - config_ip(self.1, address, netmask, gateway) + config_ip(*index, address, netmask, gateway) } } @@ -79,7 +81,7 @@ pub fn create_tun( config_ip(index, address, netmask, gateway)?; let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap()); let reader_session = session.clone(); - Ok((TunWriter(session.clone(), index), TunReader(reader_session))) + Ok((TunWriter(session.clone(), Arc::new(Mutex::new(index))), TunReader(reader_session))) } fn config_ip(index: u32, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {