diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c8535d9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "switch/p2p_channel"] + path = switch/p2p_channel + url = git@github.com:lbl8603/p2p_channel.git diff --git a/switch-desktop/Cargo.toml b/switch-desktop/Cargo.toml index 5ceebd1..7853580 100644 --- a/switch-desktop/Cargo.toml +++ b/switch-desktop/Cargo.toml @@ -13,17 +13,19 @@ console = "0.15.2" dirs = "4.0.0" log = "0.4.17" log4rs = "1.2.0" -tokio = { version = "1.24.1", features = ["full"] } +#tokio = { version = "1.24.1", features = ["full"] } chrono = "0.4.23" serde = "1.0" serde_yaml = "0.9" +serde_json = "1.0.94" crossbeam = "0.8.2" lazy_static = "1.4.0" parking_lot = "0.12.1" #parity-tokio-ipc = "0.9.0" -futures = "0.3" +#futures = "0.3" +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 b570b7a..d62431c 100644 --- a/switch-desktop/src/command/client.rs +++ b/switch-desktop/src/command/client.rs @@ -2,15 +2,17 @@ use std::io; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; use std::time::Duration; +use crate::command::entity::{DeviceItem, RouteItem, Status}; + pub struct CommandClient { udp: UdpSocket, } impl CommandClient { pub fn new() -> io::Result { - let port = crate::config::read_command_port().unwrap(); + let port = crate::config::read_command_port()?; let udp = UdpSocket::bind("127.0.0.1:0")?; - udp.set_read_timeout(Some(Duration::from_secs(5)))?; + udp.set_read_timeout(Some(Duration::from_secs(2)))?; udp.connect(SocketAddr::V4(SocketAddrV4::new( Ipv4Addr::new(127, 0, 0, 1), port, @@ -20,16 +22,52 @@ impl CommandClient { } impl CommandClient { - pub fn list(&self) -> io::Result { + pub fn list(&self) -> io::Result> { self.udp.send(b"list")?; let mut buf = [0; 10240]; let len = self.udp.recv(&mut buf)?; - Ok(String::from_utf8(buf[..len].to_vec()).unwrap()) + match serde_json::from_slice::>(&buf[..len]) { + Ok(val) => { + Ok(val) + } + Err(e) => { + log::error!("{:?}",e); + Err(io::Error::new(io::ErrorKind::Other, "data error")) + } + } } - pub fn status(&self) -> io::Result { + pub fn route(&self) -> io::Result> { + self.udp.send(b"route")?; + let mut buf = [0; 10240]; + let len = self.udp.recv(&mut buf)?; + match serde_json::from_slice::>(&buf[..len]) { + Ok(val) => { + Ok(val) + } + Err(e) => { + log::error!("{:?}",e); + Err(io::Error::new(io::ErrorKind::Other, "data error")) + } + } + } + pub fn status(&self) -> io::Result { self.udp.send(b"status")?; let mut buf = [0; 10240]; let len = self.udp.recv(&mut buf)?; + match serde_json::from_slice::(&buf[..len]) { + Ok(val) => { + Ok(val) + } + Err(e) => { + log::error!("{:?},{:?}",&buf[..len],e); + Err(io::Error::new(io::ErrorKind::Other, "data error")) + } + } + } + pub fn stop(&self) -> io::Result { + self.udp.send(b"stop")?; + let mut buf = [0; 10240]; + let len = self.udp.recv(&mut buf)?; Ok(String::from_utf8(buf[..len].to_vec()).unwrap()) } } diff --git a/switch-desktop/src/command/entity.rs b/switch-desktop/src/command/entity.rs new file mode 100644 index 0000000..2f7c373 --- /dev/null +++ b/switch-desktop/src/command/entity.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; +#[derive(Serialize, Deserialize, Debug)] +pub struct Status { + pub name: String, + pub virtual_ip: String, + pub virtual_gateway: String, + pub virtual_netmask: String, + pub connect_status: String, + pub relay_server: String, + pub nat_type: String, + pub public_ips: String, + pub local_ip: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct RouteItem { + pub destination: String, + pub next_hop: String, + pub metric: String, + pub rt: String, + pub interface: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct DeviceItem { + pub name: String, + pub virtual_ip: String, + pub nat_type: String, + pub public_ips: String, + pub local_ip: String, + pub nat_traversal_type: String, + pub rt: String, + pub status: String, +} \ No newline at end of file diff --git a/switch-desktop/src/command/mod.rs b/switch-desktop/src/command/mod.rs index c07f47e..78be5dc 100644 --- a/switch-desktop/src/command/mod.rs +++ b/switch-desktop/src/command/mod.rs @@ -1,2 +1,3 @@ pub mod client; pub mod server; +pub mod entity; diff --git a/switch-desktop/src/command/server.rs b/switch-desktop/src/command/server.rs index 0be90a0..036114f 100644 --- a/switch-desktop/src/command/server.rs +++ b/switch-desktop/src/command/server.rs @@ -3,9 +3,9 @@ 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}; -use switch::handle::{PeerDeviceStatus, RouteType}; -use switch::Switch; pub struct CommandServer {} @@ -54,111 +54,137 @@ impl CommandServer { } } +pub fn command_route(switch: &Switch) -> Vec { + let route_table = switch.route_table(); + let mut route_list = Vec::with_capacity(route_table.len()); + for (destination, route) in route_table { + let next_hop = switch.route_key(&route.route_key()).map_or(String::new(), |v| v.to_string()); + let metric = route.metric.to_string(); + let rt = if route.rt < 0 { + "".to_string() + } else { + route.rt.to_string() + }; + let interface = route.addr.to_string(); + let item = RouteItem { + destination: destination.to_string(), + next_hop, + metric, + rt, + interface, + }; + route_list.push(item); + } + route_list +} + +pub fn command_list(switch: &Switch) -> Vec { + let device_list = switch.device_list(); + let mut list = Vec::new(); + for peer in device_list { + let name = peer.name; + let virtual_ip = peer.virtual_ip.to_string(); + let (nat_type, public_ips, local_ip) = if let Some(nat_info) = switch.peer_nat_info(&peer.virtual_ip) { + let nat_type = format!("{:?}", nat_info.nat_type); + let public_ips: Vec = nat_info.public_ips.iter().map(|v| v.to_string()).collect(); + let public_ips = public_ips.join(","); + let local_ip = nat_info.local_ip.to_string(); + (nat_type, public_ips, local_ip) + } else { + ("".to_string(), "".to_string(), "".to_string()) + }; + let (nat_traversal_type, rt) = if let Some(route) = switch.route(&peer.virtual_ip) { + let nat_traversal_type = if route.metric == 1 { "p2p" } else { "relay" }.to_string(); + let rt = if route.rt < 0 { + "".to_string() + } else { + route.rt.to_string() + }; + (nat_traversal_type, rt) + } else { + ("relay".to_string(), "".to_string()) + }; + let status = format!("{:?}", peer.status); + let item = DeviceItem { + name, + virtual_ip, + nat_type, + public_ips, + local_ip, + nat_traversal_type, + rt, + status, + }; + list.push(item); + } + list +} + +pub fn command_status(switch: &Switch) -> Status { + let current_device = switch.current_device(); + let nat_info = switch.nat_info(); + let name = switch.name().to_string(); + let virtual_ip = current_device.virtual_ip().to_string(); + let virtual_gateway = current_device.virtual_gateway().to_string(); + let virtual_netmask = current_device.virtual_netmask.to_string(); + let connect_status = format!("{:?}", switch.connection_status()); + let relay_server = current_device.connect_server.to_string(); + let nat_type = format!("{:?}", nat_info.nat_type); + let public_ips: Vec = nat_info.public_ips.iter().map(|v| v.to_string()).collect(); + let public_ips = public_ips.join(","); + let local_ip = nat_info.local_ip.to_string(); + Status { + name, + virtual_ip, + virtual_gateway, + virtual_netmask, + connect_status, + relay_server, + nat_type, + public_ips, + local_ip, + } +} + fn command(cmd: &str, switch: &Switch) -> io::Result { - let mut out_str = String::new(); - match cmd { - "list" => { - let server_rt = switch.server_rt(); - let device_list = switch.device_list(); - if device_list.is_empty() { - return Ok("No other devices found\n".to_string()); + let out_str = match cmd { + "route" => { + match serde_json::to_string(&command_route(switch)) { + Ok(str) => { + str + } + Err(e) => { + format!("{:?}", e) + } } - for peer_device_info in device_list { - let route = switch.route(&peer_device_info.virtual_ip); - let str = if peer_device_info.status == PeerDeviceStatus::Online { - if route.route_type == RouteType::P2P { - let str = if route.rt >= 0 { - format!( - "[{}] {}(p2p delay:{}ms)\n", - peer_device_info.name, peer_device_info.virtual_ip, route.rt - ) - } else { - format!( - "[{}] {}(p2p)", - peer_device_info.name, peer_device_info.virtual_ip - ) - }; - style(str).green().to_string() - } else { - let str = if server_rt >= 0 { - format!( - "[{}] {}(relay delay:{}ms)\n", - peer_device_info.name, - peer_device_info.virtual_ip, - server_rt * 2 - ) - } else { - format!( - "[{}] {}(relay)\n", - peer_device_info.name, peer_device_info.virtual_ip - ) - }; - style(str).blue().to_string() - } - } else { - let str = format!( - "[{}] {}(Offline)\n", - peer_device_info.name, peer_device_info.virtual_ip - ); - style(str).red().to_string() - }; - out_str.push_str(&str); + } + "list" => { + match serde_json::to_string(&command_list(switch)) { + Ok(str) => { + str + } + Err(e) => { + format!("{:?}", e) + } } } "status" => { - let server_rt = switch.server_rt(); - let current_device = switch.current_device(); - let str = format!("Virtual ip:{}\n", style(current_device.virtual_ip).green()); - out_str.push_str(&str); - let str = format!( - "Virtual gateway:{}\n", - style(current_device.virtual_gateway).green() - ); - out_str.push_str(&str); - let str = format!( - "Connection status :{}\n", - style(format!("{:?}", switch.connection_status())).green() - ); - out_str.push_str(&str); - let str = format!( - "Relay server :{}\n", - style(current_device.connect_server).green() - ); - out_str.push_str(&str); - if server_rt >= 0 { - let str = format!("Delay of relay server :{}ms\n", style(server_rt).green()); - out_str.push_str(&str); - } - if let Some(nat_info) = switch.nat_info() { - let str = format!( - "NAT type :{}", - style(format!("{:?}", nat_info.nat_type)).green() - ); - out_str.push_str(&str); + match serde_json::to_string(&command_status(switch)) { + Ok(str) => { + str + } + Err(e) => { + format!("{:?}", e) + } } } - "help" | "h" => { - let str = format!("Options: \n"); - out_str.push_str(&str); - let str = format!( - "{} , Query the virtual IP of other devices\n", - style("list").green() - ); - out_str.push_str(&str); - let str = format!("{} , View current device status\n", style("status").green()); - out_str.push_str(&str); - let str = format!("{} , Exit the program\n", style("exit").green()); - out_str.push_str(&str); - } - "exit" => { - switch.stop_async(); + "stop" => { + switch.stop()?; + "stopping".to_string() } _ => { - let str = format!("command '{}' not fount. \n", style(cmd).red()); - out_str.push_str(&str); - let str = format!("Try to enter: '{}'\n", style("help").green()); - out_str.push_str(&str); + format!("command '{}' not fount. \n Try to enter: 'help'\n", cmd) } - } + }; Ok(out_str) } diff --git a/switch-desktop/src/config/log_config.rs b/switch-desktop/src/config/log_config.rs new file mode 100644 index 0000000..ca09594 --- /dev/null +++ b/switch-desktop/src/config/log_config.rs @@ -0,0 +1,64 @@ +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(()) +} + +pub fn log_init() -> io::Result<()> { + let home = dirs::home_dir().unwrap().join(".switch"); + if !home.exists() { + std::fs::create_dir(&home)?; + } + let stderr = log4rs::append::console::ConsoleAppender::builder() + .target(log4rs::append::console::Target::Stderr) + .build(); + let logfile = log4rs::append::file::FileAppender::builder() + // Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html + .encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new( + "{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n", + ))) + .build(home.join("switch.log"))?; + match log4rs::Config::builder() + .appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile))) + .appender( + log4rs::config::Appender::builder() + .filter(Box::new(log4rs::filter::threshold::ThresholdFilter::new( + log::LevelFilter::Error, + ))) + .build("stderr", Box::new(stderr)), + ) + .build( + log4rs::config::Root::builder() + .appender("logfile") + .appender("stderr") + .build(log::LevelFilter::Info), + ) { + Ok(config) => { + let _ = log4rs::init_config(config); + } + Err(_) => {} + } + Ok(()) +} \ No newline at end of file diff --git a/switch-desktop/src/config/mod.rs b/switch-desktop/src/config/mod.rs index 9c2e758..ed6b435 100644 --- a/switch-desktop/src/config/mod.rs +++ b/switch-desktop/src/config/mod.rs @@ -1,11 +1,104 @@ use std::fs::File; use std::io; use std::io::{Read, Write}; +use std::net::{SocketAddr, ToSocketAddrs}; use std::path::PathBuf; use lazy_static::lazy_static; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; +use crate::{BaseArgs, StartArgs}; + +pub mod log_config; + +pub struct BaseConfig { + pub name: String, + pub token: String, + pub server: SocketAddr, + pub nat_test_server: Vec, + pub device_id: String, +} + +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()); + } + let token = start_args.token.unwrap_or_else(|| args_config.as_ref().unwrap().token.clone()).trim().to_string(); + if token.is_empty() { + return Err("token不能为空(Token cannot be empty)".to_string()); + } + if token.len() > 64 { + return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string()); + } + let name = start_args.name.unwrap_or_else(|| { + if let Some(c) = &args_config { + c.name.clone() + } else { + os_info::get().to_string() + } + }); + let name = name.trim(); + let name = if name.len() > 64 { + name[..64].to_string() + } else { + name.to_string() + }; + let device_id = start_args.device_id.unwrap_or_else(|| { + if let Some(c) = &args_config { + if !c.device_id.is_empty() { + return c.device_id.clone(); + } + } + if let Ok(Some(mac_address)) = mac_address::get_mac_address() { + mac_address.to_string() + } else { + "".to_string() + } + }); + if device_id.is_empty() || device_id.len() > 64 { + return Err("设备id不能为空并且长度不能大于64字符(The device id cannot be empty and the length cannot be greater than 64 characters)".to_string()); + } + let server = match start_args.server.unwrap_or_else(|| { + if let Some(c) = &args_config { + if !c.server.is_empty() { + return c.server.clone(); + } + } + "nat1.wherewego.top:29875".to_string() + }).to_socket_addrs() { + Ok(mut server) => { + if let Some(addr) = server.next() { + addr + } else { + return Err("中继服务器地址错误( Relay server address error)".to_string()); + } + } + Err(e) => { + return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e)); + } + }; + let nat_test_server = start_args.nat_test_server.unwrap_or_else(|| { + if let Some(c) = &args_config { + if !c.nat_test_server.is_empty() { + return c.nat_test_server.join(","); + } + } + "nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string() + }).split(",").flat_map(|a| a.to_socket_addrs()).flatten() + .collect::>(); + if nat_test_server.is_empty() { + return Err("NAT检测服务地址错误(NAT detection service address error)".to_string()); + } + let base_config = BaseConfig { + name, + token, + server, + nat_test_server, + device_id, + }; + Ok(base_config) +} lazy_static! { static ref CONFIG: Mutex> = Mutex::new(None); @@ -14,17 +107,43 @@ lazy_static! { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ArgsConfig { + #[serde(default = "default_version")] + pub version: String, + #[serde(default = "default_str")] pub token: String, - pub name: Option, + #[serde(default = "default_str")] + pub name: String, pub command_port: Option, + #[serde(default = "default_str")] + pub server: String, + #[serde(default = "default_resource_vec")] + pub nat_test_server: Vec, + #[serde(default = "default_str")] + pub device_id: String, +} + +fn default_version() -> String { + "1.0".to_string() +} + +fn default_str() -> String { + "".to_string() +} + +fn default_resource_vec() -> Vec { + vec![] } impl ArgsConfig { - pub fn new(token: String, name: Option) -> Self { + pub fn new(token: String, name: String, server: String, nat_test_server: Vec, device_id: String) -> Self { Self { + version: "1.0".to_string(), token, name, command_port: None, + server, + nat_test_server, + device_id, } } } @@ -66,13 +185,13 @@ pub fn read_config() -> Option { return c; } if let Some(home) = SWITCH_HOME_PATH.lock().clone() { - match read_config_(home) { + match read_config_(home.to_path_buf()) { Ok(config) => { lock.replace(config.clone()); Some(config) } Err(e) => { - log::error!("{:?}", e); + log::error!("{:?},path:{:?}", e,home); None } } diff --git a/switch-desktop/src/console_out/mod.rs b/switch-desktop/src/console_out/mod.rs new file mode 100644 index 0000000..0c5c7aa --- /dev/null +++ b/switch-desktop/src/console_out/mod.rs @@ -0,0 +1,69 @@ +use std::net::Ipv4Addr; +use console::style; + +use switch::Route; + +use crate::command::entity::{DeviceItem, RouteItem, Status}; + +pub mod table; + +pub fn console_status(status: Status) { + println!("Name: {}", style(status.name).green()); + println!("Virtual ip: {}", style(status.virtual_ip).green()); + println!("Virtual gateway: {}", style(status.virtual_gateway).green()); + println!("Virtual netmask: {}", style(status.virtual_netmask).green()); + println!("Connection status: {}", style(status.connect_status).green()); + println!("NAT type: {}", style(status.nat_type).green()); + println!("Relay server: {}", style(status.relay_server).green()); + println!("Public ips: {}", style(status.public_ips).green()); + println!("Local ip: {}", style(status.local_ip).green()); +} + +pub fn console_route_table(list: Vec) { + if list.is_empty() { + println!("No route found"); + return; + } + let mut out_list = Vec::with_capacity(list.len()); + //表头 + out_list.push(vec!["Destination".to_string(), "Next Hop".to_string(), "Metric".to_string(), + "Rt".to_string(), "Interface".to_string()]); + for item in list { + out_list.push(vec![item.destination, item.next_hop, item.metric, + item.rt, item.interface]); + } + table::println_table(out_list) +} + +pub fn console_device_list(list: Vec) { + if list.is_empty() { + println!("No other devices found"); + return; + } + let mut out_list = Vec::with_capacity(list.len()); + //表头 + out_list.push(vec!["Name".to_string(), "Virtual Ip".to_string(), "P2P/Relay".to_string(), "Rt".to_string(), "Status".to_string()]); + for item in list { + out_list.push(vec![item.name, item.virtual_ip, item.nat_traversal_type, + item.rt, item.status]); + } + table::println_table(out_list) +} + +pub fn console_device_list_all(list: Vec) { + if list.is_empty() { + println!("No other devices found"); + return; + } + let mut out_list = Vec::with_capacity(list.len()); + //表头 + out_list.push(vec!["Name".to_string(), "Virtual Ip".to_string(), "NAT Type".to_string(), + "Public Ips".to_string(), "Local Ip".to_string(), "P2P/Relay".to_string(), + "Rt".to_string(), "Status".to_string()]); + for item in list { + out_list.push(vec![item.name, item.virtual_ip, item.nat_type, + item.public_ips, item.local_ip, item.nat_traversal_type, + item.rt, item.status]); + } + table::println_table(out_list) +} \ No newline at end of file diff --git a/switch-desktop/src/console_out/table.rs b/switch-desktop/src/console_out/table.rs new file mode 100644 index 0000000..7db54b8 --- /dev/null +++ b/switch-desktop/src/console_out/table.rs @@ -0,0 +1,26 @@ +const NODE: &str = "+"; +const EDGE: &str = "-"; +const HIGH: &str = "|"; +const SPACE: &str = " "; +const EMPTY: &str = ""; + +pub fn println_table(table: Vec>) { + if table.is_empty() { + return; + } + 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; + if width_list[index] < width { + width_list[index] = width; + } + } + } + for in_list in table { + for (index, item) in in_list.iter().enumerate() { + print!("{item:width$}", item = item, width = width_list[index]); + } + println!() + } +} \ No newline at end of file diff --git a/switch-desktop/src/main.rs b/switch-desktop/src/main.rs index b4b6d82..29582b1 100644 --- a/switch-desktop/src/main.rs +++ b/switch-desktop/src/main.rs @@ -1,104 +1,183 @@ use std::io; -use std::net::ToSocketAddrs; +use std::net::{SocketAddr, ToSocketAddrs}; use std::path::PathBuf; -use clap::Parser; +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::handle::{PeerDeviceStatus, RouteType}; -use switch::*; -#[cfg(windows)] mod command; -#[cfg(windows)] mod config; #[cfg(windows)] mod windows; +mod unix; +mod console_out; + #[derive(Parser, Debug)] #[command( - author = "Lu Beilin", - version, - about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信" +author = "Lu Beilin", +version, +about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信" )] -struct Args { - /// 32位字符 +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, + +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// 启动 + Start(StartArgs), + /// 停止后台服务 + Stop, + /// 安装服务 + /// Install service + #[cfg(windows)] + Install(InstallArgs), + /// 卸载服务 + /// Uninstall service + #[cfg(windows)] + Uninstall, + /// 配置 + #[cfg(windows)] + Config(ConfigArgs), + /// 查看路由 + /// View route + Route, + /// 查看设备列表 + /// View device list + List { + /// 查看所有 + #[arg(short, long)] + all: bool + }, + /// 查看设备当前状态 + /// View the current status of the device + Status, +} + +#[derive(Parser, Debug)] +pub struct StartArgs { + /// 不超过64个字符 /// 相同token的设备之间才能通信。 /// 建议使用uuid保证唯一性。 - /// 32-bit characters. + /// 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: String, + token: Option, /// 给设备一个名称,为空时默认用系统版本信息 /// Give the device a name. If it is blank, the system version information will be used by default - #[arg(long)] + #[arg(long, action)] 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, } -#[cfg(windows)] -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(()) +#[derive(Parser, Debug)] +pub struct InstallArgs { + /// 安装路径 + /// Service installation path + #[arg(long)] + path: String, + /// 服务开机自启动 + /// Autostart on system startup + #[arg(long)] + auto: bool, } -fn log_init() -> io::Result<()> { - let home = dirs::home_dir().unwrap().join(".switch"); - if !home.exists() { - std::fs::create_dir(&home)?; - } - let stderr = log4rs::append::console::ConsoleAppender::builder() - .target(log4rs::append::console::Target::Stderr) - .build(); - let logfile = log4rs::append::file::FileAppender::builder() - // Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html - .encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new( - "{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n", - ))) - .build(home.join("switch.log"))?; - match log4rs::Config::builder() - .appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile))) - .appender( - log4rs::config::Appender::builder() - .filter(Box::new(log4rs::filter::threshold::ThresholdFilter::new( - log::LevelFilter::Error, - ))) - .build("stderr", Box::new(stderr)), - ) - .build( - log4rs::config::Root::builder() - .appender("logfile") - .appender("stderr") - .build(log::LevelFilter::Info), - ) { - Ok(config) => { - let _ = log4rs::init_config(config); - } - Err(_) => {} - } - Ok(()) +#[derive(Parser, Debug)] +pub struct ConfigArgs { + /// 服务开机自启动 + /// Autostart on system startup + #[arg(long)] + auto: bool, + /// 取消服务开机自启动 + /// started manually + #[arg(long)] + not_auto: bool, } + #[cfg(windows)] fn main() { let args: Vec<_> = std::env::args().collect(); @@ -111,10 +190,12 @@ fn main() { windows::service::start(); return; } else { + let home = dirs::home_dir().unwrap().join(".switch"); + config::set_home(home); let _ = log_init(); - windows::main0(); + let args = BaseArgs::parse(); + windows::main0(args); } - // println!("{}", style("starting...").green()); } #[cfg(any(target_os = "linux", target_os = "macos"))] @@ -132,50 +213,16 @@ fn main() { start(args.token, args.name); } -pub fn start(token: String, name: Option) { - let mac_address = mac_address::get_mac_address().unwrap().unwrap().to_string(); - let server_address = "nat1.wherewego.top:29875" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(); - let nat_test_server = vec![ - "nat1.wherewego.top:35061" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - "nat1.wherewego.top:35062" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - "nat2.wherewego.top:35061" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - "nat2.wherewego.top:35062" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - ]; - let switch = match Config::new( +pub fn start(token: String, name: String, server_address: SocketAddr, nat_test_server: Vec, device_id: String) { + let config = Config::new( token, - mac_address, + device_id, name, server_address, nat_test_server, - || {}, - ) { - Ok(config) => match Switch::start(config) { - Ok(switch) => switch, - Err(e) => { - log::error!("{:?}", e); - return; - } - }, + ); + let switch = match Switch::start(config) { + Ok(switch) => switch, Err(e) => { log::error!("{:?}", e); return; @@ -187,11 +234,11 @@ pub fn start(token: String, name: Option) { let current_device = switch.current_device(); println!( "当前虚拟ip(virtual ip): {:?}", - style(current_device.virtual_ip).green() + style(current_device.virtual_ip()).green() ); println!( "虚拟网关(virtual gateway): {:?}", - style(current_device.virtual_gateway).green() + style(current_device.virtual_gateway()).green() ); loop { println!( @@ -202,14 +249,18 @@ pub fn start(token: String, name: Option) { Ok(cmd) => { if command(cmd.trim(), &switch).is_err() { println!("{}", style("stopping").red()); - switch.stop(); + if let Err(e) = switch.stop() { + println!("stop:{:?}", e); + } break; } } Err(e) => { println!("read_line:{:?}", e); println!("{}", style("stopping...").red()); - switch.stop(); + if let Err(e) = switch.stop() { + println!("stop:{:?}", e); + } break; } } @@ -218,81 +269,20 @@ pub fn start(token: String, name: Option) { std::process::exit(1); } + fn command(cmd: &str, switch: &Switch) -> Result<(), ()> { match cmd { + "route" => { + let list = command::server::command_route(switch); + console_out::console_route_table(list); + } "list" => { - let server_rt = switch.server_rt(); - let device_list = switch.device_list(); - if device_list.is_empty() { - println!("No other devices found"); - return Ok(()); - } - for peer_device_info in device_list { - let route = switch.route(&peer_device_info.virtual_ip); - if peer_device_info.status == PeerDeviceStatus::Online { - if route.route_type == RouteType::P2P { - let str = if route.rt >= 0 { - format!( - "[{}] {}(p2p delay:{}ms)", - peer_device_info.name, peer_device_info.virtual_ip, route.rt - ) - } else { - format!( - "[{}] {}(p2p)", - peer_device_info.name, peer_device_info.virtual_ip - ) - }; - println!("{}", style(str).green()); - } else { - let str = if server_rt >= 0 { - format!( - "[{}] {}(relay delay:{}ms)", - peer_device_info.name, - peer_device_info.virtual_ip, - server_rt * 2 - ) - } else { - format!( - "[{}] {}(relay)", - peer_device_info.name, peer_device_info.virtual_ip - ) - }; - println!("{}", style(str).blue()); - } - } else { - let str = format!( - "[{}] {}(Offline)", - peer_device_info.name, peer_device_info.virtual_ip - ); - println!("{}", style(str).red()); - } - } + let list = command::server::command_list(switch); + console_out::console_device_list(list); } "status" => { - let server_rt = switch.server_rt(); - let current_device = switch.current_device(); - println!("Virtual ip:{}", style(current_device.virtual_ip).green()); - println!( - "Virtual gateway:{}", - style(current_device.virtual_gateway).green() - ); - println!( - "Connection status :{}", - style(format!("{:?}", switch.connection_status())).green() - ); - println!( - "Relay server :{}", - style(current_device.connect_server).green() - ); - if server_rt >= 0 { - println!("Delay of relay server :{}ms", style(server_rt).green()); - } - if let Some(nat_info) = switch.nat_info() { - println!( - "NAT type :{}", - style(format!("{:?}", nat_info.nat_type)).green() - ); - } + let status = command::server::command_status(switch); + console_out::console_status(status); } "help" | "h" => { println!("Options: "); diff --git a/switch-desktop/src/unix/mod.rs b/switch-desktop/src/unix/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/switch-desktop/src/windows/mod.rs b/switch-desktop/src/windows/mod.rs index 910de42..bd7381b 100644 --- a/switch-desktop/src/windows/mod.rs +++ b/switch-desktop/src/windows/mod.rs @@ -2,8 +2,8 @@ use std::ffi::OsString; use std::path::PathBuf; use std::time::Duration; use std::{io, thread}; +use std::net::ToSocketAddrs; -use clap::Parser; use console::style; use windows_service::service::{ @@ -12,173 +12,206 @@ use windows_service::service::{ use windows_service::service_manager::{ServiceManager, ServiceManagerAccess}; use windows_service::Error; -use crate::config; +use crate::{BaseArgs, Commands, config, console_out}; +use crate::config::BaseConfig; pub mod service; mod windows_admin_check; -#[derive(Parser, Debug)] -#[command( - author = "Lu Beilin", - version, - about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信" -)] -struct Args { - /// 32位字符 - /// 相同token的设备之间才能通信。 - /// 建议使用uuid保证唯一性。 - /// 32-bit 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, - /// 安装服务,安装后可以后台运行,需要指定安装路径 - /// The installation service can run in the background after installation, and the installation path needs to be specified - #[arg(long)] - install: Option, - /// 卸载服务 - /// Uninstall service - #[arg(long)] - uninstall: 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(long)] - start: bool, - #[arg(long)] - /// 停止,安装服务后,使用 --stop停止服务 - /// Stop. After installing 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, -} - -pub const SERVICE_FLAG: &'static str = "start_switch_service_"; -pub const SERVICE_NAME: &'static str = "switch-service"; +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; -pub fn main0() { - let args = Args::parse(); - if args.list || args.status { - match service_state() { - Ok(state) => { - if state == ServiceState::Running { - let command_client = crate::command::client::CommandClient::new().unwrap(); - let out = if args.list { - command_client.list().unwrap() - } else if args.status { - command_client.status().unwrap() - } else { - "".to_string() - }; - println!("{}", out); - } else { - println!("服务未启动") +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); } - } - Err(e) => { - println!("{:?}", e); + "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); + } + _ => {} } } - return; - } + 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!( "{}", style("请使用管理员权限运行(Please run with administrator privileges)").red() ); - return; + true + } else { + false } - if let Some(path) = args.install { - let path: PathBuf = path.into(); - if !path.exists() { - std::fs::create_dir_all(&path).unwrap(); - } - if !path.is_dir() { - println!("参数必须为文件目录(Parameter must be a file directory)"); - } else { - if let Err(e) = install(path) { - log::error!("{:?}", e); +} + +fn not_started() -> bool { + match service_state() { + Ok(state) => { + if state == ServiceState::Running { + return false; } else { - println!("{}", style("安装成功(Installation succeeded)").green()) + println!("服务未启动") } } - } else if args.uninstall { - if let Err(e) = uninstall() { - log::error!("{:?}", e); - } else { - println!("{}", style("卸载成功(Uninstall succeeded)").green()) + Err(e) => { + println!("{:?}", e); } - } else if args.start { - if args.token.is_none() { - println!("{}", style("需要参数(require parameters) --token").red()); - } else { - let token = args.token.clone().unwrap(); - match service_state() { - Ok(state) => { - if state == ServiceState::Stopped { - config::save_config(config::ArgsConfig::new( - token.clone(), - args.name.clone(), - )) - .unwrap(); - match start() { - Ok(_) => { - //需要检查启动状态 - println!("{}", style("启动成功(Start successfully)").green()) - } - Err(e) => { - log::error!("{:?}", e); + } + return true; +} + +pub fn main0(base_args: BaseArgs) { + match base_args.command { + Commands::Start(args) => { + if admin_check() { + return; + } + match config::default_config(args) { + Ok(base_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(); + match start() { + Ok(_) => { + //需要检查启动状态 + std::thread::sleep(std::time::Duration::from_secs(2)); + println!("{}", style("启动成功(Start successfully)").green()) + } + Err(e) => { + log::error!("{:?}", e); + } + } + } else { + println!("服务未停止(Service not stopped)"); } } - } else { - println!("服务未停止(Service not stopped)"); + Err(e) => { + match e { + Error::Winapi(ref e) => { + if let Some(code) = e.raw_os_error() { + if code == 1060 { + //指定的服务未安装。 + println!( + "{}", + 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); + return; + } + } + } + _ => {} + } + println!("{:?}", e); + } } } Err(e) => { - match e { - Error::Winapi(ref e) => { - if let Some(code) = e.raw_os_error() { - if code == 1060 { - //指定的服务未安装。 - println!( - "{}", - style("服务未安装,在当前进程启动(The service is not installed and started in the current process)").red() - ); - crate::start(token, args.name); - return; - } - } - } - _ => {} - } - println!("{:?}", e); + println!("{}", style(e).red()); + } + }; + pause(); + } + Commands::Stop => { + if not_started() { + return; + } + match stop() { + Ok(_) => { + println!("{}", style("停止成功(Stopped successfully)").green()) + } + Err(e) => { + log::error!("{:?}", e); } } + pause(); } - } else if args.stop { - match stop() { - Ok(_) => { - println!("{}", style("停止成功(Stopped successfully)").green()) + Commands::Install(args) => { + let path: PathBuf = args.path.into(); + if !path.exists() { + std::fs::create_dir_all(&path).unwrap(); } - Err(e) => { + if !path.is_dir() { + println!("参数必须为文件目录(Parameter must be a file directory)"); + } else { + if let Err(e) = install(path, args.auto) { + log::error!("{:?}", e); + } else { + println!("{}", style("安装成功(Installation succeeded)").green()) + } + } + pause(); + } + Commands::Uninstall => { + if let Err(e) = uninstall() { log::error!("{:?}", e); + } else { + println!("{}", style("卸载成功(Uninstall succeeded)").green()) + } + pause(); + } + Commands::Config(args) => {} + Commands::Route => { + if not_started() { + return; + } + command("route"); + } + Commands::List { all } => { + if not_started() { + return; + } + if all { + command("list-all"); + } else { + command("list"); } } - } else { - println!("使用参数 -h 查看帮助(Use the parameter - h to view help)") + Commands::Status => { + if not_started() { + return; + } + command("status"); + } } - pause(); } fn pause() { @@ -191,11 +224,11 @@ fn pause() { let _ = term.read_char().unwrap(); } -fn install(path: PathBuf) -> Result<(), Error> { +fn install(path: PathBuf, auto: bool) -> Result<(), Error> { let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE; let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; let current_exe_path = std::env::current_exe().unwrap(); - let service_path = path.join("switch-service.exe"); + let service_path = path.join("switch-service-v1.exe"); std::fs::copy(current_exe_path, service_path.as_path()).unwrap(); if let Err(e) = std::fs::copy("wintun.dll", path.join("wintun.dll").as_path()) { if e.kind() == io::ErrorKind::NotFound { @@ -210,11 +243,16 @@ fn install(path: PathBuf) -> Result<(), Error> { launch_arguments.push(OsString::from( dirs::home_dir().unwrap().join(".switch").to_str().unwrap(), )); + let start_type = if auto { + ServiceStartType::AutoStart + } else { + ServiceStartType::OnDemand + }; let service_info = ServiceInfo { name: OsString::from(SERVICE_NAME), - display_name: OsString::from("switch service"), + display_name: OsString::from("switch service v1"), service_type: ServiceType::OWN_PROCESS, - start_type: ServiceStartType::OnDemand, + start_type, error_control: ServiceErrorControl::Normal, executable_path: service_path.into(), launch_arguments, diff --git a/switch-desktop/src/windows/service.rs b/switch-desktop/src/windows/service.rs index fa6d54c..52abad9 100644 --- a/switch-desktop/src/windows/service.rs +++ b/switch-desktop/src/windows/service.rs @@ -6,13 +6,12 @@ use std::sync::Arc; use std::thread; use std::time::Duration; use std::net::ToSocketAddrs; -use switch::{Config, Switch}; 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::windows::config::read_config; define_windows_service!(ffi_service_main, switch_service_main); @@ -36,8 +35,8 @@ fn service_main() -> windows_service::Result<()> { // Handle stop ServiceControl::Stop => { - log::info!("handler 服务停止"); un_parker.unpark(); + log::info!("handler 服务停止"); ServiceControlHandlerResult::NoError } _ => ServiceControlHandlerResult::NotImplemented, @@ -59,72 +58,11 @@ fn service_main() -> windows_service::Result<()> { wait_hint: Duration::default(), process_id: None, })?; - if let Some(config) = read_config() { - let mac_address = mac_address::get_mac_address().unwrap().unwrap().to_string(); - let un_parker = parker.unparker().clone(); - let server_address = "nat1.wherewego.top:29875" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(); - let nat_test_server = vec![ - "nat1.wherewego.top:35061" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - "nat1.wherewego.top:35062" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - "nat2.wherewego.top:35061" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - "nat2.wherewego.top:35062" - .to_socket_addrs() - .unwrap() - .next() - .unwrap(), - ]; - match Config::new( - config.token, - mac_address, - config.name, - server_address, - nat_test_server, - move || { - un_parker.unpark(); - }, - ) { - Ok(config) => match Switch::start(config) { - Ok(switch) => { - log::info!("switch-service服务启动"); - let switch = Arc::new(switch); - let command_server = crate::command::server::CommandServer::new(); - let switch1 = switch.clone(); - thread::spawn(move || { - if let Err(e) = command_server.start(switch1) { - log::warn!("{:?}", e); - } - }); - parker.park(); - switch.stop_async(); - thread::sleep(Duration::from_secs(1)); - log::info!("switch-service服务停止"); - } - Err(e) => { - log::error!("{:?}", e); - } - }, - Err(e) => { - log::error!("{:?}", e); - } - }; - } else { - log::info!("配置文件为空"); + if let Ok(switch) = start_switch() { + parker.park(); + if let Err(e) = switch.stop() { + log::warn!("switch stop:{:?}",e) + } } status_handle.set_service_status(ServiceStatus { service_type: crate::windows::SERVICE_TYPE, @@ -137,6 +75,49 @@ fn service_main() -> windows_service::Result<()> { }) } +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())); + } + let server_address = if let Some(server_address) = config.server + .to_socket_addrs()? + .next() { + server_address + } else { + return Err(switch::error::Error::Stop("server address error".to_string())); + }; + let mut 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())); + } + let config = Config::new( + config.token, + device_id, + config.name, + server_address, + nat_test_server); + let switch = Switch::start(config)?; + log::info!("switch-service服务启动"); + let switch = Arc::new(switch); + let command_server = crate::command::server::CommandServer::new(); + let switch1 = switch.clone(); + thread::spawn(move || { + if let Err(e) = command_server.start(switch1) { + log::warn!("{:?}", e); + } + }); + Ok(switch) + } else { + Err(switch::error::Error::Stop("配置文件为空".to_string())) + } +} + pub fn start() { log::info!("以服务的方式启动"); service_dispatcher::start("switch-service", ffi_service_main).unwrap(); diff --git a/switch/Cargo.toml b/switch/Cargo.toml index 27c9341..7c8f5e9 100644 --- a/switch/Cargo.toml +++ b/switch/Cargo.toml @@ -7,13 +7,14 @@ edition = "2021" [dependencies] packet = { path = "./packet" } -nat_traversal = { path = "./nat_traversal" } +nat_traversal = { path = "./p2p_channel" } bytes = "1.3.0" log = "0.4.17" libc = "0.2.137" dashmap = "5.4.0" crossbeam = "0.8.2" +crossbeam-skiplist = "0.1" parking_lot = "0.12.1" rsa = "0.7.2" @@ -22,11 +23,13 @@ sha2 = { version = "0.10.6", features = ["oid"] } thiserror = "1.0.37" chrono = "0.4.23" -lazy_static = "1.4.0" -moka = "0.9.6" +#lazy_static = "1.4.0" +#moka = "0.9.6" protobuf = "3.2.0" -os_info = "3.5.1" -tokio = { version = "1.24.1", features = ["full"] } +local-ip-address = "0.5.2" + +#mio = {version = "0.8.6",features = ["os-poll", "net"]} +#tokio = { version = "1.24.1", features = ["full"] } [target.'cfg(any(unix))'.dependencies] tun = { path = "./rust-tun" } diff --git a/switch/nat_traversal/Cargo.toml b/switch/nat_traversal/Cargo.toml deleted file mode 100644 index 776b151..0000000 --- a/switch/nat_traversal/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "nat_traversal" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -tokio = { version = "1.24.1", features = ["net"] } -futures = "0.3" -crossbeam-skiplist = "0.1" diff --git a/switch/nat_traversal/src/cone/mod.rs b/switch/nat_traversal/src/cone/mod.rs deleted file mode 100644 index 9f2bd8e..0000000 --- a/switch/nat_traversal/src/cone/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::io; -use std::net::SocketAddr; - -use tokio::net::UdpSocket; - -/// 锥形网络,使用一个端口 -pub struct Channel { - udp: UdpSocket, - server_address: SocketAddr, -} - -impl Channel { - pub async fn new(server_address: SocketAddr) -> io::Result { - Ok(Self { - udp: UdpSocket::bind("0:0").await?, - server_address, - }) - } -} - -impl Channel { - #[inline] - pub async fn recv(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.udp.recv_from(buf).await - } -} - -impl Channel { - #[inline] - pub async fn send_to(&self, buf: &[u8], addr: SocketAddr) -> io::Result { - self.udp.send_to(buf, addr).await - } - #[inline] - pub async fn send_server(&self, buf: &[u8]) -> io::Result { - self.udp.send_to(buf, self.server_address).await - } -} - - diff --git a/switch/nat_traversal/src/lib.rs b/switch/nat_traversal/src/lib.rs deleted file mode 100644 index 9b7699b..0000000 --- a/switch/nat_traversal/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use cone::Channel as ConeChannel; -pub use symmetric::Channel as SymmetricChannel; - -mod cone; -mod symmetric; \ No newline at end of file diff --git a/switch/nat_traversal/src/symmetric/mod.rs b/switch/nat_traversal/src/symmetric/mod.rs deleted file mode 100644 index 6f02825..0000000 --- a/switch/nat_traversal/src/symmetric/mod.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::io; -use std::net::SocketAddr; -use std::sync::Arc; - -use crossbeam_skiplist::SkipMap; -use tokio::net::UdpSocket; - -/// 对称网络,绑定多个端口 -/// -/// -/// 假设一方是对称网络,一方是锥形网络 -/// 如果对称网络一方绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,随机尝试k次的情况下 -/// 猜中的概率 p = 1-((65535-n)/65535)*((65535-n-1)/(65535-1))*...*((65535-n-k+1)/(65535-k+1)) -/// n取76,k取600,猜中的概率就超过50%了 -/// -/// 如果两方都是对称网络则不可取,因为尝试k次需要发送 k*n个包,数据量太大 -pub struct Channel { - udp_list: Vec>, - addr_map: SkipMap, - server_address: SocketAddr, -} - -impl Channel { - pub async fn new(server_address: SocketAddr, num: usize) -> io::Result { - let mut udp_list = Vec::with_capacity(num); - for _ in 0..num { - udp_list.push(Arc::new(UdpSocket::bind("0:0").await?)); - } - Ok(Self { - udp_list, - addr_map: SkipMap::new(), - server_address, - }) - } -} - -impl Channel { - #[inline] - pub async fn recv(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - let mut list = Vec::with_capacity(self.udp_list.len()); - for udp in &self.udp_list { - let udp = udp.clone(); - list.push(Box::pin(async move { - udp.readable().await - })); - } - let (rs, index, _) = futures::future::select_all(list.into_iter()).await; - let _ = rs?; - let (len, addr) = self.udp_list[index].try_recv_from(buf)?; - self.addr_map.insert(addr, index); - Ok((len, addr)) - } -} - -impl Channel { - /// 向一个已经穿透成功洞地址发数据 - #[inline] - pub async fn send_to(&self, buf: &[u8], addr: SocketAddr) -> io::Result { - if let Some(entry) = self.addr_map.get(&addr) { - self.udp_list[*entry.value()].send_to(buf, addr).await - } else { - Err(io::Error::from(io::ErrorKind::NotConnected)) - } - } - /// 向所有渠道发数据,用于打洞 - #[inline] - pub async fn send_all(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> { - for udp in &self.udp_list { - udp.send_to(buf, addr).await?; - } - Ok(()) - } - /// 向服务器发送数据 - #[inline] - pub async fn send_server(&self, buf: &[u8]) -> io::Result { - self.udp_list[0].send_to(buf, self.server_address).await - } -} - -impl Channel { - pub fn remove_hole(&self, hole: &SocketAddr) { - self.addr_map.remove(hole); - } -} - - diff --git a/switch/p2p_channel b/switch/p2p_channel new file mode 160000 index 0000000..4a971a3 --- /dev/null +++ b/switch/p2p_channel @@ -0,0 +1 @@ +Subproject commit 4a971a34dd9890f6e7ec732015f2cf4790200dc9 diff --git a/switch/proto/message.proto b/switch/proto/message.proto index f0e63f5..6a490b4 100644 --- a/switch/proto/message.proto +++ b/switch/proto/message.proto @@ -1,7 +1,7 @@ syntax = "proto3"; message RegistrationRequest{ string token = 1; - string mac_address = 2; + string device_id = 2; string name = 3; bool is_fast = 4; } @@ -26,15 +26,16 @@ message DeviceList{ repeated DeviceInfo device_info_list = 2; } -message Punch{ - fixed32 virtual_ip = 1; +message PunchInfo{ repeated fixed32 public_ip_list = 2; uint32 public_port = 3; uint32 public_port_range = 4; - NatType nat_type = 5; + PunchNatType nat_type = 5; bool reply = 6; + fixed32 local_ip = 7; + uint32 local_port = 8; } -enum NatType{ +enum PunchNatType{ Symmetric = 0; Cone = 1; } \ No newline at end of file diff --git a/switch/src/core/mod.rs b/switch/src/core/mod.rs new file mode 100644 index 0000000..b80128e --- /dev/null +++ b/switch/src/core/mod.rs @@ -0,0 +1,144 @@ +use std::io; +use std::net::{Ipv4Addr, SocketAddr}; +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 crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tun_handler}; +use crate::nat::NatTest; +use crate::tun_device; +use crate::tun_device::TunReader; + +pub struct Switch { + name: String, + current_device: Arc>, + tun_reader: TunReader, + nat_channel: Channel, + /// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化 + /// 服务端和客户端的不一致,则服务端会推送新的设备列表 + /// 1. 网络中的虚拟ip列表 + device_list: Arc)>>, + nat_test: NatTest, + connect_status: Arc>, + peer_nat_info_map: Arc>, +} + +impl Switch { + pub fn start(config: Config) -> crate::Result { + let (mut channel, punch, idle) = Boot::new::(100, 9000, 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()))); + let peer_nat_info_map: Arc> = Arc::new(SkipMap::new()); + let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected)); + 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 current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address))); + let local_addr = channel.local_addr()?; + let local_ip = if local_addr.ip().is_unspecified() { + local_ip_address::local_ip().unwrap_or(local_addr.ip()) + } else { + local_addr.ip() + }; + // NAT检测 + let nat_test = NatTest::new(config.nat_test_server.clone(), Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_addr.port()); + // tun通道 + let (tun_writer, tun_reader) = tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway)?; + + // 定时心跳 + heartbeat_handler::start_heartbeat(channel.sender()?, device_list.clone(), current_device.clone()); + // 空闲检查 + heartbeat_handler::start_idle(idle, channel.sender()?); + // 打洞处理 + punch_handler::start_cone(punch.try_clone()?, current_device.clone()); + punch_handler::start_symmetric(punch, current_device.clone()); + punch_handler::start_punch(nat_test.clone(), device_list.clone(), channel.sender()?, current_device.clone()); + //tun数据接收处理 + for _ in 0..2 { + tun_handler::start(channel.sender()?, tun_reader.clone(), tun_writer.clone(), current_device.clone()); + } + //外部数据接收处理 + let channel_recv_handler = recv_handler::RecvHandler::new(channel.try_clone()?, current_device.clone(), device_list.clone(), register.clone(), + nat_test.clone(), tun_writer.clone(), connect_status.clone(), peer_nat_info_map.clone()); + for _ in 0..2 { + recv_handler::start(channel_recv_handler.try_clone()?); + } + Ok(Switch { + name: config.name, + current_device, + tun_reader, + nat_channel: channel, + nat_test, + device_list, + connect_status, + peer_nat_info_map, + }) + } +} + +impl Switch { + pub fn name(&self) -> &str { + &self.name + } + pub fn current_device(&self) -> CurrentDeviceInfo { + self.current_device.load() + } + pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option { + self.peer_nat_info_map.get(ip).map(|e| e.value().clone()) + } + pub fn connection_status(&self) -> ConnectStatus { + self.connect_status.load() + } + pub fn nat_info(&self) -> NatInfo { + self.nat_test.nat_info() + } + pub fn device_list(&self) -> Vec { + let device_list_lock = self.device_list.lock(); + let (_epoch, device_list) = device_list_lock.clone(); + drop(device_list_lock); + device_list + } + pub fn route(&self, ip: &Ipv4Addr) -> Option { + self.nat_channel.route(ip) + } + pub fn route_key(&self, route_key: &RouteKey) -> Option { + self.nat_channel.route_to_id(route_key) + } + pub fn route_table(&self) -> Vec<(Ipv4Addr, Route)> { + self.nat_channel.route_list() + } + pub fn stop(&self) -> io::Result<()> { + self.tun_reader.close(); + self.nat_channel.close()?; + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub struct Config { + pub token: String, + pub device_id: String, + pub name: String, + pub server_address: SocketAddr, + pub nat_test_server: Vec, +} + +impl Config { + pub fn new(token: String, + device_id: String, + name: String, + server_address: SocketAddr, + nat_test_server: Vec, ) -> Self { + Self { + token, + device_id, + name, + server_address, + nat_test_server, + } + } +} \ No newline at end of file diff --git a/switch/src/error/mod.rs b/switch/src/error/mod.rs index 576bf03..24e6e3b 100644 --- a/switch/src/error/mod.rs +++ b/switch/src/error/mod.rs @@ -7,8 +7,6 @@ use thiserror::Error; pub enum Error { #[error("packet error")] PacketError(#[from] packet::error::Error), - #[error("TokioWatchRecvError")] - TokioWatchRecvError(#[from] tokio::sync::watch::error::RecvError), #[error("Io error")] Io(#[from] io::Error), #[error("Channel error")] @@ -21,6 +19,8 @@ pub enum Error { NotSupport, #[error("Stop")] Stop(String), + #[error("Warn")] + Warn(String), } pub type Result = std::result::Result; diff --git a/switch/src/handle/heartbeat_handler.rs b/switch/src/handle/heartbeat_handler.rs index 14e135f..ed49c7a 100644 --- a/switch/src/handle/heartbeat_handler.rs +++ b/switch/src/handle/heartbeat_handler.rs @@ -1,80 +1,104 @@ -use std::net::{SocketAddr, UdpSocket}; +use std::{io, thread}; +use std::net::Ipv4Addr; +use std::sync::Arc; use std::time::Duration; use chrono::Local; -use tokio::sync::watch::Receiver; -use tokio::time::sleep; +use crossbeam::atomic::AtomicCell; +use parking_lot::Mutex; +use rand::prelude::SliceRandom; +use nat_traversal::channel::Route; -use crate::error::*; -use crate::handle::{ApplicationStatus, DIRECT_ROUTE_TABLE}; +use nat_traversal::channel::sender::Sender; +use nat_traversal::idle::Idle; + +use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; +use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, Version}; use crate::protocol::control_packet::PingPacket; -use crate::protocol::{control_packet, NetPacket, Protocol, Version}; -use crate::{CurrentDeviceInfo, DEVICE_LIST}; -pub async fn start( - status_watch: Receiver, - udp: UdpSocket, - cur_info: CurrentDeviceInfo, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - tokio::spawn(async move { - match handle_loop(status_watch, udp, cur_info.connect_server).await { - Ok(_) => {} - Err(e) => { - log::warn!("{:?}", e) - } +pub fn start_idle(idle: Idle, sender: Sender) { + thread::spawn(move || { + if let Err(e) = start_idle_(idle, sender) { + log::info!("空闲检测线程停止:{:?}",e); } - stop_fn(); }); } -async fn handle_loop( - mut status_watch: Receiver, - udp: UdpSocket, - server_addr: SocketAddr, -) -> Result<()> { - const INTERVAL: u64 = 3000; - const MAX_INTERVAL: i64 = 3000 * 3; - let mut buf = [0u8; (4 + 8 + 4)]; - let mut net_packet = NetPacket::new(&mut buf)?; +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); + } +} + +pub fn start_heartbeat(sender: Sender, device_list: Arc)>>, current_device: Arc>) { + thread::spawn(move || { + if let Err(e) = start_heartbeat_(sender, device_list, current_device) { + log::info!("空闲检测线程停止:{:?}",e); + } + }); +} + +fn start_heartbeat_(sender: Sender, device_list: Arc)>>, current_device: Arc>) -> io::Result<()> { + let mut net_packet = NetPacket::new([0u8; 16])?; net_packet.set_version(Version::V1); net_packet.set_protocol(Protocol::Control); net_packet.set_transport_protocol(control_packet::Protocol::Ping.into()); - net_packet.set_ttl(255); + net_packet.first_set_ttl(MAX_TTL); + let mut count = 0; loop { - let current_time = Local::now().timestamp_millis(); + let current_device = current_device.load(); + net_packet.set_source(current_device.virtual_ip()); { + let current_time = Local::now().timestamp_millis() as u16; let mut ping = PingPacket::new(net_packet.payload_mut())?; ping.set_time(current_time); - let epoch = { DEVICE_LIST.lock().0 }; + let epoch = { device_list.lock().0 }; ping.set_epoch(epoch); } - let _ = udp.send_to(net_packet.buffer(), server_addr); - // 不clone会死锁? - for x in DIRECT_ROUTE_TABLE.clone().iter() { - let virtual_ip = x.key().clone(); - let route = x.value().clone(); - drop(x); - if current_time - route.recv_time <= MAX_INTERVAL { - let _ = udp.send_to(net_packet.buffer(), route.address); - } else { - DIRECT_ROUTE_TABLE.remove_if(&virtual_ip, |_, route| { - current_time - route.recv_time > MAX_INTERVAL - }); + if count % 7 == 0 { + let mut route_list: Option> = None; + let peer_list = device_list.lock().1.clone(); + for peer in peer_list { + net_packet.first_set_ttl(MAX_TTL); + net_packet.set_destination(peer.virtual_ip); + if sender.send_to_id(net_packet.buffer(), &peer.virtual_ip).is_err() { + //没有路由则发送到网关 + let _ = sender.send_to_addr(net_packet.buffer(), current_device.connect_server); + //再随机发送到其他地址,看有没有客户端符合转发条件 + let route_list = route_list.get_or_insert_with(|| { + let mut l = sender.route_list(); + l.shuffle(&mut rand::thread_rng()); + l + }); + let mut num = 0; + net_packet.first_set_ttl(2); + for (peer_ip, route) in route_list.iter() { + if peer_ip != &peer.virtual_ip && route.metric == 1 { + let _ = sender.send_to_route(net_packet.buffer(), &route.route_key()); + num += 1; + } + if num >= 3 { + break; + } + } + } } - } - tokio::select! { - _ = sleep(Duration::from_millis(INTERVAL))=>{ - + net_packet.set_destination(current_device.virtual_gateway()); + if let Err(e) = sender.send_to_addr(net_packet.buffer(), current_device.connect_server) { + log::warn!("connect_server:{:?},e:{:?}",current_device.connect_server,e); } - status = status_watch.changed() =>{ - status?; - if *status_watch.borrow() != ApplicationStatus::Starting{ - return Ok(()) + } else { + for (peer_ip, route) in sender.route_list().iter() { + net_packet.set_destination(*peer_ip); + if let Err(e) = sender.send_to_route(net_packet.buffer(), &route.route_key()) { + log::warn!("peer_ip:{:?},route:{:?},e:{:?}",peer_ip,route,e); } } } + + count += 1; + thread::sleep(Duration::from_secs(5)); } -} +} \ No newline at end of file diff --git a/switch/src/handle/mod.rs b/switch/src/handle/mod.rs index 5fef740..9e551f7 100644 --- a/switch/src/handle/mod.rs +++ b/switch/src/handle/mod.rs @@ -1,38 +1,17 @@ use std::net::{Ipv4Addr, SocketAddr}; -use std::sync::atomic::AtomicI64; -use std::time::Duration; - -use chrono::Local; -use dashmap::DashMap; -use lazy_static::lazy_static; -use moka::sync::Cache; -use parking_lot::{const_mutex, Mutex}; - -use crate::proto::message::NatType; pub mod heartbeat_handler; pub mod punch_handler; pub mod registration_handler; pub mod tun_handler; -pub mod udp_recv_handler; -lazy_static! { - /// 0. 机器纪元,每一次上线或者下线都会增1,由服务端维护,用于感知网络中机器变化 - /// 服务端和客户端的不一致,则服务端会推送新的设备列表 - /// 1. 网络中的虚拟ip列表 - pub static ref DEVICE_LIST:Mutex<(u32,Vec)> = const_mutex((0,Vec::new())); - /// 服务器延迟 - pub static ref SERVER_RT:AtomicI64 = AtomicI64::new(-1); - /// id - pub static ref ID:AtomicI64 = AtomicI64::new(0); - /// 直连路由表 - pub static ref DIRECT_ROUTE_TABLE:DashMap = DashMap::new(); - /// 地址映射 - pub static ref ADDR_TABLE:Cache = Cache::builder() - .time_to_idle(Duration::from_secs(60*5)).build(); - /// 当前设备的nat信息 - pub static ref NAT_INFO:Mutex> = const_mutex(None); - static ref NAT_TEST_ADDRESS:Mutex> = const_mutex(Vec::new()); +pub mod recv_handler; + +/// 是否在一个网段 +fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool { + u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(virtual_netmask.octets()) + == u32::from_be_bytes(virtual_network.octets()) } + #[derive(Clone, Debug, Eq, PartialEq)] pub struct PeerDeviceInfo { pub virtual_ip: Ipv4Addr, @@ -74,82 +53,15 @@ impl From for PeerDeviceStatus { } } -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum ApplicationStatus { - Starting, - Stopping, -} - #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ConnectStatus { Connecting, Connected, } -impl Into for ConnectStatus { - fn into(self) -> u8 { - match self { - ConnectStatus::Connecting => 0, - ConnectStatus::Connected => 1, - } - } -} - -#[derive(Clone, Debug)] -pub struct NatInfo { - pub public_ips: Vec, - pub public_port: u16, - pub public_port_range: u16, - pub nat_type: NatType, -} - -impl NatInfo { - pub fn new( - public_ips: Vec, - public_port: u16, - public_port_range: u16, - nat_type: NatType, - ) -> Self { - Self { - public_ips, - public_port, - public_port_range, - nat_type, - } - } -} - -pub fn init_nat_test_addr(addrs: Vec) { - NAT_TEST_ADDRESS.lock().extend_from_slice(&addrs); -} - -/// 初始化nat信息 -pub fn init_nat_info(public_ip: u32, public_port: u16) { - let addrs = NAT_TEST_ADDRESS.lock().clone(); - match crate::nat::check::public_ip_list(&addrs) { - Ok((nat_type, ips, port_range)) => { - let mut public_ips = Vec::new(); - public_ips.push(public_ip); - for ip in ips { - let ip = u32::from_be_bytes(ip.octets()); - if ip != public_ip { - public_ips.push(ip); - } - } - let nat_info = NatInfo::new(public_ips, public_port, port_range, nat_type); - // println!("nat信息:{:?}",nat_info); - let mut nat_info_lock = NAT_INFO.lock(); - nat_info_lock.replace(nat_info); - } - Err(e) => { - println!("获取nat数据失败,将无法进行udp打洞:{:?}", e); - } - } -} - -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct CurrentDeviceInfo { - pub virtual_ip: Ipv4Addr, + virtual_ip: Ipv4Addr, pub virtual_gateway: Ipv4Addr, pub virtual_netmask: Ipv4Addr, //网络地址 @@ -182,40 +94,16 @@ impl CurrentDeviceInfo { connect_server, } } -} - -#[derive(Clone, Debug)] -pub struct Route { - pub route_type: RouteType, - pub address: SocketAddr, - //用心跳探测延迟,收包时更新 - pub rt: i64, - //收包时更新,如果太久没有收到消息则剔除 - pub recv_time: i64, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum RouteType { - ServerRelay, - P2P, -} - -impl Into for RouteType { - fn into(self) -> u8 { - match self { - RouteType::ServerRelay => 0, - RouteType::P2P => 1, - } + #[inline] + pub fn virtual_ip(&self) -> Ipv4Addr { + self.virtual_ip + } + #[inline] + pub fn virtual_gateway(&self) -> Ipv4Addr { + self.virtual_gateway } } -impl Route { - pub fn new(address: SocketAddr) -> Self { - Self { - route_type: RouteType::P2P, - address, - rt: -1, - recv_time: Local::now().timestamp_millis(), - } - } -} + + + diff --git a/switch/src/handle/punch_handler.rs b/switch/src/handle/punch_handler.rs index 31ea851..d3ffb69 100644 --- a/switch/src/handle/punch_handler.rs +++ b/switch/src/handle/punch_handler.rs @@ -1,402 +1,140 @@ -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; -use std::time::Duration; use std::{io, thread}; - +use std::net::{IpAddr, Ipv4Addr}; +use std::sync::Arc; +use std::time::Duration; +use crossbeam::atomic::AtomicCell; +use parking_lot::Mutex; use protobuf::Message; use rand::prelude::SliceRandom; -use tokio::sync::mpsc::error::TrySendError; -use tokio::sync::mpsc::{Receiver, Sender}; -use tokio::sync::watch; +use nat_traversal::channel::sender::Sender; +use nat_traversal::punch::{NatInfo, NatType, Punch}; +use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; +use crate::nat::NatTest; +use crate::proto::message::{PunchInfo, PunchNatType}; +use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, turn_packet, Version}; -use crate::error::*; -use crate::handle::{ApplicationStatus, DIRECT_ROUTE_TABLE}; -use crate::proto::message::{NatType, Punch}; -use crate::protocol::control_packet::PunchRequestPacket; -use crate::protocol::turn_packet::TurnPacket; -use crate::protocol::{control_packet, turn_packet, NetPacket, Protocol, Version}; -use crate::{handle::NatInfo, handle::NAT_INFO, CurrentDeviceInfo, DEVICE_LIST}; - -/// 每一种类型一个通道,减少相互干扰 -pub fn bounded() -> ( - PunchSender, - ConeReceiver, - ReqSymmetricReceiver, - ResSymmetricReceiver, -) { - let (cone_sender, cone_receiver) = tokio::sync::mpsc::channel(3); - let (req_symmetric_sender, req_symmetric_receiver) = tokio::sync::mpsc::channel(1); - let (res_symmetric_sender, res_symmetric_receiver) = tokio::sync::mpsc::channel(1); - ( - PunchSender::new(cone_sender, req_symmetric_sender, res_symmetric_sender), - ConeReceiver(cone_receiver), - ReqSymmetricReceiver(req_symmetric_receiver), - ResSymmetricReceiver(res_symmetric_receiver), - ) -} - -pub struct ConeReceiver(Receiver); - -pub struct ReqSymmetricReceiver(Receiver); - -pub struct ResSymmetricReceiver(Receiver); - -#[derive(Clone)] -pub struct PunchSender { - cone_sender: Sender, - req_symmetric_sender: Sender, - res_symmetric_sender: Sender, -} - -impl PunchSender { - pub fn new( - cone_sender: Sender, - req_symmetric_sender: Sender, - res_symmetric_sender: Sender, - ) -> Self { - Self { - cone_sender, - req_symmetric_sender, - res_symmetric_sender, +pub fn start_cone(punch: Punch, current_device: Arc>) { + thread::spawn(move || { + if let Err(e) = start_(true, punch, current_device) { + log::warn!("锥形网络打洞处理线程停止 {:?}",e); } - } - // pub fn send(&self, punch: Punch) -> std::result::Result<(), SendError> { - // match punch.nat_type.enum_value_or_default() { - // NatType::Symmetric => { - // if punch.reply { - // // 为true表示回应,也就是主动发起的打洞操作 - // self.res_symmetric_sender.blocking_send(punch) - // } else { - // self.req_symmetric_sender.blocking_send(punch) - // } - // } - // NatType::Cone => { - // self.cone_sender.blocking_send(punch) - // } - // } - // } - pub fn try_send(&self, punch: Punch) -> std::result::Result<(), TrySendError> { - match punch.nat_type.enum_value_or_default() { - NatType::Symmetric => { - if punch.reply { - // 为true表示回应,也就是主动发起的打洞操作 - self.res_symmetric_sender.try_send(punch) - } else { - self.req_symmetric_sender.try_send(punch) - } + }); +} + +pub fn start_symmetric(punch: Punch, current_device: Arc>) { + thread::spawn(move || { + if let Err(e) = start_(false, punch, current_device) { + log::warn!("对称网络打洞处理线程停止 {:?}",e); + } + }); +} + +fn start_(is_cone: bool, mut punch: Punch, current_device: Arc>) -> io::Result<()> { + let mut packet = NetPacket::new([0u8; 12])?; + packet.set_version(Version::V1); + packet.first_set_ttl(1); + packet.set_protocol(Protocol::Control); + packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into()); + loop { + let (peer_ip, nat_info) = if is_cone { + punch.next_cone(None)? + } else { + punch.next_symmetric(None)? + }; + if let Some(route) = punch.sender().route(&peer_ip) { + if route.metric == 1 { + //直连地址不需要打洞 + continue; } - NatType::Cone => self.cone_sender.try_send(punch), + } + packet.set_source(current_device.load().virtual_ip()); + packet.set_destination(peer_ip); + log::info!("发起打洞,目标:{:?},{:?}",peer_ip,nat_info); + if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info) { + log::warn!("peer_ip:{:?},e:{:?}",peer_ip,e); } } } -fn handle( - _status_watch: &watch::Receiver, - udp: &UdpSocket, - punch_list: Vec, - buf: &[u8], -) -> Result<()> { - let mut counter = 0u64; - for punch in punch_list { - let dest = Ipv4Addr::from(punch.virtual_ip); - if DIRECT_ROUTE_TABLE.contains_key(&dest) { - continue; +pub fn start_punch(nat_test: NatTest, device_list: Arc)>>, sender: Sender, current_device: Arc>) { + thread::spawn(move || { + if let Err(e) = start_punch_(nat_test, device_list, sender, current_device) { + log::warn!("对称网络打洞处理线程停止 {:?}",e); } - // println!("punch {:?}", punch); - match punch.nat_type.enum_value_or_default() { - NatType::Symmetric => { - // 假设绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,随机尝试k次的情况下 - // 猜中的概率 p = 1-((65535-n)/65535)*((65535-n-1)/(65535-1))*...*((65535-n-k+1)/(65535-k+1)) - // n取76,k取600,猜中的概率就超过50%了 - // 前提 自己是锥形网络,否则猜中了也通信不了 - let mut send_f = |min_port: u16, max_port: u16, k: usize| -> io::Result<()> { - let mut nums: Vec = (min_port..max_port).collect(); - nums.push(max_port); - let mut rng = rand::thread_rng(); - nums.shuffle(&mut rng); - for pub_ip in &punch.public_ip_list { - let pub_ip = Ipv4Addr::from(*pub_ip); - for port in &nums[..k] { - udp.send_to(buf, SocketAddr::V4(SocketAddrV4::new(pub_ip, *port)))?; - select_sleep(&mut counter); - } - } - Ok(()) - }; - if punch.public_port_range < 600 { - //端口变化不大时,在预测的范围内随机发送 - let min_port = if punch.public_port > punch.public_port_range { - punch.public_port - punch.public_port_range - } else { - 1 - }; - let max_port = if punch.public_port + punch.public_port_range > 65535 { - 65535 - } else { - punch.public_port + punch.public_port_range - }; - let k = if max_port - min_port + 1 > 60 { - 60 - } else { - max_port - min_port + 1 - }; - send_f(min_port as u16, max_port as u16, k as usize)?; + }); +} + +fn start_punch_(nat_test: NatTest, device_list: Arc)>>, sender: Sender, current_device: Arc>) -> crate::Result<()> { + loop { + if sender.is_close() { + return Ok(()); + } + let current_device = current_device.load(); + let nat_info = nat_test.nat_info(); + { + let mut list = device_list.lock().clone().1; + list.shuffle(&mut rand::thread_rng()); + let mut count = 0; + for info in list { + if info.virtual_ip <= current_device.virtual_ip { + continue; } - // 全端口范围,随机取600个端口发送 - send_f(1, 65535, 600)?; + if let Some(route) = sender.route(&info.virtual_ip) { + if route.metric == 1 { + //直连地址不需要打洞 + continue; + } + } + count += 1; + if count > 3 { + break; + } + let buf = punch_packet(current_device.virtual_ip(), &nat_info, info.virtual_ip)?; + sender.send_to_addr(&buf, current_device.connect_server)?; + } + } + match nat_info.nat_type { + NatType::Symmetric => { + thread::sleep(Duration::from_secs(28)); } NatType::Cone => { - for pub_ip in punch.public_ip_list { - udp.send_to( - buf, - SocketAddr::V4(SocketAddrV4::new( - Ipv4Addr::from(pub_ip), - punch.public_port as u16, - )), - )?; - select_sleep(&mut counter); - } - } - } - } - Ok(()) -} - -/// 给对称nat发送打洞数据包 -pub async fn req_symmetric_handler_start( - status_watch: watch::Receiver, - receiver: ReqSymmetricReceiver, - udp: UdpSocket, - cur_info: CurrentDeviceInfo, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - let receiver = receiver.0; - tokio::spawn(async move { - match handle_loop(status_watch, receiver, udp, cur_info).await { - Ok(_) => {} - Err(e) => { - log::warn!("{:?}", e) - } - } - stop_fn() - }); -} - -// pub fn req_symmetric_handle_loop( -// receiver: ReqSymmetricReceiver, -// udp: UdpSocket, -// cur_info: CurrentDeviceInfo, -// ) -> Result<()> { -// let receiver = receiver.0; -// handle_loop(receiver, udp, cur_info) -// } - -/// 给对称nat发送打洞数据包,处理主动发起的打洞操作 -pub async fn res_symmetric_handler_start( - status_watch: watch::Receiver, - receiver: ResSymmetricReceiver, - udp: UdpSocket, - cur_info: CurrentDeviceInfo, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - let receiver = receiver.0; - tokio::spawn(async move { - match res_symmetric_handle_loop(status_watch, receiver, udp, cur_info).await { - Ok(_) => {} - Err(e) => { - log::warn!("{:?}", e) - } - } - stop_fn() - }); -} - -async fn res_symmetric_handle_loop( - mut status_watch: watch::Receiver, - mut receiver: Receiver, - udp: UdpSocket, - cur_info: CurrentDeviceInfo, -) -> Result<()> { - let mut buf = [0u8; 12]; - let mut packet = NetPacket::new(&mut buf)?; - packet.set_version(Version::V1); - packet.set_ttl(255); - packet.set_protocol(Protocol::Control); - packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into()); - { - let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?; - punch_packet.set_source(cur_info.virtual_ip); - } - loop { - tokio::select! { - rs = tokio::time::timeout(Duration::from_secs(20), receiver.recv()) =>{ - match rs { - Ok(punch) => { - if let Some(punch) = punch{ - let mut list = Vec::new(); - list.push(punch); - loop { - match receiver.try_recv() { - Ok(punch) => { - list.push(punch); - } - Err(_) => { - break; - } - } - } - if let Err(e) = handle(&status_watch,&udp, list, packet.buffer()) { - log::warn!("{:?}",e) - } - }else { - return Err(Error::Stop("打洞线程通道关闭".to_string())); - } - } - Err(_) => { - punch_request_handle(&udp, &cur_info)?; - } - } - } - status = status_watch.changed() =>{ - status?; - if *status_watch.borrow() != ApplicationStatus::Starting{ - return Ok(()) - } + thread::sleep(Duration::from_secs(20)); } } } } -/// 给锥形nat发送打洞数据包 -pub async fn cone_handler_start( - status_watch: watch::Receiver, - receiver: ConeReceiver, - udp: UdpSocket, - cur_info: CurrentDeviceInfo, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - let receiver = receiver.0; - tokio::spawn(async move { - match handle_loop(status_watch, receiver, udp, cur_info).await { - Ok(_) => {} - Err(e) => { - log::warn!("{:?}", e) - } - } - stop_fn(); - }); -} - -async fn handle_loop( - mut status_watch: watch::Receiver, - mut receiver: Receiver, - udp: UdpSocket, - cur_info: CurrentDeviceInfo, -) -> Result<()> { - let mut buf = [0u8; 12]; - let mut packet = NetPacket::new(&mut buf)?; - packet.set_version(Version::V1); - packet.set_ttl(255); - packet.set_protocol(Protocol::Control); - packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into()); - { - let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?; - punch_packet.set_source(cur_info.virtual_ip); - } - loop { - tokio::select! { - punch = receiver.recv() =>{ - if let Some(punch) = punch{ - let mut list = Vec::new(); - list.push(punch); - loop { - match receiver.try_recv() { - Ok(punch) => { - list.push(punch); - } - Err(_) => { - break; - } - } - } - if let Err(e) = handle(&status_watch,&udp, list, packet.buffer()) { - log::warn!("{:?}",e) - } - }else { - return Err(Error::Stop("打洞线程通道关闭".to_string())); - } - } - status = status_watch.changed() =>{ - status?; - if *status_watch.borrow() != ApplicationStatus::Starting{ - return Ok(()) - } - } - } - } -} - -fn select_sleep(counter: &mut u64) { - *counter += 1; - if *counter & 10 == 10 { - thread::sleep(Duration::from_millis(2)); - } else { - thread::sleep(Duration::from_millis(1)); - } -} - -fn punch_request_handle(udp: &UdpSocket, cur_info: &CurrentDeviceInfo) -> Result<()> { - let nat_info_lock = NAT_INFO.lock(); - let nat_info = nat_info_lock.clone(); - drop(nat_info_lock); - if let Some(nat_info) = nat_info { - if let Err(e) = send_punch(&udp, &cur_info, nat_info) { - log::warn!("发送打洞数据失败 {:?}", e) - } - Ok(()) - } else { - Err(Error::Stop("未初始化nat信息".to_string())) - } -} - -fn send_punch(udp: &UdpSocket, cur_info: &CurrentDeviceInfo, nat_info: NatInfo) -> Result<()> { - let lock = DEVICE_LIST.lock(); - let list = lock.1.clone(); - drop(lock); - for peer_info in list { - let ip = peer_info.virtual_ip; - //只向ip比自己大的发起打洞,避免双方同时发起打洞浪费流量 - if ip > cur_info.virtual_ip && !DIRECT_ROUTE_TABLE.contains_key(&ip) { - log::info!("发起打洞 {:?}, peer_info:{:?}", nat_info, peer_info); - let bytes = punch_packet(cur_info.virtual_ip, nat_info.clone(), ip)?; - udp.send_to(&bytes, cur_info.connect_server)?; - } - } - Ok(()) -} - -fn punch_packet(virtual_ip: Ipv4Addr, nat_info: NatInfo, dest: Ipv4Addr) -> Result> { - let mut punch_reply = Punch::new(); +pub fn punch_packet(virtual_ip: Ipv4Addr, nat_info: &NatInfo, dest: Ipv4Addr) -> crate::Result> { + let mut punch_reply = PunchInfo::new(); punch_reply.reply = false; - punch_reply.virtual_ip = u32::from_be_bytes(virtual_ip.octets()); - punch_reply.public_ip_list = nat_info.public_ips; + punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| { + match i { + IpAddr::V4(ip) => { + u32::from_be_bytes(ip.octets()) + } + IpAddr::V6(_) => { + panic!() + } + } + }).collect(); punch_reply.public_port = nat_info.public_port as u32; punch_reply.public_port_range = nat_info.public_port_range as u32; - punch_reply.nat_type = protobuf::EnumOrUnknown::new(nat_info.nat_type); + punch_reply.local_ip = match nat_info.local_ip { + IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()), + IpAddr::V6(_) => { + panic!() + } + }; + punch_reply.local_port = nat_info.local_port as u32; + punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type)); let bytes = punch_reply.write_to_bytes()?; - let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?; + let mut net_packet = NetPacket::new(vec![0u8; 12 + bytes.len()])?; net_packet.set_version(Version::V1); net_packet.set_protocol(Protocol::OtherTurn); net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into()); - net_packet.set_ttl(255); - let mut turn_packet = TurnPacket::new(net_packet.payload_mut())?; - turn_packet.set_source(virtual_ip); - turn_packet.set_destination(dest); - turn_packet.set_payload(&bytes); + net_packet.first_set_ttl(MAX_TTL); + net_packet.set_source(virtual_ip); + net_packet.set_destination(dest); + net_packet.set_payload(&bytes); Ok(net_packet.into_buffer()) -} +} \ No newline at end of file diff --git a/switch/src/handle/recv_handler.rs b/switch/src/handle/recv_handler.rs new file mode 100644 index 0000000..87af326 --- /dev/null +++ b/switch/src/handle/recv_handler.rs @@ -0,0 +1,385 @@ +use std::{io, thread}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::sync::Arc; + +use chrono::Local; +use crossbeam::atomic::AtomicCell; +use crossbeam_skiplist::SkipMap; +use parking_lot::Mutex; +use protobuf::Message; + +use nat_traversal::channel::{Channel, Route, RouteKey}; +use nat_traversal::punch::NatInfo; +use packet::icmp::{icmp, Kind}; +use packet::ip::ipv4; +use packet::ip::ipv4::packet::IpV4Packet; + +use crate::error::Error; +use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo}; +use crate::handle::registration_handler::Register; +use crate::nat::NatTest; +use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationResponse}; +use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, service_packet, turn_packet, Version}; +use crate::protocol::control_packet::ControlPacket; +use crate::protocol::error_packet::InErrorPacket; +use crate::tun_device::TunWriter; + +pub fn start(mut handler: RecvHandler) { + thread::spawn(move || { + let mut buf = [0; 4096]; + loop { + match handler.channel.recv_from(&mut buf, None) { + Ok((len, route)) => { + if let Err(e) = handler.handle(&mut buf[..len], &route) { + log::warn!("数据处理失败:{:?},e:{:?}",route,e); + if let Error::Stop(_) = e { + let _ = handler.channel.close(); + break; + } + } + } + Err(e) => { + log::warn!("{:?}",e); + // 检查关闭状态 + if handler.channel.is_close() { + break; + } + } + } + } + }); +} + +pub struct RecvHandler { + channel: Channel, + current_device: Arc>, + device_list: Arc)>>, + register: Arc, + nat_test: NatTest, + tun_writer: TunWriter, + connect_status: Arc>, + peer_nat_info_map: Arc>, +} + +impl RecvHandler { + pub fn new(channel: Channel, + current_device: Arc>, + device_list: Arc)>>, + register: Arc, + nat_test: NatTest, + tun_writer: TunWriter, + connect_status: Arc>, + peer_nat_info_map: Arc>, + ) -> Self { + Self { + channel, + current_device, + device_list, + register, + nat_test, + tun_writer, + connect_status, + peer_nat_info_map, + } + } + pub fn try_clone(&self) -> io::Result { + Ok(Self { + channel: self.channel.try_clone()?, + current_device: self.current_device.clone(), + device_list: self.device_list.clone(), + register: self.register.clone(), + nat_test: self.nat_test.clone(), + tun_writer: self.tun_writer.clone(), + connect_status: self.connect_status.clone(), + peer_nat_info_map: self.peer_nat_info_map.clone(), + }) + } +} + +impl RecvHandler { + fn handle(&self, buf: &mut [u8], route_key: &RouteKey) -> crate::Result<()> { + let mut net_packet = NetPacket::new(buf)?; + if net_packet.ttl() == 0 { + return Ok(()); + } + let source = net_packet.source(); + let current_device = self.current_device.load(); + if source == current_device.virtual_ip() { + return Ok(()); + } + let destination = net_packet.destination(); + if current_device.virtual_ip() != destination && self.connect_status.load() == ConnectStatus::Connected { + if !check_dest(source, current_device.virtual_netmask, current_device.virtual_network) { + log::warn!("转发数据,源地址错误:{:?},当前网络:{:?},route_key:{:?}",source,current_device.virtual_network,route_key); + return Ok(()); + } + if !check_dest(destination, current_device.virtual_netmask, current_device.virtual_network) { + log::warn!("转发数据,目的地址错误:{:?},当前网络:{:?},route_key:{:?}",destination,current_device.virtual_network,route_key); + return Ok(()); + } + let ttl = net_packet.ttl(); + if ttl > 1 { + // 转发 + net_packet.set_ttl(ttl - 1); + if let Some(route) = self.channel.route(&destination) { + if route.metric <= net_packet.ttl() { + self.channel.send_to_route(net_packet.buffer(), &route.route_key())?; + } + } else if (ttl > 2 || destination == current_device.virtual_gateway()) + && source != current_device.virtual_gateway() { + //网关默认要转发一次,生存时间不够的发到网关也会被丢弃 + self.channel.send_to_addr(net_packet.buffer(), current_device.connect_server)?; + } + } + return Ok(()); + } + match net_packet.protocol() { + Protocol::Ipv4Turn => { + let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?; + if ipv4.protocol() == ipv4::protocol::Protocol::Icmp { + let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?; + if icmp_packet.kind() == Kind::EchoRequest { + //开启ping + icmp_packet.set_kind(Kind::EchoReply); + icmp_packet.update_checksum(); + ipv4.set_source_ip(destination); + ipv4.set_destination_ip(source); + ipv4.update_checksum(); + net_packet.set_source(destination); + net_packet.set_destination(source); + self.channel.send_to_route(net_packet.buffer(), route_key)?; + return Ok(()); + } + } + self.tun_writer.write(net_packet.payload())?; + } + Protocol::Service => { + self.service(current_device, source, net_packet, route_key)?; + } + Protocol::Error => { + self.error(current_device, source, net_packet, route_key)?; + } + Protocol::Control => { + self.control(current_device, source, net_packet, route_key)?; + } + Protocol::OtherTurn => { + self.other_turn(current_device, source, net_packet, route_key)?; + } + Protocol::UnKnow(e) => { + log::info!("不支持的协议:{}",e); + } + } + Ok(()) + } + fn service(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> { + if route_key.addr != current_device.connect_server || source != current_device.virtual_gateway() { + return Ok(()); + } + match service_packet::Protocol::from(net_packet.transport_protocol()) { + service_packet::Protocol::RegistrationRequest => {} + service_packet::Protocol::RegistrationResponse => { + let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?; + let local_addr = self.channel.local_addr()?; + let local_ip = if local_addr.ip().is_unspecified() { + local_ip_address::local_ip().unwrap_or(local_addr.ip()) + } else { + local_addr.ip() + }; + let nat_info = self.nat_test.re_test(Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_addr.port()); + self.channel.set_nat_type(nat_info.nat_type)?; + let new_ip = Ipv4Addr::from(response.virtual_ip); + let current_ip = current_device.virtual_ip(); + if current_ip != new_ip { + // ip发生变化 + log::info!("ip发生变化,old_ip:{:?},new_ip:{:?}",current_ip,new_ip); + let old_netmask = current_device.virtual_netmask; + let old_gateway = current_device.virtual_gateway(); + let virtual_ip = Ipv4Addr::from(response.virtual_ip); + let virtual_gateway = Ipv4Addr::from(response.virtual_gateway); + let virtual_netmask = Ipv4Addr::from(response.virtual_netmask); + self.tun_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?; + let new_current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, + virtual_netmask, current_device.connect_server); + if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) { + log::warn!("替换失败:{:?}",e); + } + } + self.connect_status.store(ConnectStatus::Connected); + } + service_packet::Protocol::PollDeviceList => {} + service_packet::Protocol::PushDeviceList => { + let device_list_t = DeviceList::parse_from_bytes(net_packet.payload())?; + let ip_list = device_list_t + .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 = self.device_list.lock(); + if dev.0 < device_list_t.epoch as u16 || device_list_t.epoch as u16 - dev.0 > u16::MAX >> 2 { + dev.0 = device_list_t.epoch as u16; + dev.1 = ip_list; + } + } + service_packet::Protocol::UnKnow(u) => { + log::warn!("未知服务协议:{}",u); + } + } + Ok(()) + } + fn error(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> { + if route_key.addr != current_device.connect_server || source != current_device.virtual_gateway() { + return Ok(()); + } + match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? { + InErrorPacket::TokenError => { + return Err(Error::Stop("Token error".to_string())); + } + InErrorPacket::Disconnect => { + self.connect_status.store(ConnectStatus::Connecting); + self.register.fast_register()?; + } + InErrorPacket::AddressExhausted => { + //地址用尽 + return Err(Error::Stop("IP address has been exhausted".to_string())); + } + InErrorPacket::OtherError(e) => { + log::error!("OtherError {:?}", e.message()); + } + } + Ok(()) + } + fn control(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, mut net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> { + match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? { + ControlPacket::PingPacket(_) => { + net_packet.set_transport_protocol(control_packet::Protocol::Pong.into()); + net_packet.set_source(current_device.virtual_ip()); + net_packet.set_destination(source); + net_packet.first_set_ttl(MAX_TTL); + self.channel.send_to_route(net_packet.buffer(), route_key)?; + } + ControlPacket::PongPacket(pong_packet) => { + let current_time = Local::now().timestamp_millis() as u16; + if current_time < pong_packet.time() { + return Ok(()); + } + let rt = (current_time - pong_packet.time()) as i64; + let metric = net_packet.source_ttl() - net_packet.ttl() + 1; + if let Some(current_route) = self.channel.route(&source) { + if ¤t_route.route_key() == route_key { + self.channel.update_route(&source, metric, rt); + } else if current_route.metric >= metric && current_route.rt > rt { + let route = Route::from(*route_key, metric, rt); + self.channel.add_route(source, route); + } + } else { + let route = Route::from(*route_key, metric, rt); + self.channel.add_route(source, route); + } + if route_key.addr == current_device.connect_server && source == current_device.virtual_gateway() { + let epoch = self.device_list.lock().0; + if pong_packet.epoch() != epoch { + let mut poll_device = NetPacket::new([0; 12])?; + poll_device.set_source(current_device.virtual_ip()); + poll_device.set_destination(source); + poll_device.set_version(Version::V1); + poll_device.first_set_ttl(MAX_TTL); + poll_device.set_protocol(Protocol::Service); + poll_device.set_transport_protocol(service_packet::Protocol::PollDeviceList.into()); + self.channel.send_to_route(poll_device.buffer(), route_key)?; + } + } + } + ControlPacket::PunchRequest => { + log::info!("PunchRequest route_key:{:?}",route_key); + //回应 + net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into()); + net_packet.set_source(current_device.virtual_ip()); + net_packet.set_destination(source); + net_packet.first_set_ttl(1); + self.channel.send_to_route(net_packet.buffer(), route_key)?; + let route = Route::from(*route_key, 1, -1); + self.channel.add_route(source, route); + } + ControlPacket::PunchResponse => { + log::info!("PunchResponse route_key:{:?}",route_key); + let route = Route::from(*route_key, 1, -1); + self.channel.add_route(net_packet.source(), route); + } + } + Ok(()) + } + fn other_turn(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> { + match turn_packet::Protocol::from(net_packet.transport_protocol()) { + turn_packet::Protocol::Punch => { + let punch_info = PunchInfo::parse_from_bytes(net_packet.payload())?; + let public_ips = punch_info.public_ip_list. + iter().map(|v| { IpAddr::from(v.to_be_bytes()) }).collect(); + let peer_nat_info = NatInfo::new(public_ips, + punch_info.public_port as u16, + punch_info.public_port_range as u16, + IpAddr::from(punch_info.local_ip.to_be_bytes()), + punch_info.local_port as u16, + punch_info.nat_type.enum_value_or_default().into()); + self.peer_nat_info_map.insert(source, peer_nat_info.clone()); + if !punch_info.reply { + let mut punch_reply = PunchInfo::new(); + punch_reply.reply = true; + let nat_info = self.nat_test.nat_info(); + punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| { + match i { + IpAddr::V4(ip) => { + u32::from_be_bytes(ip.octets()) + } + IpAddr::V6(_) => { + panic!() + } + } + }).collect(); + punch_reply.public_port = nat_info.public_port as u32; + punch_reply.public_port_range = nat_info.public_port_range as u32; + punch_reply.nat_type = + protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type)); + let bytes = punch_reply.write_to_bytes()?; + let mut net_packet = + NetPacket::new(vec![0u8; 12 + bytes.len()])?; + net_packet.set_version(Version::V1); + net_packet.set_protocol(Protocol::OtherTurn); + net_packet.set_transport_protocol( + turn_packet::Protocol::Punch.into(), + ); + net_packet.first_set_ttl(MAX_TTL); + 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() { + let mut packet = NetPacket::new([0u8; 12])?; + packet.set_version(Version::V1); + packet.first_set_ttl(1); + packet.set_protocol(Protocol::Control); + packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into()); + packet.set_source(current_device.virtual_ip()); + packet.set_destination(source); + let _ = self.channel.send_to_addr(packet.buffer(), SocketAddr::new(peer_nat_info.local_ip, peer_nat_info.local_port)); + } + if let Err(e) = self.channel.punch(source, peer_nat_info) { + log::warn!("发送到打洞通道失败 {:?}",e); + return Ok(()); + } + self.channel.send_to_route(net_packet.buffer(), route_key)?; + } else { + let _ = self.channel.punch(source, peer_nat_info); + } + } + turn_packet::Protocol::UnKnow(e) => { + log::warn!("不支持的转发协议 {:?},source:{:?}",e,source); + } + } + Ok(()) + } +} \ No newline at end of file diff --git a/switch/src/handle/registration_handler.rs b/switch/src/handle/registration_handler.rs index b98ccfb..50b43fa 100644 --- a/switch/src/handle/registration_handler.rs +++ b/switch/src/handle/registration_handler.rs @@ -1,139 +1,136 @@ use std::io; -use std::net::{SocketAddr, UdpSocket}; +use std::net::{Ipv4Addr, SocketAddr}; use std::sync::atomic::{AtomicI64, Ordering}; use std::time::Duration; use chrono::Local; -use crossbeam::atomic::AtomicCell; -use parking_lot::RwLock; use protobuf::Message; +use nat_traversal::channel::Channel; +use nat_traversal::channel::sender::Sender; use crate::error::*; -use crate::handle::ConnectStatus; use crate::proto::message::{RegistrationRequest, RegistrationResponse}; use crate::protocol::error_packet::InErrorPacket; -use crate::protocol::{service_packet, NetPacket, Protocol, Version}; +use crate::protocol::{service_packet, NetPacket, Protocol, Version, MAX_TTL}; -lazy_static::lazy_static! { - static ref REQUEST:RwLock> = parking_lot::const_rwlock(None); - static ref REGISTRATION_TIME:AtomicI64=AtomicI64::new(0); - pub(crate) static ref CONNECTION_STATUS:AtomicCell = AtomicCell::new(ConnectStatus::Connecting); -} - -///向中继服务器注册,token标识一个虚拟网关,mac_address防止多次注册时得到的ip不一致 +///向中继服务器注册,token标识一个虚拟网关,device_id防止多次注册时得到的ip不一致 pub fn registration( - udp: &UdpSocket, + channel: &mut Channel, server_address: SocketAddr, token: String, - mac_address: String, + device_id: String, name: String, ) -> Result { - // todo 和服务器通信加密 let request_packet = - registration_request_packet(token.clone(), mac_address.clone(), name.clone(), false)?; + registration_request_packet(token.clone(), device_id.clone(), name.clone(), false)?; let buf = request_packet.buffer(); - let mut counter = 0; let mut recv_buf = [0u8; 10240]; - udp.set_read_timeout(Some(Duration::from_millis(500)))?; - loop { - counter += 1; - if counter & 10 == 10 { - return Err(Error::Stop("注册请求超时".to_string())); - } - udp.send_to(buf, server_address)?; - let (len, addr) = match udp.recv_from(&mut recv_buf) { - Ok(ok) => ok, - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut { - continue; - } - return Err(Error::Io(e)); - } - }; - if server_address != addr { - continue; - } - let net_packet = NetPacket::new(&recv_buf[..len])?; - match net_packet.protocol() { - Protocol::Service => { - match service_packet::Protocol::from(net_packet.transport_protocol()) { - service_packet::Protocol::RegistrationResponse => { - let response = - RegistrationResponse::parse_from_bytes(net_packet.payload())?; - let _ = REQUEST.write().replace((token, mac_address, name)); - udp.set_read_timeout(None)?; - CONNECTION_STATUS.store(ConnectStatus::Connected); - return Ok(response); - } - _ => {} - } - } - Protocol::Error => { - return match InErrorPacket::new( - net_packet.transport_protocol(), - net_packet.payload(), - ) { - Ok(e) => match e { - InErrorPacket::TokenError => Err(Error::Stop("token错误".to_string())), - InErrorPacket::Disconnect => Err(Error::Stop("断开连接".to_string())), - InErrorPacket::AddressExhausted => Err(Error::Stop("地址用尽".to_string())), - InErrorPacket::OtherError(e) => match e.message() { - Ok(str) => Err(Error::Stop(str)), - Err(e) => Err(Error::Stop(format!("{:?}", e))), - }, - }, - Err(e) => Err(Error::Stop(format!("{:?}", e))), - }; - } - _ => { - return Err(Error::Stop(format!("数据错误:{:?}", net_packet))); - } - } + channel.send_to_addr(buf, server_address)?; + let (len, route) = channel.recv_from(&mut recv_buf, Some(Duration::from_millis(300)))?; + if server_address != route.addr { + return Err(Error::Warn(format!("数据来源错误:{:?}", route.addr))); } + let net_packet = NetPacket::new(&recv_buf[..len])?; + return match net_packet.protocol() { + Protocol::Service => { + match service_packet::Protocol::from(net_packet.transport_protocol()) { + service_packet::Protocol::RegistrationResponse => { + let response = + RegistrationResponse::parse_from_bytes(net_packet.payload())?; + Ok(response) + } + _ => { + Err(Error::Warn(format!("数据错误:{:?}", net_packet))) + } + } + } + Protocol::Error => { + match InErrorPacket::new( + net_packet.transport_protocol(), + net_packet.payload(), + ) { + Ok(e) => match e { + InErrorPacket::TokenError => Err(Error::Stop("token错误".to_string())), + InErrorPacket::Disconnect => Err(Error::Warn("断开连接".to_string())), + InErrorPacket::AddressExhausted => Err(Error::Stop("地址用尽".to_string())), + InErrorPacket::OtherError(e) => match e.message() { + Ok(str) => Err(Error::Warn(str)), + Err(e) => Err(Error::Warn(format!("{:?}", e))), + }, + }, + Err(e) => Err(Error::Warn(format!("{:?}", e))), + } + } + _ => { + Err(Error::Warn(format!("数据错误:{:?}", net_packet))) + } + }; } fn registration_request_packet( token: String, - mac_address: String, + device_id: String, name: String, is_fast: bool, -) -> Result>> { +) -> crate::Result>> { let mut request = RegistrationRequest::new(); request.token = token; - request.mac_address = mac_address; + request.device_id = device_id; request.name = name; request.is_fast = is_fast; let bytes = request.write_to_bytes()?; - let buf = vec![0u8; 4 + bytes.len()]; + let buf = vec![0u8; 12 + bytes.len()]; let mut net_packet = NetPacket::new(buf)?; net_packet.set_version(Version::V1); net_packet.set_protocol(Protocol::Service); net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into()); - net_packet.set_ttl(255); + net_packet.first_set_ttl(MAX_TTL); net_packet.set_payload(&bytes); Ok(net_packet) } -pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result<()> { - let last = REGISTRATION_TIME.load(Ordering::Relaxed); - let new = Local::now().timestamp_millis(); - if new - last < 2000 - || REGISTRATION_TIME +pub struct Register { + sender: Sender, + server_address: SocketAddr, + token: String, + device_id: String, + name: String, + time: AtomicI64, +} + +impl Register { + pub fn new(sender: Sender, + server_address: SocketAddr, + token: String, + device_id: String, + name: String, ) -> Self { + Self { + sender, + server_address, + token, + device_id, + name, + time: AtomicI64::new(0), + } + } + pub fn fast_register(&self) -> io::Result<()> { + let last = self.time.load(Ordering::Relaxed); + let new = Local::now().timestamp_millis(); + if new - last < 1000 + || self.time .compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed) .is_err() - { - //短时间不重复注册 - return Ok(()); + { + //短时间不重复注册 + return Ok(()); + } + log::info!("重新连接"); + let request_packet = + registration_request_packet(self.token.clone(), + self.device_id.clone(), + self.name.clone(), false).unwrap(); + let buf = request_packet.buffer(); + self.sender.send_to_addr(buf, self.server_address)?; + Ok(()) } - CONNECTION_STATUS.store(ConnectStatus::Connecting); - let lock = REQUEST.read(); - let option = lock.clone(); - drop(lock); - if let Some((token, mac_address, name)) = option { - let request_packet = registration_request_packet(token, mac_address, name, true)?; - udp.send_to(request_packet.buffer(), server_address)?; - REGISTRATION_TIME.store(Local::now().timestamp_millis(), Ordering::Relaxed); - return Ok(()); - } - return Err(Error::Stop("注册信息不存在".to_string())); } diff --git a/switch/src/handle/tun_handler.rs b/switch/src/handle/tun_handler.rs index d3b20a4..e0d3af4 100644 --- a/switch/src/handle/tun_handler.rs +++ b/switch/src/handle/tun_handler.rs @@ -1,29 +1,22 @@ +use std::{io, thread}; /// 接收tun数据,并且转发到udp上 -use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; -use std::thread; - -use chrono::Local; -use tokio::sync::watch; +use std::net::Ipv4Addr; +use std::sync::Arc; +use crossbeam::atomic::AtomicCell; +use nat_traversal::channel::sender::Sender; use packet::icmp::icmp::IcmpPacket; use packet::icmp::Kind; use packet::ip::ipv4; use packet::ip::ipv4::packet::IpV4Packet; use crate::error::*; -use crate::handle::{CurrentDeviceInfo, DIRECT_ROUTE_TABLE}; -use crate::protocol::turn_packet::TurnPacket; -use crate::protocol::{NetPacket, Protocol, Version}; -use crate::tun_device::TunReader; -use crate::ApplicationStatus; +use crate::handle::{check_dest, CurrentDeviceInfo}; +use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version}; +use crate::tun_device::{TunReader, TunWriter}; -/// 是否在一个网段 -fn check_dest(dest: Ipv4Addr, cur_info: &CurrentDeviceInfo) -> bool { - u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(cur_info.virtual_netmask.octets()) - == u32::from_be_bytes(cur_info.virtual_network.octets()) -} -fn icmp(udp: &UdpSocket, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> { +fn icmp(tun_writer: &TunWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> { if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp { let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?; if icmp.kind() == Kind::EchoRequest { @@ -33,21 +26,14 @@ fn icmp(udp: &UdpSocket, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> { ipv4_packet.set_source_ip(ipv4_packet.destination_ip()); ipv4_packet.set_destination_ip(src); ipv4_packet.update_checksum(); - let mut addr = udp.local_addr()?; - addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - udp.send_to(ipv4_packet.buffer, addr)?; + tun_writer.write(ipv4_packet.buffer)?; } } Ok(()) } #[inline] -fn handle( - udp: &UdpSocket, - data: &mut [u8], - cur_info: &CurrentDeviceInfo, - net_packet: &mut NetPacket>, -) -> Result<()> { +fn handle(sender: &Sender, data: &mut [u8], tun_writer: &TunWriter, current_device: CurrentDeviceInfo, net_packet: &mut NetPacket>) -> Result<()> { let data_len = data.len(); let ipv4_packet = match IpV4Packet::new(data) { Ok(ipv4_packet) => ipv4_packet, @@ -63,135 +49,49 @@ fn handle( // // 137端口是在局域网中提供计算机的名字或IP地址查询服务 // return Ok(()); // } - if src_ip != cur_info.virtual_ip || !check_dest(dest_ip, &cur_info) { + if src_ip != current_device.virtual_ip() || !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) { return Ok(()); } if src_ip == dest_ip { - return icmp(&udp, ipv4_packet); + return icmp(&tun_writer, ipv4_packet); } - let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?; - ipv4_turn_packet.set_source(src_ip); - ipv4_turn_packet.set_destination(dest_ip); - ipv4_turn_packet.set_payload(ipv4_packet.buffer); + net_packet.set_source(src_ip); + net_packet.set_destination(dest_ip); + net_packet.set_payload(ipv4_packet.buffer); //优先发到直连到地址 - if let Some(route) = DIRECT_ROUTE_TABLE.get(&dest_ip) { - let current_time = Local::now().timestamp_millis(); - if current_time - route.recv_time < 3_000 { - if udp - .send_to(&net_packet.buffer()[..(4 + 8 + data_len)], route.address) - .is_ok() - { - return Ok(()); - } - } + 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)?; } - udp.send_to( - &net_packet.buffer()[..(4 + 8 + data_len)], - cur_info.connect_server, - )?; return Ok(()); } -#[cfg(target_os = "windows")] -pub async fn handler_start( - mut status_watch: watch::Receiver, - udp: UdpSocket, - tun_reader: TunReader, - cur_info: CurrentDeviceInfo, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - let session = tun_reader.0.clone(); - tokio::spawn(async move { - let _ = status_watch.changed().await; - session.shutdown(); - let udp = UdpSocket::bind("0.0.0.0:0").unwrap(); - let _ = udp.send_to( - &[0], - SocketAddr::new(IpAddr::V4(cur_info.virtual_gateway), 10), - ); - }); +pub fn start(sender: Sender, + tun_reader: TunReader, + tun_writer: TunWriter, + current_device: Arc>, ) { thread::spawn(move || { - if let Err(e) = handle_loop(udp, tun_reader, cur_info) { - log::warn!("tun数据处理线程停止 {:?}", e); + if let Err(e) = start_(sender, tun_reader, tun_writer, current_device) { + log::warn!("{:?}",e); } - stop_fn(); }); } -#[cfg(target_os = "windows")] -fn handle_loop(udp: UdpSocket, tun_reader: TunReader, cur_info: CurrentDeviceInfo) -> Result<()> { +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(255); + net_packet.set_ttl(MAX_TTL); loop { let mut data = tun_reader.next()?; - match handle(&udp, data.bytes_mut(), &cur_info, &mut net_packet) { + match handle(&sender, data.bytes_mut(), &tun_writer, current_device.load(), &mut net_packet) { Ok(_) => {} Err(e) => { log::warn!("{:?}", e) } } } -} - -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "android"))] -pub async fn handler_start( - mut status_watch: watch::Receiver, - udp: UdpSocket, - tun_reader: TunReader, - cur_info: CurrentDeviceInfo, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - #[cfg(target_os = "macos")] - use std::os::fd::AsRawFd; - #[cfg(target_os = "linux")] - use std::os::unix::io::AsRawFd; - let raw_fd = tun_reader.0.as_raw_fd(); - tokio::spawn(async move { - let _ = status_watch.changed().await; - // 让tun接收线程关闭,问题:如果改变tun配置,可能导致tun接收线程无法关闭 - unsafe { - libc::close(raw_fd); - } - let udp = UdpSocket::bind("0.0.0.0:0").unwrap(); - let _ = udp.send_to( - &[0], - SocketAddr::new(IpAddr::V4(cur_info.virtual_gateway), 10), - ); - }); - thread::spawn(move || { - if let Err(e) = handle_loop(udp, tun_reader, cur_info) { - log::warn!(" tun数据处理线程停止 {:?}", e); - } - stop_fn(); - }); -} - -#[cfg(any(target_os = "macos", target_os = "linux", target_os = "android"))] -pub fn handle_loop( - udp: UdpSocket, - mut tun_reader: TunReader, - cur_info: CurrentDeviceInfo, -) -> 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(0); - net_packet.set_ttl(255); - let mut buf = [0u8; 1500]; - loop { - let data = tun_reader.read(&mut buf)?; - match handle(&udp, data, &cur_info, &mut net_packet) { - Ok(_) => {} - Err(e) => { - log::warn!("{:?}", e) - } - } - } -} +} \ No newline at end of file diff --git a/switch/src/handle/udp_recv_handler.rs b/switch/src/handle/udp_recv_handler.rs deleted file mode 100644 index ef06650..0000000 --- a/switch/src/handle/udp_recv_handler.rs +++ /dev/null @@ -1,389 +0,0 @@ -use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; -use std::sync::atomic::Ordering; -use std::thread; - -use chrono::Local; -use packet::icmp::{icmp, Kind}; -use packet::ip::ipv4; -use packet::ip::ipv4::packet::IpV4Packet; -use protobuf::Message; -use tokio::sync::mpsc::error::TrySendError; -use tokio::sync::mpsc::{Receiver, Sender}; -use tokio::sync::watch; - -use crate::error::*; -use crate::handle::punch_handler::PunchSender; -use crate::handle::registration_handler::{fast_registration, CONNECTION_STATUS}; -use crate::handle::{ - ConnectStatus, Route, ADDR_TABLE, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, SERVER_RT, -}; -use crate::proto::message::{DeviceList, Punch, RegistrationResponse}; -use crate::protocol::control_packet::{ControlPacket, PunchResponsePacket}; -use crate::protocol::error_packet::InErrorPacket; -use crate::protocol::turn_packet::TurnPacket; -use crate::protocol::{control_packet, service_packet, turn_packet, NetPacket, Protocol, Version}; -use crate::tun_device::TunWriter; -use crate::{ApplicationStatus, CurrentDeviceInfo, PeerDeviceInfo}; - -const UDP_STOP_BUF: [u8; 1] = [0u8]; - -pub async fn udp_recv_start( - mut status_watch: watch::Receiver, - udp: UdpSocket, - server_addr: SocketAddr, - other_sender: Sender<(SocketAddr, Vec)>, - tun_writer: TunWriter, - current_device: CurrentDeviceInfo, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - { - let udp = udp.try_clone().unwrap(); - tokio::spawn(async move { - let _ = status_watch.changed().await; - let mut addr = udp.local_addr().unwrap(); - addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - udp.send_to(&UDP_STOP_BUF, addr).unwrap(); - }); - } - - thread::spawn(move || { - if let Err(e) = recv_loop(udp, server_addr, other_sender, tun_writer, current_device) { - log::warn!("udp数据处理线程停止 {:?}", e); - } - stop_fn(); - }); -} - -fn recv_loop( - udp: UdpSocket, - server_addr: SocketAddr, - other_sender: Sender<(SocketAddr, Vec)>, - mut tun_writer: TunWriter, - current_device: CurrentDeviceInfo, -) -> Result<()> { - let mut buf = [0u8; 65536]; - let mut local_addr = udp.local_addr()?; - local_addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); - loop { - match udp.recv_from(&mut buf) { - Ok((len, addr)) => { - if addr == local_addr { - if len == 1 && &buf[..len] == &UDP_STOP_BUF { - return Ok(()); - } - //本地的包直接再发到网卡,这个主要用于处理当前虚拟ip的icmp ping - if let Ok(ip) = IpV4Packet::new(&buf[..len]) { - if ip.destination_ip() == current_device.virtual_ip { - let _ = tun_writer.write(&buf[..len]); - } - } - continue; - } - match recv_handle( - &udp, - addr, - &mut buf[..len], - &server_addr, - &other_sender, - &mut tun_writer, - ¤t_device, - ) { - Ok(_) => {} - Err(Error::Stop(str)) => { - return Err(Error::Stop(str)); - } - Err(e) => { - log::warn!("{:?}", e); - } - } - } - Err(e) => { - log::warn!("{:?}", e); - } - }; - } -} - -fn recv_handle( - udp: &UdpSocket, - recv_addr: SocketAddr, - buf: &mut [u8], - _server_addr: &SocketAddr, - other_sender: &Sender<(SocketAddr, Vec)>, - tun_writer: &mut TunWriter, - current_device: &CurrentDeviceInfo, -) -> Result<()> { - let mut net_packet = NetPacket::new(buf)?; - match net_packet.protocol() { - Protocol::Ipv4Turn => { - let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?; - let source = ipv4_turn_packet.source(); - let destination = ipv4_turn_packet.destination(); - let mut ipv4 = IpV4Packet::new(ipv4_turn_packet.payload_mut())?; - if ipv4.source_ip() == source - && ipv4.destination_ip() == destination - && current_device.virtual_ip == ipv4.destination_ip() - { - if ipv4.protocol() == ipv4::protocol::Protocol::Icmp { - let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?; - if icmp_packet.kind() == Kind::EchoRequest { - //开启ping - icmp_packet.set_kind(Kind::EchoReply); - icmp_packet.update_checksum(); - ipv4.set_source_ip(destination); - ipv4.set_destination_ip(source); - ipv4.update_checksum(); - ipv4_turn_packet.set_source(destination); - ipv4_turn_packet.set_destination(source); - udp.send_to(net_packet.buffer(), recv_addr)?; - } else { - tun_writer.write(ipv4_turn_packet.payload())?; - } - } else { - tun_writer.write(ipv4_turn_packet.payload())?; - } - } - } - Protocol::UnKnow(_) => {} - _ => { - //发送到子线程处理 - let v = net_packet.buffer().to_vec(); - match other_sender.try_send((recv_addr, v)) { - Ok(_) => {} - Err(TrySendError::Closed(_)) => { - return Err(Error::Stop("子处理线程停止".to_string())); - } - Err(e) => { - log::warn!("子线程处理 {:?}", e); - } - } - } - } - Ok(()) -} - -pub async fn udp_other_recv_start( - status_watch: watch::Receiver, - udp: UdpSocket, - receiver: Receiver<(SocketAddr, Vec)>, - current_device: CurrentDeviceInfo, - sender: PunchSender, - stop_fn: F, -) where - F: FnOnce() + Send + 'static, -{ - tokio::spawn(async move { - match other_loop(status_watch, udp, receiver, current_device, sender).await { - Ok(_) => { - log::info!("udp子处理线程停止"); - } - Err(e) => { - log::warn!("{:?}", e); - } - } - stop_fn(); - }); -} - -async fn other_loop( - mut status_watch: watch::Receiver, - udp: UdpSocket, - mut receiver: Receiver<(SocketAddr, Vec)>, - current_device: CurrentDeviceInfo, - sender: PunchSender, -) -> Result<()> { - loop { - tokio::select! { - rs = receiver.recv()=>{ - if let Some((peer_addr, buf)) = rs { - match other_handle(&udp, buf, peer_addr, ¤t_device, &sender) { - Ok(_) => {} - Err(Error::Stop(str)) => { - return Err(Error::Stop(str)); - } - Err(e) => { - log::warn!("other_loop {:?}",e); - } - } - } - } - status = status_watch.changed() =>{ - status?; - if *status_watch.borrow() != ApplicationStatus::Starting{ - return Ok(()) - } - } - } - } -} - -fn other_handle( - udp: &UdpSocket, - buf: Vec, - peer_addr: SocketAddr, - current_device: &CurrentDeviceInfo, - sender: &PunchSender, -) -> Result<()> { - let server_addr = current_device.connect_server; - let mut net_packet = NetPacket::new(buf)?; - match net_packet.protocol() { - Protocol::Service => { - if peer_addr != current_device.connect_server { - return Ok(()); - } - match service_packet::Protocol::from(net_packet.transport_protocol()) { - service_packet::Protocol::RegistrationRequest => {} - service_packet::Protocol::RegistrationResponse => { - let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?; - crate::handle::init_nat_info(response.public_ip, response.public_port as u16); - CONNECTION_STATUS.store(ConnectStatus::Connected); - //需要保证重连ip不变 - } - service_packet::Protocol::UpdateDeviceList => { - let device_list = DeviceList::parse_from_bytes(net_packet.payload())?; - let ip_list = device_list - .device_info_list - .into_iter() - .map(|info| { - PeerDeviceInfo::new( - Ipv4Addr::from(info.virtual_ip), - info.name, - info.device_status as u8, - ) - }) - .collect(); - let mut dev = DEVICE_LIST.lock(); - if dev.0 < device_list.epoch || device_list.epoch - dev.0 > u32::MAX >> 2 { - dev.0 = device_list.epoch; - dev.1 = ip_list; - } - } - service_packet::Protocol::UnKnow(_) => {} - } - } - Protocol::Error => { - match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? { - InErrorPacket::TokenError => { - if server_addr == peer_addr { - //停止整个应用 - return Err(Error::Stop("token无效".to_string())); - } - } - InErrorPacket::Disconnect => { - if server_addr == peer_addr { - fast_registration(&udp, server_addr)?; - } - } - InErrorPacket::AddressExhausted => { - return Err(Error::Stop("IP address has been exhausted".to_string())); - } - InErrorPacket::OtherError(e) => { - log::error!("OtherError {:?}", e.message()); - } - } - } - Protocol::Control => { - match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? { - ControlPacket::PingPacket(_ping) => { - net_packet.set_transport_protocol(control_packet::Protocol::Pong.into()); - udp.send_to(&net_packet.buffer()[..12], peer_addr)?; - } - ControlPacket::PongPacket(pong_packet) => { - let current_time = Local::now().timestamp_millis(); - let rt = current_time - pong_packet.time(); - if rt >= 0 { - if peer_addr == server_addr { - SERVER_RT.store(rt, Ordering::Relaxed) - } else { - //其他设备 - if let Some(virtual_ip) = ADDR_TABLE.get(&peer_addr) { - if let Some(mut info) = DIRECT_ROUTE_TABLE.get_mut(&virtual_ip) { - info.rt = rt; - info.recv_time = current_time; - } - } - } - } - } - ControlPacket::PunchRequest(punch_request) => { - // println!("打洞请求:{:?}", punch_request); - let src = punch_request.source(); - drop(punch_request); - //回应 - let mut punch_response = PunchResponsePacket::new(net_packet.payload_mut())?; - punch_response.set_source(current_device.virtual_ip); - net_packet - .set_transport_protocol(control_packet::Protocol::PunchResponse.into()); - udp.send_to(net_packet.buffer(), peer_addr)?; - let route = Route::new(peer_addr); - DIRECT_ROUTE_TABLE.insert(src, route); - ADDR_TABLE.insert(peer_addr, src); - } - ControlPacket::PunchResponse(punch_response) => { - // println!("打洞响应:{:?}", punch_response); - let route = Route::new(peer_addr); - DIRECT_ROUTE_TABLE.insert(punch_response.source(), route); - ADDR_TABLE.insert(peer_addr, punch_response.source()); - } - } - } - Protocol::Ipv4Turn => {} - Protocol::OtherTurn => { - let turn_packet = TurnPacket::new(net_packet.payload())?; - // println!("{:?}",turn_packet); - let src = turn_packet.source(); - let dest = turn_packet.destination(); - if dest == current_device.virtual_ip { - match turn_packet::Protocol::from(net_packet.transport_protocol()) { - turn_packet::Protocol::Punch => { - let punch = Punch::parse_from_bytes(turn_packet.payload())?; - if punch.virtual_ip.to_be_bytes() == src.octets() { - if !punch.reply { - let mut punch_reply = Punch::new(); - punch_reply.reply = true; - punch_reply.virtual_ip = - u32::from_be_bytes(current_device.virtual_ip.octets()); - if let Err(_) = sender.try_send(punch) { - return Ok(()); - } - let nat_info = NAT_INFO.lock(); - if let Some(info) = nat_info.as_ref() { - punch_reply.public_ip_list = info.public_ips.clone(); - punch_reply.public_port = info.public_port as u32; - punch_reply.public_port_range = info.public_port_range as u32; - punch_reply.nat_type = - protobuf::EnumOrUnknown::new(info.nat_type); - drop(nat_info); - let bytes = punch_reply.write_to_bytes()?; - let mut net_packet = - NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?; - net_packet.set_version(Version::V1); - net_packet.set_protocol(Protocol::OtherTurn); - net_packet.set_transport_protocol( - turn_packet::Protocol::Punch.into(), - ); - net_packet.set_ttl(255); - let mut turn_packet = - TurnPacket::new(net_packet.payload_mut())?; - turn_packet.set_source(current_device.virtual_ip); - turn_packet.set_destination(src); - turn_packet.set_payload(&bytes); - udp.send_to(net_packet.buffer(), peer_addr)?; - } - } else { - let _ = sender.try_send(punch); - } - } - } - turn_packet::Protocol::UnKnow(_) => {} - } - } - } - Protocol::UnKnow(p) => { - log::warn!("未知协议 {}", p); - } - } - Ok(()) -} diff --git a/switch/src/lib.rs b/switch/src/lib.rs index 69e28b1..d01196f 100644 --- a/switch/src/lib.rs +++ b/switch/src/lib.rs @@ -1,21 +1,27 @@ -use std::io; -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; -use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::time::Duration; +use crate::error::Error; -use crossbeam::atomic::AtomicCell; -use crossbeam::sync::WaitGroup; -use parking_lot::Mutex; -use tokio::sync::watch; +// 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}; -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, -}; +pub type Result = std::result::Result; pub mod error; pub mod handle; @@ -23,353 +29,340 @@ pub mod nat; 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(); - 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 mut port = 101 as u16; - let udp = loop { - match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(0), port))) { - Ok(udp) => { - break udp; - } - Err(e) => { - if e.kind() == io::ErrorKind::AddrInUse { - port += 1; - } else { - log::error!("创建udp失败 {:?}", e); - return Err(Error::Stop("udp bind error".to_string())); - } - } - } - }; - udp.set_write_timeout(Some(Duration::from_millis(2000)))?; - //注册 - 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, - }) - } -} +// +// #[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 9fa98be..6e7bcd7 100644 --- a/switch/src/nat/check.rs +++ b/switch/src/nat/check.rs @@ -2,8 +2,8 @@ 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 crate::proto::message::NatType; // #[derive(Debug, Copy, Clone, PartialEq)] // pub enum NatType { @@ -79,9 +79,6 @@ pub fn public_ip_list_( for addr in addrs { let _ = udp.send_to(b"NatTest", addr)?; } - // let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35062")?; - // let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35061")?; - // let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35062")?; let mut hash_set = HashSet::new(); let mut count = 0; let mut min_port = 65535; @@ -99,7 +96,6 @@ pub fn public_ip_list_( max_port = port; } let ip = Ipv4Addr::new(buf[10], buf[11], buf[12], buf[13]); - // println!("pub {:?}:{}", ip, port); hash_set.insert(ip); count += 1; } diff --git a/switch/src/nat/mod.rs b/switch/src/nat/mod.rs index 3e8ff0f..ebea25c 100644 --- a/switch/src/nat/mod.rs +++ b/switch/src/nat/mod.rs @@ -1 +1,78 @@ +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::sync::Arc; +use parking_lot::Mutex; +use nat_traversal::punch::{NatInfo, NatType}; +use crate::proto::message::PunchNatType; + pub mod check; + + +#[derive(Clone)] +pub struct NatTest { + nat_test_server: Arc>, + info: Arc>, +} + +impl From for PunchNatType { + fn from(value: NatType) -> Self { + match value { + NatType::Symmetric => PunchNatType::Symmetric, + NatType::Cone => PunchNatType::Cone + } + } +} + +impl Into for PunchNatType { + fn into(self) -> NatType { + match self { + PunchNatType::Symmetric => NatType::Symmetric, + PunchNatType::Cone => NatType::Cone + } + } +} + +impl NatTest { + pub fn new(nat_test_server: Vec, public_ip: Ipv4Addr, public_port: u16, local_ip: IpAddr, local_port: u16) -> NatTest { + let info = NatTest::re_test_(&nat_test_server, public_ip, public_port, local_ip, local_port); + NatTest { + nat_test_server: Arc::new(nat_test_server), + info: Arc::new(Mutex::new(info)), + } + } + pub fn nat_info(&self) -> NatInfo { + self.info.lock().clone() + } + pub fn re_test(&self, public_ip: Ipv4Addr, public_port: u16, local_ip: IpAddr, local_port: u16) -> NatInfo { + let info = NatTest::re_test_(&self.nat_test_server, public_ip, public_port, local_ip, local_port); + *self.info.lock() = info.clone(); + info + } + fn re_test_(nat_test_server: &Vec, public_ip: Ipv4Addr, public_port: u16, local_ip: IpAddr, local_port: u16) -> NatInfo { + return match check::public_ip_list(nat_test_server) { + Ok((nat_type, ips, port_range)) => { + let mut public_ips = Vec::new(); + public_ips.push(IpAddr::from(public_ip)); + for ip in ips { + if ip != public_ip { + public_ips.push(IpAddr::from(ip)); + } + } + NatInfo::new(public_ips, + public_port, + port_range, + local_ip, local_port, + nat_type, ) + } + Err(e) => { + log::warn!("{:?}",e); + NatInfo::new( + vec![IpAddr::from(public_ip)], + public_port, + 0, + local_ip, local_port, + NatType::Cone, + ) + } + }; + } +} \ No newline at end of file diff --git a/switch/src/proto/message.rs b/switch/src/proto/message.rs index b335bb3..7164962 100644 --- a/switch/src/proto/message.rs +++ b/switch/src/proto/message.rs @@ -31,8 +31,8 @@ pub struct RegistrationRequest { // message fields // @@protoc_insertion_point(field:RegistrationRequest.token) pub token: ::std::string::String, - // @@protoc_insertion_point(field:RegistrationRequest.mac_address) - pub mac_address: ::std::string::String, + // @@protoc_insertion_point(field:RegistrationRequest.device_id) + pub device_id: ::std::string::String, // @@protoc_insertion_point(field:RegistrationRequest.name) pub name: ::std::string::String, // @@protoc_insertion_point(field:RegistrationRequest.is_fast) @@ -62,9 +62,9 @@ impl RegistrationRequest { |m: &mut RegistrationRequest| { &mut m.token }, )); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( - "mac_address", - |m: &RegistrationRequest| { &m.mac_address }, - |m: &mut RegistrationRequest| { &mut m.mac_address }, + "device_id", + |m: &RegistrationRequest| { &m.device_id }, + |m: &mut RegistrationRequest| { &mut m.device_id }, )); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( "name", @@ -98,7 +98,7 @@ impl ::protobuf::Message for RegistrationRequest { self.token = is.read_string()?; }, 18 => { - self.mac_address = is.read_string()?; + self.device_id = is.read_string()?; }, 26 => { self.name = is.read_string()?; @@ -121,8 +121,8 @@ impl ::protobuf::Message for RegistrationRequest { if !self.token.is_empty() { my_size += ::protobuf::rt::string_size(1, &self.token); } - if !self.mac_address.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.mac_address); + if !self.device_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.device_id); } if !self.name.is_empty() { my_size += ::protobuf::rt::string_size(3, &self.name); @@ -139,8 +139,8 @@ impl ::protobuf::Message for RegistrationRequest { if !self.token.is_empty() { os.write_string(1, &self.token)?; } - if !self.mac_address.is_empty() { - os.write_string(2, &self.mac_address)?; + if !self.device_id.is_empty() { + os.write_string(2, &self.device_id)?; } if !self.name.is_empty() { os.write_string(3, &self.name)?; @@ -166,7 +166,7 @@ impl ::protobuf::Message for RegistrationRequest { fn clear(&mut self) { self.token.clear(); - self.mac_address.clear(); + self.device_id.clear(); self.name.clear(); self.is_fast = false; self.special_fields.clear(); @@ -175,7 +175,7 @@ impl ::protobuf::Message for RegistrationRequest { fn default_instance() -> &'static RegistrationRequest { static instance: RegistrationRequest = RegistrationRequest { token: ::std::string::String::new(), - mac_address: ::std::string::String::new(), + device_id: ::std::string::String::new(), name: ::std::string::String::new(), is_fast: false, special_fields: ::protobuf::SpecialFields::new(), @@ -732,80 +732,87 @@ impl ::protobuf::reflect::ProtobufValue for DeviceList { } #[derive(PartialEq,Clone,Default,Debug)] -// @@protoc_insertion_point(message:Punch) -pub struct Punch { +// @@protoc_insertion_point(message:PunchInfo) +pub struct PunchInfo { // message fields - // @@protoc_insertion_point(field:Punch.virtual_ip) - pub virtual_ip: u32, - // @@protoc_insertion_point(field:Punch.public_ip_list) + // @@protoc_insertion_point(field:PunchInfo.public_ip_list) pub public_ip_list: ::std::vec::Vec, - // @@protoc_insertion_point(field:Punch.public_port) + // @@protoc_insertion_point(field:PunchInfo.public_port) pub public_port: u32, - // @@protoc_insertion_point(field:Punch.public_port_range) + // @@protoc_insertion_point(field:PunchInfo.public_port_range) pub public_port_range: u32, - // @@protoc_insertion_point(field:Punch.nat_type) - pub nat_type: ::protobuf::EnumOrUnknown, - // @@protoc_insertion_point(field:Punch.reply) + // @@protoc_insertion_point(field:PunchInfo.nat_type) + pub nat_type: ::protobuf::EnumOrUnknown, + // @@protoc_insertion_point(field:PunchInfo.reply) pub reply: bool, + // @@protoc_insertion_point(field:PunchInfo.local_ip) + pub local_ip: u32, + // @@protoc_insertion_point(field:PunchInfo.local_port) + pub local_port: u32, // special fields - // @@protoc_insertion_point(special_field:Punch.special_fields) + // @@protoc_insertion_point(special_field:PunchInfo.special_fields) pub special_fields: ::protobuf::SpecialFields, } -impl<'a> ::std::default::Default for &'a Punch { - fn default() -> &'a Punch { - ::default_instance() +impl<'a> ::std::default::Default for &'a PunchInfo { + fn default() -> &'a PunchInfo { + ::default_instance() } } -impl Punch { - pub fn new() -> Punch { +impl PunchInfo { + pub fn new() -> PunchInfo { ::std::default::Default::default() } fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(6); + let mut fields = ::std::vec::Vec::with_capacity(7); let mut oneofs = ::std::vec::Vec::with_capacity(0); - fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( - "virtual_ip", - |m: &Punch| { &m.virtual_ip }, - |m: &mut Punch| { &mut m.virtual_ip }, - )); fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>( "public_ip_list", - |m: &Punch| { &m.public_ip_list }, - |m: &mut Punch| { &mut m.public_ip_list }, + |m: &PunchInfo| { &m.public_ip_list }, + |m: &mut PunchInfo| { &mut m.public_ip_list }, )); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( "public_port", - |m: &Punch| { &m.public_port }, - |m: &mut Punch| { &mut m.public_port }, + |m: &PunchInfo| { &m.public_port }, + |m: &mut PunchInfo| { &mut m.public_port }, )); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( "public_port_range", - |m: &Punch| { &m.public_port_range }, - |m: &mut Punch| { &mut m.public_port_range }, + |m: &PunchInfo| { &m.public_port_range }, + |m: &mut PunchInfo| { &mut m.public_port_range }, )); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( "nat_type", - |m: &Punch| { &m.nat_type }, - |m: &mut Punch| { &mut m.nat_type }, + |m: &PunchInfo| { &m.nat_type }, + |m: &mut PunchInfo| { &mut m.nat_type }, )); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( "reply", - |m: &Punch| { &m.reply }, - |m: &mut Punch| { &mut m.reply }, + |m: &PunchInfo| { &m.reply }, + |m: &mut PunchInfo| { &mut m.reply }, )); - ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( - "Punch", + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "local_ip", + |m: &PunchInfo| { &m.local_ip }, + |m: &mut PunchInfo| { &mut m.local_ip }, + )); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "local_port", + |m: &PunchInfo| { &m.local_port }, + |m: &mut PunchInfo| { &mut m.local_port }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "PunchInfo", fields, oneofs, ) } } -impl ::protobuf::Message for Punch { - const NAME: &'static str = "Punch"; +impl ::protobuf::Message for PunchInfo { + const NAME: &'static str = "PunchInfo"; fn is_initialized(&self) -> bool { true @@ -814,9 +821,6 @@ impl ::protobuf::Message for Punch { fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { while let Some(tag) = is.read_raw_tag_or_eof()? { match tag { - 13 => { - self.virtual_ip = is.read_fixed32()?; - }, 18 => { is.read_repeated_packed_fixed32_into(&mut self.public_ip_list)?; }, @@ -835,6 +839,12 @@ impl ::protobuf::Message for Punch { 48 => { self.reply = is.read_bool()?; }, + 61 => { + self.local_ip = is.read_fixed32()?; + }, + 64 => { + self.local_port = is.read_uint32()?; + }, tag => { ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; }, @@ -847,9 +857,6 @@ impl ::protobuf::Message for Punch { #[allow(unused_variables)] fn compute_size(&self) -> u64 { let mut my_size = 0; - if self.virtual_ip != 0 { - my_size += 1 + 4; - } my_size += 5 * self.public_ip_list.len() as u64; if self.public_port != 0 { my_size += ::protobuf::rt::uint32_size(3, self.public_port); @@ -857,21 +864,24 @@ impl ::protobuf::Message for Punch { if self.public_port_range != 0 { my_size += ::protobuf::rt::uint32_size(4, self.public_port_range); } - if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) { + if self.nat_type != ::protobuf::EnumOrUnknown::new(PunchNatType::Symmetric) { my_size += ::protobuf::rt::int32_size(5, self.nat_type.value()); } if self.reply != false { my_size += 1 + 1; } + if self.local_ip != 0 { + my_size += 1 + 4; + } + if self.local_port != 0 { + my_size += ::protobuf::rt::uint32_size(8, self.local_port); + } my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); self.special_fields.cached_size().set(my_size as u32); my_size } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { - if self.virtual_ip != 0 { - os.write_fixed32(1, self.virtual_ip)?; - } for v in &self.public_ip_list { os.write_fixed32(2, *v)?; }; @@ -881,12 +891,18 @@ impl ::protobuf::Message for Punch { if self.public_port_range != 0 { os.write_uint32(4, self.public_port_range)?; } - if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) { + if self.nat_type != ::protobuf::EnumOrUnknown::new(PunchNatType::Symmetric) { os.write_enum(5, ::protobuf::EnumOrUnknown::value(&self.nat_type))?; } if self.reply != false { os.write_bool(6, self.reply)?; } + if self.local_ip != 0 { + os.write_fixed32(7, self.local_ip)?; + } + if self.local_port != 0 { + os.write_uint32(8, self.local_port)?; + } os.write_unknown_fields(self.special_fields.unknown_fields())?; ::std::result::Result::Ok(()) } @@ -899,85 +915,87 @@ impl ::protobuf::Message for Punch { &mut self.special_fields } - fn new() -> Punch { - Punch::new() + fn new() -> PunchInfo { + PunchInfo::new() } fn clear(&mut self) { - self.virtual_ip = 0; self.public_ip_list.clear(); self.public_port = 0; self.public_port_range = 0; - self.nat_type = ::protobuf::EnumOrUnknown::new(NatType::Symmetric); + self.nat_type = ::protobuf::EnumOrUnknown::new(PunchNatType::Symmetric); self.reply = false; + self.local_ip = 0; + self.local_port = 0; self.special_fields.clear(); } - fn default_instance() -> &'static Punch { - static instance: Punch = Punch { - virtual_ip: 0, + fn default_instance() -> &'static PunchInfo { + static instance: PunchInfo = PunchInfo { public_ip_list: ::std::vec::Vec::new(), public_port: 0, public_port_range: 0, nat_type: ::protobuf::EnumOrUnknown::from_i32(0), reply: false, + local_ip: 0, + local_port: 0, special_fields: ::protobuf::SpecialFields::new(), }; &instance } } -impl ::protobuf::MessageFull for Punch { +impl ::protobuf::MessageFull for PunchInfo { fn descriptor() -> ::protobuf::reflect::MessageDescriptor { static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); - descriptor.get(|| file_descriptor().message_by_package_relative_name("Punch").unwrap()).clone() + descriptor.get(|| file_descriptor().message_by_package_relative_name("PunchInfo").unwrap()).clone() } } -impl ::std::fmt::Display for Punch { +impl ::std::fmt::Display for PunchInfo { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for Punch { +impl ::protobuf::reflect::ProtobufValue for PunchInfo { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } #[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)] -// @@protoc_insertion_point(enum:NatType) -pub enum NatType { - // @@protoc_insertion_point(enum_value:NatType.Symmetric) +// @@protoc_insertion_point(enum:PunchNatType) +pub enum PunchNatType { + // @@protoc_insertion_point(enum_value:PunchNatType.Symmetric) Symmetric = 0, - // @@protoc_insertion_point(enum_value:NatType.Cone) + // @@protoc_insertion_point(enum_value:PunchNatType.Cone) Cone = 1, } -impl ::protobuf::Enum for NatType { - const NAME: &'static str = "NatType"; +impl ::protobuf::Enum for PunchNatType { + const NAME: &'static str = "PunchNatType"; fn value(&self) -> i32 { *self as i32 } - fn from_i32(value: i32) -> ::std::option::Option { + fn from_i32(value: i32) -> ::std::option::Option { match value { - 0 => ::std::option::Option::Some(NatType::Symmetric), - 1 => ::std::option::Option::Some(NatType::Cone), + 0 => ::std::option::Option::Some(PunchNatType::Symmetric), + 1 => ::std::option::Option::Some(PunchNatType::Cone), _ => ::std::option::Option::None } } - const VALUES: &'static [NatType] = &[ - NatType::Symmetric, - NatType::Cone, + const VALUES: &'static [PunchNatType] = &[ + PunchNatType::Symmetric, + PunchNatType::Cone, ]; } -impl ::protobuf::EnumFull for NatType { +impl ::protobuf::EnumFull for PunchNatType { fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor { static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new(); - descriptor.get(|| file_descriptor().enum_by_package_relative_name("NatType").unwrap()).clone() + descriptor.get(|| file_descriptor().enum_by_package_relative_name("PunchNatType").unwrap()).clone() } fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor { @@ -986,41 +1004,41 @@ impl ::protobuf::EnumFull for NatType { } } -impl ::std::default::Default for NatType { +impl ::std::default::Default for PunchNatType { fn default() -> Self { - NatType::Symmetric + PunchNatType::Symmetric } } -impl NatType { +impl PunchNatType { fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData { - ::protobuf::reflect::GeneratedEnumDescriptorData::new::("NatType") + ::protobuf::reflect::GeneratedEnumDescriptorData::new::("PunchNatType") } } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\rmessage.proto\"y\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\ - \x20\x01(\tR\x05token\x12\x1f\n\x0bmac_address\x18\x02\x20\x01(\tR\nmacA\ - ddress\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x17\n\x07is_fas\ - t\x18\x04\x20\x01(\x08R\x06isFast\"\x92\x02\n\x14RegistrationResponse\ - \x12\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvirtualIp\x12'\n\x0fvirtua\ - l_gateway\x18\x02\x20\x01(\x07R\x0evirtualGateway\x12'\n\x0fvirtual_netm\ - ask\x18\x03\x20\x01(\x07R\x0evirtualNetmask\x12\x14\n\x05epoch\x18\x04\ - \x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x05\x20\x03(\x0b2\ - \x0b.DeviceInfoR\x0edeviceInfoList\x12\x1b\n\tpublic_ip\x18\x06\x20\x01(\ - \x07R\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\x20\x01(\rR\npublicPo\ - rt\"d\n\nDeviceInfo\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\x12\ - \x1d\n\nvirtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\x12#\n\rdevice_statu\ - s\x18\x03\x20\x01(\rR\x0cdeviceStatus\"Y\n\nDeviceList\x12\x14\n\x05epoc\ - h\x18\x01\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x02\x20\ - \x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xd4\x01\n\x05Punch\x12\ - \x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvirtualIp\x12$\n\x0epublic_ip_\ - list\x18\x02\x20\x03(\x07R\x0cpublicIpList\x12\x1f\n\x0bpublic_port\x18\ - \x03\x20\x01(\rR\npublicPort\x12*\n\x11public_port_range\x18\x04\x20\x01\ - (\rR\x0fpublicPortRange\x12#\n\x08nat_type\x18\x05\x20\x01(\x0e2\x08.Nat\ - TypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\x01(\x08R\x05reply*\"\n\ - \x07NatType\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01b\x06proto\ - 3\ + \n\rmessage.proto\"u\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\ + \x20\x01(\tR\x05token\x12\x1b\n\tdevice_id\x18\x02\x20\x01(\tR\x08device\ + Id\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x17\n\x07is_fast\ + \x18\x04\x20\x01(\x08R\x06isFast\"\x92\x02\n\x14RegistrationResponse\x12\ + \x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvirtualIp\x12'\n\x0fvirtual_ga\ + teway\x18\x02\x20\x01(\x07R\x0evirtualGateway\x12'\n\x0fvirtual_netmask\ + \x18\x03\x20\x01(\x07R\x0evirtualNetmask\x12\x14\n\x05epoch\x18\x04\x20\ + \x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x05\x20\x03(\x0b2\x0b.D\ + eviceInfoR\x0edeviceInfoList\x12\x1b\n\tpublic_ip\x18\x06\x20\x01(\x07R\ + \x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\x20\x01(\rR\npublicPort\"d\ + \n\nDeviceInfo\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\x12\x1d\n\n\ + virtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\x12#\n\rdevice_status\x18\ + \x03\x20\x01(\rR\x0cdeviceStatus\"Y\n\nDeviceList\x12\x14\n\x05epoch\x18\ + \x01\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x02\x20\x03(\ + \x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xf8\x01\n\tPunchInfo\x12$\n\ + \x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\x12\x1f\n\x0bpu\ + blic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11public_port_range\ + \x18\x04\x20\x01(\rR\x0fpublicPortRange\x12(\n\x08nat_type\x18\x05\x20\ + \x01(\x0e2\r.PunchNatTypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\x01\ + (\x08R\x05reply\x12\x19\n\x08local_ip\x18\x07\x20\x01(\x07R\x07localIp\ + \x12\x1d\n\nlocal_port\x18\x08\x20\x01(\rR\tlocalPort*'\n\x0cPunchNatTyp\ + e\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01b\x06proto3\ "; /// `FileDescriptorProto` object which was a source for this generated file @@ -1043,9 +1061,9 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { messages.push(RegistrationResponse::generated_message_descriptor_data()); messages.push(DeviceInfo::generated_message_descriptor_data()); messages.push(DeviceList::generated_message_descriptor_data()); - messages.push(Punch::generated_message_descriptor_data()); + messages.push(PunchInfo::generated_message_descriptor_data()); let mut enums = ::std::vec::Vec::with_capacity(1); - enums.push(NatType::generated_enum_descriptor_data()); + enums.push(PunchNatType::generated_enum_descriptor_data()); ::protobuf::reflect::GeneratedFileDescriptor::new_generated( file_descriptor_proto(), deps, diff --git a/switch/src/protocol/control_packet.rs b/switch/src/protocol/control_packet.rs index 93e0ab1..c887bae 100644 --- a/switch/src/protocol/control_packet.rs +++ b/switch/src/protocol/control_packet.rs @@ -1,13 +1,22 @@ -use std::fmt; -use std::net::Ipv4Addr; +use std::{fmt, io}; -use crate::error::*; #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum Protocol { + /// ping请求 + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | time | echo | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ Ping, + /// 维持连接,内容同ping Pong, + /// 打洞请求 PunchRequest, + /// 打洞响应 PunchResponse, UnKnow(u8), } @@ -39,22 +48,18 @@ impl Into for Protocol { pub enum ControlPacket { PingPacket(PingPacket), PongPacket(PongPacket), - PunchRequest(PunchRequestPacket), - PunchResponse(PunchResponsePacket), + PunchRequest, + PunchResponse, } impl> ControlPacket { - pub fn new(protocol: u8, buffer: B) -> Result> { + pub fn new(protocol: u8, buffer: B) -> io::Result> { match Protocol::from(protocol) { Protocol::Ping => Ok(ControlPacket::PingPacket(PingPacket::new(buffer)?)), Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)), - Protocol::PunchRequest => Ok(ControlPacket::PunchRequest(PunchRequestPacket::new( - buffer, - )?)), - Protocol::PunchResponse => Ok(ControlPacket::PunchResponse(PunchResponsePacket::new( - buffer, - )?)), - Protocol::UnKnow(_) => Err(Error::NotSupport), + Protocol::PunchRequest => Ok(ControlPacket::PunchRequest), + Protocol::PunchResponse => Ok(ControlPacket::PunchResponse), + Protocol::UnKnow(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "Unsupported")), } } } @@ -65,36 +70,33 @@ pub struct PingPacket { buffer: B, } -#[derive(Copy, Clone)] -pub struct PongPacket { - buffer: B, -} +type PongPacket = PingPacket; impl> PingPacket { - pub fn new(buffer: B) -> Result> { + pub fn new(buffer: B) -> io::Result> { let len = buffer.as_ref().len(); - if len != 8 + 4 { - return Err(Error::InvalidPacket); + if len != 4 { + return Err(io::Error::new(io::ErrorKind::InvalidData, "len != 4")); } Ok(PingPacket { buffer }) } } impl> PingPacket { - pub fn time(&self) -> i64 { - i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap()) + pub fn time(&self) -> u16 { + u16::from_be_bytes(self.buffer.as_ref()[..2].try_into().unwrap()) } - pub fn epoch(&self) -> u32 { - u32::from_be_bytes(self.buffer.as_ref()[8..12].try_into().unwrap()) + pub fn epoch(&self) -> u16 { + u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap()) } } impl + AsMut<[u8]>> PingPacket { - pub fn set_time(&mut self, time: i64) { - self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes()) + pub fn set_time(&mut self, time: u16) { + self.buffer.as_mut()[..2].copy_from_slice(&time.to_be_bytes()) } - pub fn set_epoch(&mut self, epoch: u32) { - self.buffer.as_mut()[8..12].copy_from_slice(&epoch.to_be_bytes()) + pub fn set_epoch(&mut self, epoch: u16) { + self.buffer.as_mut()[2..4].copy_from_slice(&epoch.to_be_bytes()) } } @@ -105,118 +107,4 @@ impl> fmt::Debug for PingPacket { .field("epoch", &self.epoch()) .finish() } -} - -impl> PongPacket { - pub fn new(buffer: B) -> Result> { - let len = buffer.as_ref().len(); - if len != 8 { - return Err(Error::InvalidPacket); - } - Ok(PongPacket { buffer }) - } -} - -impl> PongPacket { - pub fn time(&self) -> i64 { - i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap()) - } -} - -impl + AsMut<[u8]>> PongPacket { - pub fn set_time(&mut self, time: i64) { - self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes()) - } -} - -impl> fmt::Debug for PongPacket { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PongPacket") - .field("time", &self.time()) - .finish() - } -} - -pub type TurnPongPacket = TurnPingPacket; - -/// 探测目标延迟 -#[derive(Copy, Clone)] -pub struct TurnPingPacket { - buffer: B, -} - -impl> TurnPingPacket { - pub fn new(buffer: B) -> Result> { - let len = buffer.as_ref().len(); - if len != 16 { - return Err(Error::InvalidPacket); - } - Ok(TurnPingPacket { buffer }) - } -} - -impl> TurnPingPacket { - // pub fn source(&self) -> Ipv4Addr { - // let tmp:[u8;4] = self.buffer.as_ref()[..4].try_into().unwrap(); - // Ipv4Addr::from(tmp) - // } - // pub fn destination(&self) -> Ipv4Addr { - // let tmp:[u8;4] = self.buffer.as_ref()[4..8].try_into().unwrap(); - // Ipv4Addr::from(tmp) - // } - pub fn time(&self) -> i64 { - i64::from_be_bytes(self.buffer.as_ref()[8..].try_into().unwrap()) - } -} - -impl + AsMut<[u8]>> TurnPingPacket { - pub fn set_source(&mut self, source: Ipv4Addr) { - self.buffer.as_mut()[..4].copy_from_slice(&source.octets()); - } - pub fn set_destination(&mut self, destination: Ipv4Addr) { - self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets()); - } - pub fn set_time(&mut self, time: i64) { - self.buffer.as_mut()[8..].copy_from_slice(&time.to_be_bytes()) - } -} - -pub type PunchResponsePacket = PunchPacket; -pub type PunchRequestPacket = PunchPacket; - -/// nat穿透 -#[derive(Clone)] -pub struct PunchPacket { - buffer: B, -} - -impl> PunchPacket { - pub fn new(buffer: B) -> Result> { - let len = buffer.as_ref().len(); - if len != 8 { - return Err(Error::InvalidPacket); - } - Ok(Self { buffer }) - } -} - -impl> PunchPacket { - pub fn source(&self) -> Ipv4Addr { - let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap(); - Ipv4Addr::from(tmp) - } -} - -impl + AsMut<[u8]>> PunchPacket { - pub fn set_source(&mut self, source: Ipv4Addr) { - self.buffer.as_mut()[..4].copy_from_slice(&source.octets()); - } -} - -impl> fmt::Debug for PunchPacket { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PunchPacket") - .field("source", &self.source()) - .finish() - } -} +} \ No newline at end of file diff --git a/switch/src/protocol/mod.rs b/switch/src/protocol/mod.rs index 3f6bd86..339f2d6 100644 --- a/switch/src/protocol/mod.rs +++ b/switch/src/protocol/mod.rs @@ -1,6 +1,19 @@ -use std::fmt; +use std::{fmt, io}; +use std::net::Ipv4Addr; -use crate::error::*; +/* + 0 15 31 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 版本(8) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 源ip地址(32) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 目的ip地址(32) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 数据体 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ pub mod control_packet; pub mod error_packet; @@ -41,6 +54,7 @@ pub enum Protocol { Control, /// 转发ipv4数据 Ipv4Turn, + /// 转发其他数据 OtherTurn, UnKnow(u8), } @@ -71,17 +85,19 @@ impl Into for Protocol { } } +pub const MAX_TTL: u8 = 0b1111; + #[derive(Copy, Clone)] pub struct NetPacket { buffer: B, } impl> NetPacket { - pub fn new(buffer: B) -> Result> { + pub fn new(buffer: B) -> io::Result> { let len = buffer.as_ref().len(); // 不能大于udp最大载荷长度 - if len < 4 || len > 65535 - 20 - 8 { - return Err(Error::InvalidPacket); + if len < 12 || len > 65535 - 20 - 8 { + return Err(io::Error::new(io::ErrorKind::InvalidData, "length overflow")); } Ok(NetPacket { buffer }) } @@ -104,10 +120,21 @@ impl> NetPacket { self.buffer.as_ref()[2] } pub fn ttl(&self) -> u8 { - self.buffer.as_ref()[3] + self.buffer.as_ref()[3] & MAX_TTL + } + pub fn source_ttl(&self) -> u8 { + self.buffer.as_ref()[3] >> 4 + } + pub fn source(&self) -> Ipv4Addr { + let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap(); + Ipv4Addr::from(tmp) + } + pub fn destination(&self) -> Ipv4Addr { + let tmp: [u8; 4] = self.buffer.as_ref()[8..12].try_into().unwrap(); + Ipv4Addr::from(tmp) } pub fn payload(&self) -> &[u8] { - &self.buffer.as_ref()[4..] + &self.buffer.as_ref()[12..] } } @@ -121,14 +148,26 @@ impl + AsMut<[u8]>> NetPacket { pub fn set_transport_protocol(&mut self, transport_protocol: u8) { self.buffer.as_mut()[2] = transport_protocol; } + pub fn first_set_ttl(&mut self, ttl: u8) { + self.buffer.as_mut()[3] = ttl << 4 | ttl; + } pub fn set_ttl(&mut self, ttl: u8) { - self.buffer.as_mut()[3] = ttl; + self.buffer.as_mut()[3] = 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]; + } + pub fn set_source(&mut self, source: Ipv4Addr) { + self.buffer.as_mut()[4..8].copy_from_slice(&source.octets()); + } + pub fn set_destination(&mut self, destination: Ipv4Addr) { + self.buffer.as_mut()[8..12].copy_from_slice(&destination.octets()); } pub fn set_payload(&mut self, payload: &[u8]) { - self.buffer.as_mut()[4..payload.len() + 4].copy_from_slice(payload); + self.buffer.as_mut()[12..payload.len() + 12].copy_from_slice(payload); } pub fn payload_mut(&mut self) -> &mut [u8] { - &mut self.buffer.as_mut()[4..] + &mut self.buffer.as_mut()[12..] } } @@ -139,6 +178,9 @@ impl> fmt::Debug for NetPacket { .field("protocol", &self.protocol()) .field("transport_protocol", &self.transport_protocol()) .field("ttl", &self.ttl()) + .field("source_ttl", &self.source_ttl()) + .field("source", &self.source()) + .field("destination", &self.destination()) .field("payload", &self.payload()) .finish() } diff --git a/switch/src/protocol/service_packet.rs b/switch/src/protocol/service_packet.rs index c933ac6..bc3ea1e 100644 --- a/switch/src/protocol/service_packet.rs +++ b/switch/src/protocol/service_packet.rs @@ -4,8 +4,10 @@ pub enum Protocol { RegistrationRequest, /// 注册响应 RegistrationResponse, - /// 更新设备列表 - UpdateDeviceList, + /// 拉取设备列表 + PollDeviceList, + /// 推送设备列表 + PushDeviceList, UnKnow(u8), } @@ -14,7 +16,8 @@ impl From for Protocol { match value { 1 => Self::RegistrationRequest, 2 => Self::RegistrationResponse, - 3 => Self::UpdateDeviceList, + 3 => Self::PollDeviceList, + 4 => Self::PushDeviceList, val => Self::UnKnow(val), } } @@ -25,7 +28,8 @@ impl Into for Protocol { match self { Self::RegistrationRequest => 1, Self::RegistrationResponse => 2, - Self::UpdateDeviceList => 3, + Self::PollDeviceList => 3, + Self::PushDeviceList => 4, Self::UnKnow(val) => val, } } diff --git a/switch/src/protocol/turn_packet.rs b/switch/src/protocol/turn_packet.rs index 4016825..5ab3b54 100644 --- a/switch/src/protocol/turn_packet.rs +++ b/switch/src/protocol/turn_packet.rs @@ -1,7 +1,4 @@ -use std::fmt; -use std::net::Ipv4Addr; -use crate::error::*; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum Protocol { @@ -26,56 +23,3 @@ impl Into for Protocol { } } } - -pub struct TurnPacket { - buffer: B, -} - -impl> TurnPacket { - pub fn new(buffer: B) -> Result> { - let len = buffer.as_ref().len(); - if len <= 8 { - return Err(Error::InvalidPacket); - } - Ok(Self { buffer }) - } -} - -impl> TurnPacket { - pub fn source(&self) -> Ipv4Addr { - let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap(); - Ipv4Addr::from(tmp) - } - pub fn destination(&self) -> Ipv4Addr { - let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap(); - Ipv4Addr::from(tmp) - } - pub fn payload(&self) -> &[u8] { - &self.buffer.as_ref()[8..] - } -} - -impl + AsMut<[u8]>> TurnPacket { - pub fn payload_mut(&mut self) -> &mut [u8] { - &mut self.buffer.as_mut()[8..] - } - pub fn set_source(&mut self, source: Ipv4Addr) { - self.buffer.as_mut()[..4].copy_from_slice(&source.octets()); - } - pub fn set_destination(&mut self, destination: Ipv4Addr) { - self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets()); - } - pub fn set_payload(&mut self, payload: &[u8]) { - self.buffer.as_mut()[8..payload.len() + 8].copy_from_slice(payload) - } -} - -impl> fmt::Debug for TurnPacket { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TurnPacket") - .field("source", &self.source()) - .field("destination", &self.destination()) - .field("payload", &self.payload()) - .finish() - } -} diff --git a/switch/src/tun_device/windows.rs b/switch/src/tun_device/windows.rs index 39e87b5..720064f 100644 --- a/switch/src/tun_device/windows.rs +++ b/switch/src/tun_device/windows.rs @@ -5,9 +5,8 @@ use std::sync::Arc; use libloading::Library; use wintun::{Adapter, Packet, Session}; -use crate::error::*; - -pub struct TunWriter(Arc); +#[derive(Clone)] +pub struct TunWriter(Arc, u32); impl TunWriter { pub fn write(&self, buf: &[u8]) -> io::Result<()> { @@ -21,10 +20,19 @@ impl TunWriter { } return Err(io::Error::new(io::ErrorKind::Other, "send err")); } + 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) { + log::warn!("{:?}",e); + } + config_ip(self.1, address, netmask, gateway) + } } +#[derive(Clone)] pub struct TunReader(pub(crate) Arc); + impl TunReader { pub fn next(&self) -> io::Result { match self.0.receive_blocking() { @@ -35,36 +43,46 @@ impl TunReader { } return Err(io::Error::new(io::ErrorKind::Other, "read err")); } + pub fn close(&self) { + self.0.shutdown() + } } pub fn create_tun( address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr, -) -> Result<(TunWriter, TunReader)> { +) -> io::Result<(TunWriter, TunReader)> { let win_tun = unsafe { match Library::new("wintun.dll") { Ok(library) => match wintun::load_from_library(library) { Ok(win_tun) => win_tun, Err(e) => { - return Err(Error::Stop(format!("{:?}", e))); + return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e))); } }, Err(e) => { log::error!("wintun.dll not found"); - return Err(Error::Stop(format!("wintun.dll not found {:?}", e))); + return Err(io::Error::new(io::ErrorKind::Other, format!("wintun.dll not found {:?}", e))); } } }; - let adapter = match Adapter::open(&win_tun, "Switch") { + let adapter = match Adapter::open(&win_tun, "Switch-V1") { Ok(a) => a, - Err(_) => match Adapter::create(&win_tun, "Switch", "Switch", None) { + Err(_) => match Adapter::create(&win_tun, "Switch-V1", "Switch-V1", None) { Ok(adapter) => adapter, - Err(e) => return Err(Error::Stop(format!("{:?}", e))), + Err(e) => return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e))), }, }; let index = adapter.get_adapter_index().unwrap(); + 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))) +} + +fn config_ip(index: u32, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> { let set_mtu = format!( "netsh interface ipv4 set subinterface {} mtu=1420 store=persistent", index @@ -74,9 +92,6 @@ pub fn create_tun( "netsh interface ip set address {} static {:?} {:?} ", // gateway={:?} index, address, netmask, ); - // println!("{}", set_mtu); - // println!("{}", set_metric); - // println!("{}", set_address); // 执行网卡初始化命令 let out = std::process::Command::new("cmd") .arg("/C") @@ -84,7 +99,7 @@ pub fn create_tun( .output() .unwrap(); if !out.status.success() { - return Err(Error::Stop(format!("设置mtu失败:{:?}", out))); + return Err(io::Error::new(io::ErrorKind::Other, format!("设置mtu失败: {:?}", out))); } let out = std::process::Command::new("cmd") .arg("/C") @@ -92,7 +107,7 @@ pub fn create_tun( .output() .unwrap(); if !out.status.success() { - return Err(Error::Stop(format!("设置接口跃点失败:{:?}", out))); + return Err(io::Error::new(io::ErrorKind::Other, format!("设置接口跃点失败: {:?}", out))); } let out = std::process::Command::new("cmd") .arg("/C") @@ -100,7 +115,7 @@ pub fn create_tun( .output() .unwrap(); if !out.status.success() { - return Err(Error::Stop(format!("设置网络地址失败:{:?}", out))); + return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", out))); } let dest = { let ip = address.octets(); @@ -116,7 +131,6 @@ pub fn create_tun( "route add {:?} mask {:?} {:?} if {}", dest, netmask, gateway, index ); - // println!("{}", set_route); // 执行添加路由命令 let out = std::process::Command::new("cmd") .arg("/C") @@ -124,9 +138,32 @@ pub fn create_tun( .output() .unwrap(); if !out.status.success() { - return Err(Error::Stop(format!("添加路由失败:{:?}", out))); + return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", out))); } - let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap()); - let reader_session = session.clone(); - Ok((TunWriter(session), TunReader(reader_session))) + Ok(()) +} + +fn delete_route(index: u32, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> { + let mask = netmask.octets(); + let ip = gateway.octets(); + let dest = Ipv4Addr::from([ + ip[0] & mask[0], + ip[1] & mask[1], + ip[2] & mask[2], + ip[3] & mask[3], + ]); + let delete_route = format!( + "route delete {:?} mask {:?} {:?} if {}", + dest, netmask, gateway, index + ); + // 删除路由 + let out = std::process::Command::new("cmd") + .arg("/C") + .arg(delete_route) + .output() + .unwrap(); + if !out.status.success() { + return Err(io::Error::new(io::ErrorKind::Other, format!("删除路由失败: {:?}", out))); + } + Ok(()) }