From c2b7b02f3f7775866dccb1dbc01fd48133defdca Mon Sep 17 00:00:00 2001 From: lubeilin <1791778603@qq.com> Date: Mon, 17 Jul 2023 01:31:05 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4jni=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E3=80=81=E4=BC=98=E5=8C=96cmd=E6=A8=A1=E5=9D=97=E5=B1=95?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/rust.yml | 8 +- common/Cargo.toml | 8 + common/src/args_parse.rs | 50 ++++ common/src/identifier.rs | 69 ++++++ common/src/lib.rs | 2 + {switch-mini => switch-cmd}/Cargo.toml | 15 +- switch-cmd/README.md | 35 +++ switch-cmd/src/command/client.rs | 84 +++++++ switch-cmd/src/command/entity.rs | 34 +++ switch-cmd/src/command/mod.rs | 141 ++++++++++++ switch-cmd/src/command/server.rs | 105 +++++++++ switch-cmd/src/console_out/mod.rs | 133 +++++++++++ switch-cmd/src/console_out/table.rs | 23 ++ switch-cmd/src/main.rs | 269 ++++++++++++++++++++++ switch-jni/README.md | 1 + switch-jni/src/switch.rs | 31 ++- switch-jni/src/switch_util.rs | 9 +- switch-mini/src/main.rs | 256 -------------------- switch/Cargo.toml | 3 +- switch/packet/src/udp/udp.rs | 10 +- switch/src/channel/channel.rs | 9 +- switch/src/core/mod.rs | 106 +++++---- switch/src/core/status.rs | 10 +- switch/src/core/sync.rs | 13 +- switch/src/external_route/mod.rs | 7 +- switch/src/handle/heartbeat_handler.rs | 33 ++- switch/src/handle/punch_handler.rs | 2 - switch/src/handle/recv_handler.rs | 6 +- switch/src/handle/registration_handler.rs | 20 +- switch/src/handle/tun_tap/tap_handler.rs | 4 +- switch/src/handle/tun_tap/tun_handler.rs | 13 +- switch/src/tun_tap_device/android.rs | 10 +- switch/src/tun_tap_device/linux.rs | 4 +- switch/src/tun_tap_device/linux_mac.rs | 8 +- switch/src/tun_tap_device/mac.rs | 10 +- switch/src/tun_tap_device/mod.rs | 1 + switch/src/tun_tap_device/windows.rs | 24 +- switch/win-tun-tap/src/netsh.rs | 5 + switch/win-tun-tap/src/route.rs | 3 + 39 files changed, 1184 insertions(+), 390 deletions(-) create mode 100644 common/Cargo.toml create mode 100644 common/src/args_parse.rs create mode 100644 common/src/identifier.rs create mode 100644 common/src/lib.rs rename {switch-mini => switch-cmd}/Cargo.toml (54%) create mode 100644 switch-cmd/README.md create mode 100644 switch-cmd/src/command/client.rs create mode 100644 switch-cmd/src/command/entity.rs create mode 100644 switch-cmd/src/command/mod.rs create mode 100644 switch-cmd/src/command/server.rs create mode 100644 switch-cmd/src/console_out/mod.rs create mode 100644 switch-cmd/src/console_out/table.rs create mode 100644 switch-cmd/src/main.rs create mode 100644 switch-jni/README.md delete mode 100644 switch-mini/src/main.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9b5a9cb..ff4afc7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -65,7 +65,7 @@ jobs: # needs: test runs-on: ${{ matrix.OS }} env: - NAME: switch-desktop # change with the name of your project + NAME: switch-cmd # change with the name of your project TARGET: ${{ matrix.TARGET }} OS: ${{ matrix.OS }} steps: @@ -106,7 +106,7 @@ jobs: - name: Install rust target run: rustup target add $TARGET - name: Run build - run: cargo build --package switch-desktop --release --verbose --target $TARGET + run: cargo build --package switch-cmd --release --verbose --target $TARGET - name: List target run: find ./target - name: Compress @@ -128,7 +128,7 @@ jobs: - name: Archive artifact uses: actions/upload-artifact@v2 with: - name: switch-desktop + name: switch-cmd path: | ./artifacts # deploys to github releases on tag @@ -140,7 +140,7 @@ jobs: - name: Download artifacts uses: actions/download-artifact@v2 with: - name: switch-desktop + name: switch-cmd path: ./artifacts - name: List run: find ./artifacts diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 0000000..27839f2 --- /dev/null +++ b/common/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "common" +version = "1.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/common/src/args_parse.rs b/common/src/args_parse.rs new file mode 100644 index 0000000..6155cea --- /dev/null +++ b/common/src/args_parse.rs @@ -0,0 +1,50 @@ +use std::net::Ipv4Addr; + +pub fn ips_parse(ips: &Vec) -> Result, String> { + let mut in_ips_c = vec![]; + for x in ips { + let mut split = x.split(","); + let net = if let Some(net) = split.next() { + net + } else { + return Err("ipv4/mask,ipv4".to_string()); + }; + let ip = if let Some(ip) = split.next() { + ip + } else { + return Err("ipv4/mask,ipv4".to_string()); + }; + let ip = if let Ok(ip) = ip.parse::() { + ip + } else { + return Err("not ipv4".to_string()); + }; + let mut split = net.split("/"); + let dest = if let Some(dest) = split.next() { + dest + } else { + return Err("no ipv4/mask".to_string()); + }; + let mask = if let Some(mask) = split.next() { + mask + } else { + return Err("no netmask".to_string()); + }; + let dest = if let Ok(dest) = dest.parse::() { + dest + } else { + return Err("not ipv4".to_string()); + }; + let mask = if let Ok(m) = mask.parse::() { + let mut mask = 0 as u32; + for i in 0..m { + mask = mask | (1 << (31 - i)); + } + mask + } else { + return Err("not netmask".to_string()); + }; + in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip)); + } + Ok(in_ips_c) +} \ No newline at end of file diff --git a/common/src/identifier.rs b/common/src/identifier.rs new file mode 100644 index 0000000..5876044 --- /dev/null +++ b/common/src/identifier.rs @@ -0,0 +1,69 @@ + +use std::process::Command; + +#[cfg(target_os = "windows")] +pub fn get_unique_identifier() -> Option { + use std::os::windows::process::CommandExt; + let output = match Command::new("wmic") + .creation_flags(0x08000000) + .args(&["csproduct", "get", "UUID"]) + .output() { + Ok(output) => { output } + Err(_) => { + return None; + } + }; + + let result = String::from_utf8_lossy(&output.stdout); + let identifier = result.lines().nth(1).unwrap_or("").trim(); + if identifier.is_empty() { + None + } else { + Some(identifier.to_string()) + } +} + +#[cfg(target_os = "macos")] +pub fn get_unique_identifier() -> Option { + let output = match Command::new("ioreg") + .args(&["-rd1", "-c", "IOPlatformExpertDevice"]) + .output() { + Ok(output) => { output } + Err(_) => { + return None; + } + }; + + let result = String::from_utf8_lossy(&output.stdout); + let identifier = result + .lines() + .find(|line| line.contains("IOPlatformUUID")) + .and_then(|line| line.split('"').nth(4)) + .unwrap_or("").trim(); + if identifier.is_empty() { + None + } else { + Some(identifier.to_string()) + } +} + +#[cfg(target_os = "linux")] +pub fn get_unique_identifier() -> Option { + let output = match Command::new("dmidecode") + .arg("-s") + .arg("system-uuid") + .output() { + Ok(output) => { output } + Err(_) => { + return None; + } + }; + + let result = String::from_utf8_lossy(&output.stdout); + let identifier = result.trim().to_string(); + if identifier.is_empty() { + None + } else { + Some(identifier.to_string()) + } +} \ No newline at end of file diff --git a/common/src/lib.rs b/common/src/lib.rs new file mode 100644 index 0000000..5872876 --- /dev/null +++ b/common/src/lib.rs @@ -0,0 +1,2 @@ +pub mod identifier; +pub mod args_parse; diff --git a/switch-mini/Cargo.toml b/switch-cmd/Cargo.toml similarity index 54% rename from switch-mini/Cargo.toml rename to switch-cmd/Cargo.toml index 14430ce..dbe4559 100644 --- a/switch-mini/Cargo.toml +++ b/switch-cmd/Cargo.toml @@ -1,12 +1,21 @@ [package] -name = "switch-mini" -version = "1.0.7" +name = "switch-cmd" +version = "1.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] switch = {path="../switch"} +common = {path="../common"} tokio = { version = "1.28.1", features = ["full"] } getopts = "0.2.21" -ansi_term = "0.12.1" +console = "0.15.2" +os_info = "3.7.0" +dirs = "4.0.0" +serde = "1.0" +serde_json = "1.0.94" +log = "0.4.17" +[features] +default = [] +mini = [] \ No newline at end of file diff --git a/switch-cmd/README.md b/switch-cmd/README.md new file mode 100644 index 0000000..95e533e --- /dev/null +++ b/switch-cmd/README.md @@ -0,0 +1,35 @@ +## 模块介绍 +体积小,可以在服务器、路由器等环境使用 +## 详细参数说明 +### -k +一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网 +### -n +设备名称,方便区分不同设备 +### -d +设备id,每台设备的唯一标识,注意不要重复 +### -c +关闭命令,后台运行时可以加此参数 +### -s +中继服务器地址,注册和转发数据 +### -e +探测客户端NAT类型,不同类型有不同的打洞策略 +### -a +加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高 +### -i、-o +配置点对网时使用,例如A(10.26.0.2)通过B(10.26.0.3,192.168.0.10)访问C(192.168.0.11), + +则在A配置 --in-ip 192.168.10.0/24,10.26.0.3 ,表示将192.168.10.0/24网段的数据都转发到10.26.0.3节点 + +在B配置 --out-ip 192.168.10.0/24,192.168.1.10 ,表示允许将192.168.10.0/24的数据从网卡192.168.1.10转发出去 + +### -w +提升通信安全性,使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密。使用相同密码的客户端才能通信 + +### -m +模拟组播,高频使用组播通信时,可以尝试开启此参数,默认情况下会把组播当作广播发给所有节点 + +### -u + +设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值 + + diff --git a/switch-cmd/src/command/client.rs b/switch-cmd/src/command/client.rs new file mode 100644 index 0000000..903dbe9 --- /dev/null +++ b/switch-cmd/src/command/client.rs @@ -0,0 +1,84 @@ +use std::io; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; +use std::str::FromStr; +use std::time::Duration; + +use crate::command::entity::{DeviceItem, RouteItem, Info}; + +pub struct CommandClient { + udp: UdpSocket, +} + +impl CommandClient { + pub fn new() -> io::Result { + let path_buf = dirs::home_dir().unwrap().join(".switch_desktop").join("command-port"); + if !path_buf.exists() { + return Err(io::Error::new(io::ErrorKind::Other, "not started")); + } + let port = std::fs::read_to_string(path_buf)?; + let port = match u16::from_str(&port) { + Ok(port) => { port } + Err(_) => { + return Err(io::Error::new(io::ErrorKind::Other, "'command-port' file error")); + } + }; + let udp = UdpSocket::bind("127.0.0.1:0")?; + udp.set_read_timeout(Some(Duration::from_secs(2)))?; + udp.connect(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new(127, 0, 0, 1), + port, + )))?; + Ok(Self { udp }) + } +} + +impl CommandClient { + pub fn list(&self) -> io::Result> { + self.udp.send(b"list")?; + let mut buf = [0; 10240]; + let len = self.udp.recv(&mut buf)?; + 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 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 info(&self) -> io::Result { + self.udp.send(b"info")?; + 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-cmd/src/command/entity.rs b/switch-cmd/src/command/entity.rs new file mode 100644 index 0000000..9140522 --- /dev/null +++ b/switch-cmd/src/command/entity.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; +#[derive(Serialize, Deserialize, Debug)] +pub struct Info { + 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-cmd/src/command/mod.rs b/switch-cmd/src/command/mod.rs new file mode 100644 index 0000000..7b9f11b --- /dev/null +++ b/switch-cmd/src/command/mod.rs @@ -0,0 +1,141 @@ +use std::io; +use switch::core::Switch; +use crate::command::entity::{DeviceItem, RouteItem, Info}; +use crate::console_out; + +pub mod client; +pub mod server; +pub mod entity; + +pub enum CommandEnum { + Route, + List, + All, + Info, + Stop, +} + +pub fn command(cmd: CommandEnum) { + if let Err(e) = command_(cmd) { + println!("cmd: {}", e); + } +} + +fn command_(cmd: CommandEnum) -> io::Result<()> { + let command_client = client::CommandClient::new()?; + match cmd { + CommandEnum::Route => { + let list = command_client.route()?; + console_out::console_route_table(list); + } + CommandEnum::List => { + let list = command_client.list()?; + console_out::console_device_list(list); + } + CommandEnum::All => { + let list = command_client.list()?; + console_out::console_device_list_all(list); + } + CommandEnum::Info => { + let info = command_client.info()?; + console_out::console_info(info); + } + CommandEnum::Stop => { + command_client.stop()?; + } + } + Ok(()) +} + +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_info(switch: &Switch) -> Info { + 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(); + Info { + name, + virtual_ip, + virtual_gateway, + virtual_netmask, + connect_status, + relay_server, + nat_type, + public_ips, + local_ip, + } +} + diff --git a/switch-cmd/src/command/server.rs b/switch-cmd/src/command/server.rs new file mode 100644 index 0000000..d46b240 --- /dev/null +++ b/switch-cmd/src/command/server.rs @@ -0,0 +1,105 @@ +use std::io; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; +use tokio::net::UdpSocket; + +use switch::core::Switch; + + +pub struct CommandServer {} + +impl CommandServer { + pub fn new() -> Self { + Self {} + } +} + +impl CommandServer { + pub async fn start(self, switch: Switch) -> io::Result<()> { + let mut port = 21637 as u16; + let udp = loop { + match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::new(127, 0, 0, 1), + port, + ))).await { + Ok(udp) => { + break udp; + } + Err(e) => { + if e.kind() == io::ErrorKind::AddrInUse { + port += 1; + } else { + log::error!("创建udp失败 {:?}", e); + return Err(e); + } + } + } + }; + let path_buf = dirs::home_dir().unwrap().join(".switch_desktop").join("command-port"); + if !path_buf.parent().unwrap().exists() { + std::fs::create_dir_all(path_buf.parent().unwrap())?; + } + std::fs::write(path_buf,udp.local_addr()?.port().to_string())?; + let mut buf = [0u8; 64]; + loop { + let (len, addr) = udp.recv_from(&mut buf).await?; + match std::str::from_utf8(&buf[..len]) { + Ok(cmd) => { + if let Ok(out) = command(cmd, &switch) { + let _ = udp.send_to(out.as_bytes(), addr).await; + if "stopped" == &out { + break; + } + } + } + Err(e) => { + log::warn!("{:?}", e); + } + } + } + Ok(()) + } +} + + +fn command(cmd: &str, switch: &Switch) -> io::Result { + let out_str = match cmd { + "route" => { + match serde_json::to_string(&crate::command::command_route(switch)) { + Ok(str) => { + str + } + Err(e) => { + format!("{:?}", e) + } + } + } + "list" => { + match serde_json::to_string(&crate::command::command_list(switch)) { + Ok(str) => { + str + } + Err(e) => { + format!("{:?}", e) + } + } + } + "info" => { + match serde_json::to_string(&crate::command::command_info(switch)) { + Ok(str) => { + str + } + Err(e) => { + format!("{:?}", e) + } + } + } + "stop" => { + switch.stop()?; + "stopped".to_string() + } + _ => { + format!("command '{}' not found. \n Try to enter: 'help'\n", cmd) + } + }; + Ok(out_str) +} diff --git a/switch-cmd/src/console_out/mod.rs b/switch-cmd/src/console_out/mod.rs new file mode 100644 index 0000000..95e634b --- /dev/null +++ b/switch-cmd/src/console_out/mod.rs @@ -0,0 +1,133 @@ +use console::{style, Style}; + +use crate::command::entity::{DeviceItem, RouteItem, Info}; + +pub mod table; + +pub fn console_info(status: Info) { + 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(mut list: Vec) { + if list.is_empty() { + println!("No route found"); + return; + } + list.sort_by(|t1, t2| t1.destination.cmp(&t2.destination)); + let mut out_list = Vec::with_capacity(list.len()); + + out_list.push(vec![("Destination".to_string(), Style::new()), + ("Next Hop".to_string(), Style::new()), + ("Metric".to_string(), Style::new()), + ("Rt".to_string(), Style::new()), + ("Interface".to_string(), Style::new()), ]); + for item in list { + out_list.push(vec![(item.destination, Style::new().green()), + (item.next_hop, Style::new().green()), + (item.metric, Style::new().green()), + (item.rt, Style::new().green()), + (item.interface, Style::new().green())]); + } + + table::println_table(out_list) +} + +pub fn console_device_list(mut list: Vec) { + if list.is_empty() { + println!("No other devices found"); + return; + } + list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip)); + list.sort_by(|t1, t2| t1.status.cmp(&t2.status)); + let mut out_list = Vec::with_capacity(list.len()); + //表头 + out_list.push(vec![("Name".to_string(), Style::new()), + ("Virtual Ip".to_string(), Style::new()), + ("Status".to_string(), Style::new()), + ("P2P/Relay".to_string(), Style::new()), + ("Rt".to_string(), Style::new())]); + for item in list { + if &item.status == "Online" { + if &item.nat_traversal_type == "p2p" { + out_list.push(vec![(item.name, Style::new().green()), + (item.virtual_ip, Style::new().green()), + (item.status, Style::new().green()), + (item.nat_traversal_type, Style::new().green()), + (item.rt, Style::new().green())]); + } else { + out_list.push(vec![(item.name, Style::new().yellow()), + (item.virtual_ip, Style::new().yellow()), + (item.status, Style::new().yellow()), + (item.nat_traversal_type, Style::new().yellow()), + (item.rt, Style::new().yellow())]); + } + } else { + out_list.push(vec![(item.name, Style::new().color256(102)), + (item.virtual_ip, Style::new().color256(102)), + (item.status, Style::new().color256(102)), + ("".to_string(), Style::new().color256(102)), + ("".to_string(), Style::new().color256(102))]); + } + } + table::println_table(out_list) +} + +pub fn console_device_list_all(mut list: Vec) { + if list.is_empty() { + println!("No other devices found"); + return; + } + list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip)); + list.sort_by(|t1, t2| t1.status.cmp(&t2.status)); + let mut out_list = Vec::with_capacity(list.len()); + //表头 + out_list.push(vec![("Name".to_string(), Style::new()), + ("Virtual Ip".to_string(), Style::new()), + ("Status".to_string(), Style::new()), + ("NAT Type".to_string(), Style::new()), + ("Public Ips".to_string(), Style::new()), + ("Local Ip".to_string(), Style::new()), + ("P2P/Relay".to_string(), Style::new()), + ("Rt".to_string(), Style::new())]); + for item in list { + if &item.status == "Online" { + if &item.nat_traversal_type == "p2p" { + out_list.push(vec![(item.name, Style::new().green()), + (item.virtual_ip, Style::new().green()), + (item.status, Style::new().green()), + (item.nat_traversal_type, Style::new().green()), + (item.rt, Style::new().green()), + (item.nat_type, Style::new().green()), + (item.public_ips, Style::new().green()), + (item.local_ip, Style::new().green())]); + } else { + out_list.push(vec![(item.name, Style::new().yellow()), + (item.virtual_ip, Style::new().yellow()), + (item.status, Style::new().yellow()), + (item.nat_traversal_type, Style::new().yellow()), + (item.rt, Style::new().yellow()), + (item.nat_type, Style::new().yellow()), + (item.public_ips, Style::new().yellow()), + (item.local_ip, Style::new().yellow()), ]); + } + } else { + out_list.push(vec![(item.name, Style::new().color256(102)), + (item.virtual_ip, Style::new().color256(102)), + (item.status, Style::new().color256(102)), + ("".to_string(), Style::new().color256(102)), + ("".to_string(), Style::new().color256(102)), + ("".to_string(), Style::new().color256(102)), + ("".to_string(), Style::new().color256(102)), + ("".to_string(), Style::new().color256(102)), ]); + } + } + table::println_table(out_list) +} \ No newline at end of file diff --git a/switch-cmd/src/console_out/table.rs b/switch-cmd/src/console_out/table.rs new file mode 100644 index 0000000..c117b95 --- /dev/null +++ b/switch-cmd/src/console_out/table.rs @@ -0,0 +1,23 @@ +use console::Style; + +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 (col, (item, style)) in in_list.iter().enumerate() { + let str = format!("{:1$}", item, width_list[col]); + print!("{}", style.apply_to(str)); + } + println!() + } +} \ No newline at end of file diff --git a/switch-cmd/src/main.rs b/switch-cmd/src/main.rs new file mode 100644 index 0000000..a7868c0 --- /dev/null +++ b/switch-cmd/src/main.rs @@ -0,0 +1,269 @@ +use std::net::ToSocketAddrs; +use std::str::FromStr; +#[cfg(not(feature = "mini"))] +use console::style; +use getopts::Options; +use tokio::io::{AsyncBufReadExt, BufReader}; +use common::args_parse::ips_parse; +use switch::core::{Config, SwitchUtil}; +use switch::handle::registration_handler::ReqEnum; + +mod command; +mod console_out; + +#[tokio::main] +async fn main() { + let args: Vec = std::env::args().collect(); + let program = args[0].clone(); + let mut opts = Options::new(); + opts.long_only(false); + opts.optopt("k", "", &format!("{}", green("使用相同的token,就能组建一个局域网络".to_string())), ""); + opts.optopt("n", "", "给设备一个名字", ""); + opts.optopt("d", "", "设备唯一标识符,凭id分配ip", ""); + #[cfg(not(feature = "mini"))] + opts.optflag("c", "", "关闭交互式命令"); + opts.optopt("s", "", "注册和中继服务器地址", ""); + opts.optopt("e", "", "NAT探测服务器地址,使用逗号分隔", ""); + opts.optflag("a", "", "使用tap模式,默认使用tun模式"); + opts.optmulti("i", "", "配置点对网(IP代理)时使用,--in-ip 192.168.10.0/24,10.26.0.3,表示允许接收网段192.168.10.0/24的数据并转发到10.26.0.3", ""); + opts.optmulti("o", "", "配置点对网时使用,--out-ip 192.168.10.0/24,192.168.1.10,表示允许目标为192.168.10.0/24的数据从网卡192.168.1.10转发出去", ""); + opts.optopt("w", "", "使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", ""); + opts.optflag("m", "", "模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送"); + opts.optopt("u", "", "虚拟网卡mtu值", ""); + //"后台运行时,查看其他设备列表" + opts.optflag("", "list", &format!("{}", yellow("后台运行时,查看其他设备列表".to_string()))); + opts.optflag("", "all", &format!("{}", yellow("后台运行时,查看其他设备完整信息".to_string()))); + opts.optflag("", "info", &format!("{}", yellow("后台运行时,查看当前设备信息".to_string()))); + opts.optflag("", "route", &format!("{}", yellow("后台运行时,查看数据转发路径".to_string()))); + opts.optflag("", "stop", &format!("{}", yellow("停止后台运行".to_string()))); + opts.optflag("h", "help", "帮助"); + let matches = match opts.parse(&args[1..]) { + Ok(m) => { m } + Err(f) => { + print_usage(&program, opts); + println!("{}", f.to_string()); + return; + } + }; + if matches.opt_present("l") { + command::command(command::CommandEnum::List); + return; + } else if matches.opt_present("f") { + command::command(command::CommandEnum::Info); + return; + } else if matches.opt_present("q") { + command::command(command::CommandEnum::Stop); + return; + } else if matches.opt_present("r") { + command::command(command::CommandEnum::Route); + return; + } else if matches.opt_present("z") { + command::command(command::CommandEnum::All); + return; + } + if matches.opt_present("h") { + print_usage(&program, opts); + return; + } + if !matches.opt_present("k") { + print_usage(&program, opts); + println!("parameter -k not found ."); + return; + } + let tap = matches.opt_present("a"); + let token: String = matches.opt_get("k").unwrap().unwrap(); + let device_id = matches.opt_get_default("d", String::new()).unwrap(); + #[cfg(not(feature = "mini"))] + let device_id = if device_id.is_empty() { + common::identifier::get_unique_identifier().unwrap_or(String::new()) + } else { + device_id + }; + if device_id.is_empty() { + print_usage(&program, opts); + println!("parameter -d not found ."); + return; + } + let name = matches.opt_get_default("n", os_info::get().to_string()).unwrap(); + let server_address_str = matches.opt_get_default("s", "nat1.wherewego.top:29871".to_string()).unwrap(); + let server_address = server_address_str.to_socket_addrs().unwrap().next().unwrap(); + let nat_test_server = matches.opt_get_default("e", + "nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string()).unwrap(); + + let nat_test_server = nat_test_server.split(",").flat_map(|a| a.to_socket_addrs()).flatten() + .collect::>(); + + let in_ip = matches.opt_strs("i"); + let in_ip = match ips_parse(&in_ip) { + Ok(in_ip) => { in_ip } + Err(e) => { + print_usage(&program, opts); + println!(); + println!("-i {}", e); + return; + } + }; + let out_ip = matches.opt_strs("o"); + let out_ip = match ips_parse(&out_ip) { + Ok(out_ip) => { out_ip } + Err(e) => { + print_usage(&program, opts); + println!(); + println!("-o {}", e); + return; + } + }; + let password: Option = matches.opt_get("w").unwrap(); + let simulate_multicast = matches.opt_present("m"); + #[cfg(feature = "mini")] + let unused_cmd = true; + #[cfg(not(feature = "mini"))] + let unused_cmd = matches.opt_present("c"); + let mtu: Option = matches.opt_get("u").unwrap(); + let mtu = if let Some(mtu) = mtu { + match u16::from_str(&mtu) { + Ok(mtu) => { + Some(mtu) + } + Err(e) => { + print_usage(&program, opts); + println!(); + println!("-u {}", e); + return; + } + } + } else { + None + }; + let config = Config::new(tap, + token, device_id, name, + server_address, server_address_str, + nat_test_server, in_ip, + out_ip, password, simulate_multicast, mtu); + let mut switch_util = SwitchUtil::new(config).await.unwrap(); + let response = loop { + match switch_util.connect().await { + Ok(response) => { + break response; + } + Err(e) => { + match e { + ReqEnum::TokenError => { + println!("token error"); + } + ReqEnum::AddressExhausted => { + println!("address exhausted"); + } + ReqEnum::Timeout => { + println!("timeout..."); + continue; + } + ReqEnum::ServerError(str) => { + println!("error:{}", str); + } + ReqEnum::Other(str) => { + println!("error:{}", str); + } + } + return; + } + } + }; + println!(" ====== Connect Successfully ====== "); + println!("virtual_gateway:{}", response.virtual_gateway); + println!("virtual_ip:{}", green(response.virtual_ip.to_string())); + let driver_info = switch_util.create_iface().unwrap(); + println!(" ====== Create Network Interface Successfully ====== "); + println!("name:{}", driver_info.name); + println!("version:{}", driver_info.version); + let mut switch = match switch_util.build().await { + Ok(switch) => { + switch + } + Err(e) => { + println!("error:{}", e); + return; + } + }; + println!(" ====== Start Successfully ====== "); + let switch_s = switch.clone(); + tokio::spawn(async { + if let Err(e) = command::server::CommandServer::new().start(switch_s).await { + println!("command error :{}", e); + } + }); + if unused_cmd { + switch.wait_stop().await; + } else { + #[cfg(not(feature = "mini"))] + { + let stdin = tokio::io::stdin(); + let mut cmd = String::new(); + let mut reader = BufReader::new(stdin); + loop { + cmd.clear(); + println!("input:list,info,route,all,stop"); + tokio::select! { + _ = switch.wait_stop()=>{ + break; + } + rs = reader.read_line(&mut cmd)=>{ + match rs { + Ok(len) => { + if len ==0 { + break; + } + match cmd[..len].to_lowercase().trim() { + "list" => { + let list = command::command_list(&switch); + console_out::console_device_list(list); + } + "info"=>{ + let info = command::command_info(&switch); + console_out::console_info(info); + } + "route" =>{ + let route = command::command_route(&switch); + console_out::console_route_table(route); + } + "all" =>{ + let list = command::command_list(&switch); + console_out::console_device_list_all(list); + } + "stop" =>{ + let _ = switch.stop(); + break; + } + _ => { + } + } + println!(); + } + Err(e) => { + println!("input err:{}",e); + break; + } + } + } + } + } + switch.wait_stop().await; + } + } + std::process::exit(0); +} + +fn print_usage(program: &str, opts: Options) { + let brief = format!("Usage: {} [options]", program); + println!("version:1.1.0"); + println!("{}", opts.usage(&brief)); +} + +fn green(str: String) -> impl std::fmt::Display { + style(str).green() +} + +fn yellow(str: String) -> impl std::fmt::Display { + style(str).yellow() +} + diff --git a/switch-jni/README.md b/switch-jni/README.md new file mode 100644 index 0000000..676a70c --- /dev/null +++ b/switch-jni/README.md @@ -0,0 +1 @@ +## 提供给安卓端使用 \ No newline at end of file diff --git a/switch-jni/src/switch.rs b/switch-jni/src/switch.rs index 1d3217f..b73d2f7 100644 --- a/switch-jni/src/switch.rs +++ b/switch-jni/src/switch.rs @@ -2,7 +2,7 @@ use std::ptr; use jni::errors::Error; use jni::JNIEnv; use jni::objects::{JClass, JObject, JValue}; -use jni::sys::{jbyte, jint, jlong, jobject, jobjectArray, jsize}; +use jni::sys::{jboolean, jbyte, jint, jlong, jobject, jobjectArray, jsize}; use switch::channel::Route; use switch::core::sync::SwitchSync; use switch::handle::PeerDeviceInfo; @@ -27,6 +27,31 @@ pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_waitStop0( let _ = (&mut *switch).wait_stop(); } +#[no_mangle] +pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_waitStopMs0( + _env: JNIEnv, + _class: JClass, + raw_switch: jlong, + ms: jlong, +) -> jboolean { + let switch = raw_switch as *mut SwitchSync; + if (&mut *switch).wait_stop_ms(ms as _) { + jni::sys::JNI_TRUE + } else { + jni::sys::JNI_FALSE + } +} + +#[no_mangle] +pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_drop0( + _env: JNIEnv, + _class: JClass, + raw_switch: jlong, +) { + let switch = raw_switch as *mut SwitchSync; + let _ = Box::from_raw(switch).stop(); +} + #[no_mangle] pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_list0( mut env: JNIEnv, @@ -69,14 +94,14 @@ pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_list0( Err(e) => { env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e)) .expect("throw"); - return ptr::null_mut() + return ptr::null_mut(); } } } Err(e) => { env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e)) .expect("throw"); - return ptr::null_mut() + return ptr::null_mut(); } } } diff --git a/switch-jni/src/switch_util.rs b/switch-jni/src/switch_util.rs index 492f2a5..ca81111 100644 --- a/switch-jni/src/switch_util.rs +++ b/switch-jni/src/switch_util.rs @@ -53,9 +53,10 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result let token = to_string_not_null(env, &config, "token")?; let name = to_string_not_null(env, &config, "name")?; let device_id = to_string_not_null(env, &config, "deviceId")?; - let server = to_string_not_null(env, &config, "server")?; + let password = to_string(env, &config, "password")?; + let server_address_str = to_string_not_null(env, &config, "server")?; let nat_test_server = to_string_not_null(env, &config, "natTestServer")?; - let server_address = match server.to_socket_addrs() { + let server_address = match server_address_str.to_socket_addrs() { Ok(mut rs) => { if let Some(addr) = rs.next() { addr @@ -75,9 +76,9 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result .collect::>(); let config = Config::new(false, token, device_id, name, - server_address, + server_address, server_address_str, nat_test_server, vec![], - vec![], None, false, ); + vec![], password, false, None); match SwitchUtilSync::new(config) { Ok(switch_util) => { Ok(switch_util) diff --git a/switch-mini/src/main.rs b/switch-mini/src/main.rs deleted file mode 100644 index 2c2b719..0000000 --- a/switch-mini/src/main.rs +++ /dev/null @@ -1,256 +0,0 @@ -use std::net::{Ipv4Addr, ToSocketAddrs}; -use ansi_term::Colour; -use ansi_term::Colour::{Green, Yellow}; -use getopts::Options; -use tokio::io::{AsyncBufReadExt, BufReader}; -use switch::core::{Config, SwitchUtil}; -use switch::handle::PeerDeviceStatus; -use switch::handle::registration_handler::ReqEnum; - -#[tokio::main] -async fn main() { - let args: Vec = std::env::args().collect(); - let program = args[0].clone(); - let mut opts = Options::new(); - opts.optopt("", "token", "必选,使用相同的token,就能组建一个局域网络", ""); - opts.optopt("", "device-id", "必选,设备唯一标识符,凭id分配ip", ""); - opts.optopt("", "name", "必选,给设备一个名字", ""); - opts.optflag("", "unused-cmd", "关闭交互式命令"); - opts.optopt("", "server", "注册和中继服务器地址", ""); - opts.optopt("", "nat-test-server", "NAT探测服务器地址,使用逗号分隔", ""); - opts.optflag("", "tap", "使用tap模式"); - opts.optmulti("", "in-ip", "配置点对网(IP代理)时使用,--in-ip 192.168.10.0/24,10.26.0.3,表示允许接收网段192.168.10.0/24的数据并转 发到10.26.0.3", ""); - opts.optmulti("", "out-ip", "配置点对网时使用,--out-ip 192.168.10.0/24,192.168.1.10,表示允许目标为192.168.10.0/24的数据从网卡192.168.1.10转发出去", ""); - opts.optopt("", "password", "使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密。使用相同密码的客户端才能通信", ""); - opts.optflag("", "simulate-multicast", "模拟组播,默认情况下组播数据会被当作广播发送,兼容性更强,但是会造成流量浪费。开启后会模拟真实组播的数据发送"); - opts.optflag("h", "help", "帮助"); - let matches = match opts.parse(&args[1..]) { - Ok(m) => { m } - Err(f) => { - print_usage(&program, opts); - println!(); - println!("{}", f.to_string()); - return; - } - }; - if matches.opt_present("h") { - print_usage(&program, opts); - return; - } - if !matches.opt_present("token") || !matches.opt_present("device-id") || !matches.opt_present("name") { - print_usage(&program, opts); - return; - } - let tap = matches.opt_present("tap"); - let token: String = matches.opt_get("token").unwrap().unwrap(); - let device_id: String = matches.opt_get("device-id").unwrap().unwrap(); - let name: String = matches.opt_get("name").unwrap().unwrap(); - let server_address = matches.opt_get_default("server", "nat1.wherewego.top:29871".to_string()).unwrap(); - let server_address = server_address.to_socket_addrs().unwrap().next().unwrap(); - let nat_test_server = matches.opt_get_default("nat-test-server", - "nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string()).unwrap(); - - let nat_test_server = nat_test_server.split(",").flat_map(|a| a.to_socket_addrs()).flatten() - .collect::>(); - - let in_ip = matches.opt_strs("in-ip"); - let in_ip = match ips_parse(&in_ip) { - Ok(in_ip) => { in_ip } - Err(e) => { - print_usage(&program, opts); - println!(); - println!("--in-ip {}", e); - return; - } - }; - let out_ip = matches.opt_strs("out-ip"); - let out_ip = match ips_parse(&out_ip) { - Ok(out_ip) => { out_ip } - Err(e) => { - print_usage(&program, opts); - println!(); - println!("--out-ip {}", e); - return; - } - }; - let password: Option = matches.opt_get("password").unwrap(); - let simulate_multicast = matches.opt_present("simulate-multicast"); - let unused_cmd = matches.opt_present("unused-cmd"); - let config = Config::new(tap, - token, device_id, name, - server_address, - nat_test_server, in_ip, - out_ip, password, simulate_multicast, ); - let mut switch_util = SwitchUtil::new(config).await.unwrap(); - let response = loop { - match switch_util.connect().await { - Ok(response) => { - break response; - } - Err(e) => { - match e { - ReqEnum::TokenError => { - println!("token error"); - } - ReqEnum::AddressExhausted => { - println!("address exhausted"); - } - ReqEnum::Timeout => { - println!("timeout..."); - continue; - } - ReqEnum::ServerError(str) => { - println!("error:{}", str); - } - ReqEnum::Other(str) => { - println!("error:{}", str); - } - } - return; - } - } - }; - println!(" ====== Connect Successfully ====== "); - println!("virtual_gateway:{}", response.virtual_gateway); - println!("virtual_ip:{}", Green.paint(response.virtual_ip.to_string())); - let driver_info = switch_util.create_iface().unwrap(); - println!(" ====== Create Network Interface Successfully ====== "); - println!("name:{}", driver_info.name); - println!("version:{}", driver_info.version); - let mut switch = match switch_util.build().await { - Ok(switch) => { - switch - } - Err(e) => { - println!("error:{}", e); - return; - } - }; - println!(" ====== Start Successfully ====== "); - if unused_cmd { - switch.wait_stop().await; - } else { - let stdin = tokio::io::stdin(); - let mut cmd = String::new(); - let mut reader = BufReader::new(stdin); - loop { - cmd.clear(); - println!("input:list,exit"); - tokio::select! { - _ = switch.wait_stop()=>{ - break; - } - rs = reader.read_line(&mut cmd)=>{ - match rs { - Ok(len) => { - if len ==0 { - break; - } - match cmd[..len].trim() { - "list" => { - let mut list = switch.device_list(); - if list.is_empty(){ - println!("No other devices found"); - continue; - } - list.sort_by_key(|v|{(v.virtual_ip,v.status)}); - for x in list { - match x.status { - PeerDeviceStatus::Online => { - println!(" {}",Green.paint(x.virtual_ip.to_string())); - println!(" name:{}",x.name); - println!(" status:Online"); - if let Some(route) = switch.route(&x.virtual_ip){ - if route.is_p2p() { - println!(" connect:{}",Green.paint("p2p")); - }else { - println!(" connect:{}",Yellow.paint("relay")); - } - println!(" rt:{}",route.rt); - println!(" ->:{}",route.addr); - } - } - PeerDeviceStatus::Offline => { - println!(" {}",x.virtual_ip); - println!(" name:{}",x.name); - println!(" status:{}",Colour::RGB(150,150,150).paint("Offline")); - } - } - } - println!(); - } - "exit" =>{ - let _ = switch.stop(); - break; - } - _ => { - } - } - - } - Err(e) => { - println!("input err:{}",e); - break; - } - } - } - } - } - switch.wait_stop().await; - } -} - -fn print_usage(program: &str, opts: Options) { - let brief = format!("Usage: {} [options]", program); - println!("version:1.0.7"); - print!("{}", opts.usage(&brief)); -} - -fn ips_parse(ips: &Vec) -> Result, String> { - let mut in_ips_c = vec![]; - for x in ips { - let mut split = x.split(","); - let net = if let Some(net) = split.next() { - net - } else { - return Err("参数错误".to_string()); - }; - let ip = if let Some(ip) = split.next() { - ip - } else { - return Err("参数错误".to_string()); - }; - let ip = if let Ok(ip) = ip.parse::() { - ip - } else { - return Err("参数错误".to_string()); - }; - let mut split = net.split("/"); - let dest = if let Some(dest) = split.next() { - dest - } else { - return Err("参数错误".to_string()); - }; - let mask = if let Some(mask) = split.next() { - mask - } else { - return Err("参数错误".to_string()); - }; - let dest = if let Ok(dest) = dest.parse::() { - dest - } else { - return Err("参数错误".to_string()); - }; - let mask = if let Ok(m) = mask.parse::() { - let mut mask = 0 as u32; - for i in 0..m { - mask = mask | (1 << (31 - i)); - } - mask - } else { - return Err("参数错误".to_string()); - }; - in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip)); - } - Ok(in_ips_c) -} diff --git a/switch/Cargo.toml b/switch/Cargo.toml index fb2b1cb..ce42616 100644 --- a/switch/Cargo.toml +++ b/switch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "switch" -version = "1.0.7" +version = "1.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -32,3 +32,4 @@ libloading = "0.7.4" [build-dependencies] protobuf-codegen = "3.2.0" protoc-bin-vendored = "3.0.0" + diff --git a/switch/packet/src/udp/udp.rs b/switch/packet/src/udp/udp.rs index 7b6808a..917ae39 100644 --- a/switch/packet/src/udp/udp.rs +++ b/switch/packet/src/udp/udp.rs @@ -107,11 +107,11 @@ impl> UdpPacket { } } -impl + AsMut<[u8]>> UdpPacket { - fn header_mut(&mut self) -> &mut [u8] { - &mut self.buffer.as_mut()[..8] - } -} +// impl + AsMut<[u8]>> UdpPacket { +// fn header_mut(&mut self) -> &mut [u8] { +// &mut self.buffer.as_mut()[..8] +// } +// } impl + AsMut<[u8]>> UdpPacket { /// 设置源端口 diff --git a/switch/src/channel/channel.rs b/switch/src/channel/channel.rs index 73ebf23..0493323 100644 --- a/switch/src/channel/channel.rs +++ b/switch/src/channel/channel.rs @@ -302,8 +302,8 @@ impl Channel { let context = self.context; let main_channel = context.inner.main_channel.clone(); let handler = self.handler.clone(); - tokio::spawn(Self::start_(worker.clone(), context.clone(), handler.clone(), main_channel.clone(), head_reserve, true)); - tokio::spawn(Self::start_(worker.clone(), context.clone(), handler, main_channel, head_reserve, true)); + tokio::spawn(Self::start_(worker.worker("main_channel_1"), context.clone(), handler.clone(), main_channel.clone(), head_reserve, true)); + tokio::spawn(Self::start_(worker.worker("main_channel_2"), context.clone(), handler, main_channel, head_reserve, true)); let mut cur_status = Status::Cone; let mut status_receiver = context.inner.status_receiver.clone(); loop { @@ -314,7 +314,8 @@ impl Channel { rs=status_receiver.changed()=>{ match rs { Ok(_) => { - match *status_receiver.borrow() { + let s = status_receiver.borrow().clone(); + match s { Status::Cone => { cur_status = Status::Cone; } @@ -329,7 +330,7 @@ impl Channel { let udp = Arc::new(udp); let context = context.clone(); let handler = self.handler.clone(); - tokio::spawn(Self::start_(worker.clone(),context, handler, udp, head_reserve, false)); + tokio::spawn(Self::start_(worker.worker("symmetric_channel"),context, handler, udp, head_reserve, false)); } Err(e) => { log::error!("{}",e); diff --git a/switch/src/core/mod.rs b/switch/src/core/mod.rs index 2a5b36d..6063ba3 100644 --- a/switch/src/core/mod.rs +++ b/switch/src/core/mod.rs @@ -1,5 +1,5 @@ -use std::{io, thread}; -use std::net::{Ipv4Addr, SocketAddr}; +use std::io; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::Arc; use std::time::Duration; @@ -34,12 +34,12 @@ pub mod status; pub mod sync; +#[derive(Clone)] pub struct Switch { name: String, current_device: Arc>, context: Context, switch_status_manager: SwitchStatusManger, - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] device_writer: DeviceWriter, /// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化 /// 服务端和客户端的不一致,则服务端会推送新的设备列表 @@ -113,9 +113,11 @@ impl SwitchUtil { } tun_tap_device::DeviceType::Tun }; + let mtu = self.config.mtu.unwrap_or(1430); let in_ips = self.config.in_ips.iter().map(|(dest, mask, _)| { (Ipv4Addr::from(*dest & *mask), Ipv4Addr::from(*mask)) }).collect::>(); - let (device_writer, device_reader, driver_info) = tun_tap_device::create_device(device_type, response.virtual_ip, response.virtual_netmask, response.virtual_gateway, in_ips)?; + let (device_writer, device_reader, driver_info) = tun_tap_device::create_device(device_type, response.virtual_ip, + response.virtual_netmask, response.virtual_gateway, in_ips, mtu)?; let _ = self.iface.insert((device_writer, device_reader)); Ok(driver_info) } @@ -154,7 +156,7 @@ impl SwitchUtil { let register = Arc::new(registration_handler::Register::new(channel_sender.clone(), 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 device_list: Arc)>> = Arc::new(Mutex::new((response.epoch, response.device_info_list))); let peer_nat_info_map: Arc> = Arc::new(SkipMap::new()); let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected)); let virtual_ip = response.virtual_ip; @@ -188,14 +190,14 @@ impl SwitchUtil { }; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] if config.tap { - tap_handler::start(switch_status_manager.worker(), channel_sender.clone(), device_reader, device_writer.clone(), + tap_handler::start(switch_status_manager.worker("tap_handler"), channel_sender.clone(), device_reader, device_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone()); } else { - tun_handler::start(switch_status_manager.worker(), channel_sender.clone(), device_reader, device_writer.clone(), + tun_handler::start(switch_status_manager.worker("tun_handler"), channel_sender.clone(), device_reader, device_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone()); } #[cfg(any(target_os = "android"))] - tun_handler::start(switch_status_manager.worker(), channel_sender.clone(), device_reader, device_writer.clone(), + tun_handler::start(switch_status_manager.worker("android tun_handler"), channel_sender.clone(), device_reader, device_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone()); //外部数据接收处理 @@ -204,46 +206,33 @@ impl SwitchUtil { device_writer.clone(), connect_status.clone(), peer_nat_info_map.clone(), ip_proxy_map, out_external_route, cone_sender, symmetric_sender, cipher); - let channel = Channel::new(context.clone(), channel_recv_handler); - let channel_worker = switch_status_manager.worker(); - //数据接收 - thread::spawn(move || { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build().unwrap() - .block_on(async move { - if let Some(tcp_proxy) = tcp_proxy { - tokio::spawn(tcp_proxy.start()); - } - if let Some(udp_proxy) = udp_proxy { - tokio::spawn(udp_proxy.start()); - } - channel.start(channel_worker, 14, 65).await; - }); - }); { - let other_worker = switch_status_manager.worker(); + let channel = Channel::new(context.clone(), channel_recv_handler); + let channel_worker = switch_status_manager.worker("channel_worker"); + if let Some(tcp_proxy) = tcp_proxy { + tokio::spawn(tcp_proxy.start()); + } + if let Some(udp_proxy) = udp_proxy { + tokio::spawn(udp_proxy.start()); + } + tokio::spawn(async move { + channel.start(channel_worker, 14, 65).await + }); + } + { + let other_worker = switch_status_manager.worker("punch_handler"); let nat_test = nat_test.clone(); let device_list = device_list.clone(); let current_device = current_device.clone(); - //其他任务处理 - thread::spawn(move || { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build().unwrap() - .block_on(async move { - // 定时心跳 - heartbeat_handler::start_heartbeat(other_worker.clone(), channel_sender.clone(), device_list.clone(), current_device.clone()); - // 空闲检查 - heartbeat_handler::start_idle(other_worker.clone(), idle, channel_sender.clone()); - // 打洞处理 - punch_handler::start(other_worker.clone(), cone_receiver, punch.clone(), current_device.clone()); - punch_handler::start(other_worker.clone(), symmetric_receiver, punch, current_device.clone()); - punch_handler::start_punch(other_worker.clone(), nat_test.clone(), - device_list.clone(), channel_sender.clone(), - current_device.clone()).await; - }); - }); + // 定时心跳 + heartbeat_handler::start_heartbeat(other_worker.worker("heartbeat"), channel_sender.clone(), device_list.clone(), current_device.clone(), config.server_address_str); + // 空闲检查 + heartbeat_handler::start_idle(other_worker.worker("idle"), idle, channel_sender.clone()); + // 打洞处理 + punch_handler::start(other_worker.worker("cone_receiver"), cone_receiver, punch.clone(), current_device.clone()); + punch_handler::start(other_worker.worker("symmetric_receiver"), symmetric_receiver, punch, current_device.clone()); + tokio::spawn(punch_handler::start_punch(other_worker, nat_test, + device_list, channel_sender, current_device)); } context.switch(nat_test.nat_info().nat_type); Ok(Switch { @@ -251,7 +240,6 @@ impl SwitchUtil { current_device, context, switch_status_manager, - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] device_writer, nat_test, device_list, @@ -295,14 +283,33 @@ impl Switch { pub fn stop(&self) -> io::Result<()> { self.context.close(); self.switch_status_manager.stop_all(); - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] self.device_writer.close()?; + let virtual_gateway = self.current_device.load().virtual_gateway; + let _ = std::net::UdpSocket::bind("0.0.0.0:0")?.send_to(&[0], + SocketAddr::V4(SocketAddrV4::new(virtual_gateway, 10000))); Ok(()) } pub async fn wait_stop(&mut self) { self.switch_status_manager.wait().await; let _ = self.stop(); } + pub async fn wait_stop_ms(&mut self, ms: Duration) -> bool { + tokio::select! { + _=self.switch_status_manager.wait()=>{ + let _ = self.stop(); + return true; + } + _=tokio::time::sleep(ms)=>{ + return false; + } + } + } +} + +impl Drop for Switch { + fn drop(&mut self) { + let _ = self.stop(); + } } #[derive(Clone, Debug)] @@ -312,11 +319,13 @@ pub struct Config { pub device_id: String, pub name: String, pub server_address: SocketAddr, + pub server_address_str: String, pub nat_test_server: Vec, pub in_ips: Vec<(u32, u32, Ipv4Addr)>, pub out_ips: Vec<(u32, u32, Ipv4Addr)>, pub key: Option<[u8; 32]>, pub simulate_multicast: bool, + pub mtu: Option, } @@ -325,9 +334,10 @@ impl Config { device_id: String, name: String, server_address: SocketAddr, + server_address_str: String, nat_test_server: Vec, in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>, - password: Option, simulate_multicast: bool, ) -> Self { + password: Option, simulate_multicast: bool, mtu: Option, ) -> Self { let key = if let Some(password) = password { let mut hasher = sha2::Sha256::new(); hasher.update(password.as_bytes()); @@ -342,11 +352,13 @@ impl Config { device_id, name, server_address, + server_address_str, nat_test_server, in_ips, out_ips, key, simulate_multicast, + mtu, } } } \ No newline at end of file diff --git a/switch/src/core/status.rs b/switch/src/core/status.rs index 9333ed7..ff9c8fb 100644 --- a/switch/src/core/status.rs +++ b/switch/src/core/status.rs @@ -10,15 +10,17 @@ pub enum SwitchStatus { } pub struct SwitchWorker { + _name: String, wg: WaitGroup, status_s: Arc>, status_r: Receiver, } -impl Clone for SwitchWorker { - fn clone(&self) -> Self { +impl SwitchWorker { + pub fn worker(&self, name: &str) -> Self { self.wg.add(); SwitchWorker { + _name: name.to_string(), wg: self.wg.clone(), status_s: self.status_s.clone(), status_r: self.status_r.clone(), @@ -53,6 +55,7 @@ impl SwitchWorker { } } +#[derive(Clone)] pub struct SwitchStatusManger { wg: WaitGroup, status_s: Arc>, @@ -74,9 +77,10 @@ impl SwitchStatusManger { pub async fn wait(&mut self) { self.wg.wait().await } - pub fn worker(&self) -> SwitchWorker { + pub fn worker(&self, name: &str) -> SwitchWorker { self.wg.add(); SwitchWorker { + _name: name.to_string(), wg: self.wg.clone(), status_s: self.status_s.clone(), status_r: self.status_r.clone(), diff --git a/switch/src/core/sync.rs b/switch/src/core/sync.rs index bcaf481..7aa4f4d 100644 --- a/switch/src/core/sync.rs +++ b/switch/src/core/sync.rs @@ -17,7 +17,7 @@ pub struct SwitchSync { impl SwitchUtilSync { pub fn new(config: Config) -> io::Result { - let runtime = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(); + let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap(); let switch_util = runtime.block_on(SwitchUtil::new(config))?; Ok(SwitchUtilSync { switch_util, @@ -38,9 +38,15 @@ impl SwitchUtilSync { pub fn build(self) -> crate::Result { let runtime = self.runtime; let switch = runtime.block_on(self.switch_util.build())?; + { + let mut switch = switch.clone(); + std::thread::spawn(move || { + runtime.block_on(switch.wait_stop()) + }); + } Ok(SwitchSync { switch, - runtime, + runtime: tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(), }) } } @@ -50,8 +56,7 @@ impl SwitchSync { self.runtime.block_on(self.switch.wait_stop()) } pub fn wait_stop_ms(&mut self, ms: u64) -> bool { - self.runtime.block_on(tokio::time::timeout(Duration::from_millis(ms), - self.switch.wait_stop())).is_ok() + self.runtime.block_on(self.switch.wait_stop_ms(Duration::from_millis(ms))) } } diff --git a/switch/src/external_route/mod.rs b/switch/src/external_route/mod.rs index 77a6ec1..080d9e5 100644 --- a/switch/src/external_route/mod.rs +++ b/switch/src/external_route/mod.rs @@ -1,21 +1,22 @@ use std::net::Ipv4Addr; +use std::sync::Arc; // 目标ip,子网掩码,网关 #[derive(Clone)] pub struct ExternalRoute { - route_table: Vec<(u32, u32, Ipv4Addr)>, + route_table: Arc>, } impl ExternalRoute { pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self { Self { - route_table + route_table:Arc::new(route_table) } } pub fn route(&self, ip: &Ipv4Addr) -> Option { let ip = u32::from_be_bytes(ip.octets()); - for (dest, mask, gateway) in &self.route_table { + for (dest, mask, gateway) in self.route_table.iter() { if *mask & ip == *mask & *dest { return Some(*gateway); } diff --git a/switch/src/handle/heartbeat_handler.rs b/switch/src/handle/heartbeat_handler.rs index 7518edf..eb7f793 100644 --- a/switch/src/handle/heartbeat_handler.rs +++ b/switch/src/handle/heartbeat_handler.rs @@ -1,4 +1,4 @@ -use std::net::Ipv4Addr; +use std::net::{Ipv4Addr, ToSocketAddrs}; use std::sync::Arc; use std::time::Duration; use std::io; @@ -49,13 +49,14 @@ pub fn start_heartbeat( sender: ChannelSender, device_list: Arc)>>, current_device: Arc>, + server_address_str: String, ) { tokio::spawn(async move { tokio::select! { _=worker.stop_wait()=>{ return; } - rs=start_heartbeat_(sender, device_list, current_device)=>{ + rs=start_heartbeat_(sender, device_list, current_device,server_address_str)=>{ if let Err(e) = rs { log::warn!("心跳任务停止:{:?}", e); } @@ -76,6 +77,7 @@ async fn start_heartbeat_( sender: ChannelSender, device_list: Arc)>>, current_device: Arc>, + server_address_str: String, ) -> io::Result<()> { let mut net_packet = NetPacket::new([0u8; 16])?; net_packet.set_version(Version::V1); @@ -88,20 +90,33 @@ async fn start_heartbeat_( if sender.is_close() { return Ok(()); } - let current_device = current_device.load(); - net_packet.set_source(current_device.virtual_ip()); + let mut current_dev = current_device.load(); + if count % 6 == 0 { + if let Ok(mut addr) = server_address_str.to_socket_addrs() { + if let Some(addr) = addr.next() { + if addr != current_dev.connect_server { + let mut tmp = current_dev.clone(); + tmp.connect_server = addr; + if current_device.compare_exchange(current_dev, tmp).is_ok() { + current_dev.connect_server = addr; + } + } + } + } + } + net_packet.set_source(current_dev.virtual_ip()); { let mut ping = PingPacket::new(net_packet.payload_mut())?; let epoch = { device_list.lock().0 }; ping.set_epoch(epoch); } set_now_time(&mut net_packet)?; - net_packet.set_destination(current_device.virtual_gateway()); - if let Err(e) = sender.send_main(net_packet.buffer(), current_device.connect_server).await + net_packet.set_destination(current_dev.virtual_gateway()); + if let Err(e) = sender.send_main(net_packet.buffer(), current_dev.connect_server).await { log::warn!( "connect_server:{:?},e:{:?}", - current_device.connect_server, + current_dev.connect_server, e ); } @@ -109,7 +124,7 @@ async fn start_heartbeat_( let mut route_list: Option)>> = None; let peer_list = { device_list.lock().1.clone() }; for peer in peer_list { - if peer.virtual_ip == current_device.virtual_ip { + if peer.virtual_ip == current_dev.virtual_ip { continue; } set_now_time(&mut net_packet)?; @@ -121,7 +136,7 @@ async fn start_heartbeat_( } } else { //没有直连路由则发送到网关 - let _ = sender.send_main(net_packet.buffer(), current_device.connect_server).await; + let _ = sender.send_main(net_packet.buffer(), current_dev.connect_server).await; continue; } diff --git a/switch/src/handle/punch_handler.rs b/switch/src/handle/punch_handler.rs index 360a598..c1b4b80 100644 --- a/switch/src/handle/punch_handler.rs +++ b/switch/src/handle/punch_handler.rs @@ -78,8 +78,6 @@ pub async fn start_punch( } num += 1; } - - worker.stop_all(); } async fn start_punch_( diff --git a/switch/src/handle/recv_handler.rs b/switch/src/handle/recv_handler.rs index f0cc7e2..d497ea1 100644 --- a/switch/src/handle/recv_handler.rs +++ b/switch/src/handle/recv_handler.rs @@ -21,7 +21,7 @@ use crate::channel::{Route, RouteKey}; use crate::error::Error; use crate::external_route::ExternalRoute; -use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo}; +use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, PeerDeviceStatus}; use crate::handle::registration_handler::Register; use crate::igmp_server::IgmpServer; use crate::ip_proxy::IpProxyMap; @@ -362,7 +362,9 @@ impl ChannelDataHandler { .collect(); let route = Route::from(*route_key, 2, 99); for x in &ip_list { - context.add_route_if_absent(x.virtual_ip, route); + if x.status == PeerDeviceStatus::Online { + context.add_route_if_absent(x.virtual_ip, route); + } } let mut dev = self.device_list.lock(); if dev.0 != device_list_t.epoch as u16 { diff --git a/switch/src/handle/registration_handler.rs b/switch/src/handle/registration_handler.rs index 778a0ed..18e232c 100644 --- a/switch/src/handle/registration_handler.rs +++ b/switch/src/handle/registration_handler.rs @@ -6,6 +6,7 @@ use crossbeam_utils::atomic::AtomicCell; use protobuf::Message; use tokio::net::UdpSocket; use crate::channel::sender::ChannelSender; +use crate::handle::PeerDeviceInfo; use crate::proto::message::{RegistrationRequest, RegistrationResponse}; use crate::protocol::error_packet::InErrorPacket; @@ -24,7 +25,8 @@ pub struct RegResponse { pub virtual_ip: Ipv4Addr, pub virtual_gateway: Ipv4Addr, pub virtual_netmask: Ipv4Addr, - pub epoch: u32, + pub epoch: u16, + pub device_info_list: Vec, pub public_ip: Ipv4Addr, pub public_port: u16, } @@ -62,11 +64,23 @@ pub async fn registration( service_packet::Protocol::RegistrationResponse => { match RegistrationResponse::parse_from_bytes(net_packet.payload()) { Ok(response) => { + let device_info_list: Vec = response + .device_info_list + .into_iter() + .map(|info| { + PeerDeviceInfo::new( + Ipv4Addr::from(info.virtual_ip), + info.name, + info.device_status as u8, + ) + }) + .collect(); Ok(RegResponse { virtual_ip: Ipv4Addr::from(response.virtual_ip), virtual_gateway: Ipv4Addr::from(response.virtual_gateway), virtual_netmask: Ipv4Addr::from(response.virtual_netmask), - epoch: response.epoch, + epoch: response.epoch as u16, + device_info_list, public_ip: Ipv4Addr::from(response.public_ip), public_port: response.public_port as u16, }) @@ -134,7 +148,7 @@ fn registration_request_packet( request.device_id = device_id; request.name = name; request.is_fast = is_fast; - request.version = "1.0.7".to_string(); + request.version = "1.1.0".to_string(); let bytes = request.write_to_bytes()?; let buf = vec![0u8; 12 + bytes.len()]; let mut net_packet = NetPacket::new(buf)?; diff --git a/switch/src/handle/tun_tap/tap_handler.rs b/switch/src/handle/tun_tap/tap_handler.rs index 06d8f11..6137782 100644 --- a/switch/src/handle/tun_tap/tap_handler.rs +++ b/switch/src/handle/tun_tap/tap_handler.rs @@ -25,7 +25,7 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender, ip_route: Option, ip_proxy_map: Option, cipher: Option) { - thread::spawn(move || { + thread::Builder::new().name("tap_handler".into()).spawn(move || { tokio::runtime::Builder::new_current_thread() .enable_all().build().unwrap() .block_on(async move { @@ -36,7 +36,7 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender, } worker.stop_all(); }); - }); + }).unwrap(); } async fn start_(sender: ChannelSender, diff --git a/switch/src/handle/tun_tap/tun_handler.rs b/switch/src/handle/tun_tap/tun_handler.rs index 24618b1..03bfaa1 100644 --- a/switch/src/handle/tun_tap/tun_handler.rs +++ b/switch/src/handle/tun_tap/tun_handler.rs @@ -62,21 +62,22 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender, ip_route: Option, ip_proxy_map: Option, cipher: Option) { - thread::spawn(move || { + thread::Builder::new().name("tun_handler".into()).spawn(move || { tokio::runtime::Builder::new_current_thread() .enable_all().build().unwrap() .block_on(async move { - if let Err(e) = start_(sender, device_reader, device_writer, igmp_server, current_device, ip_route, ip_proxy_map, cipher).await { - log::warn!("tun:{:?}",e); + if let Err(e) = start_(sender, device_reader, &device_writer, igmp_server, current_device, ip_route, ip_proxy_map, cipher).await { + log::warn!("stop:{}",e); } + let _ = device_writer.close(); worker.stop_all(); }) - }); + }).unwrap(); } async fn start_(sender: ChannelSender, device_reader: DeviceReader, - device_writer: DeviceWriter, + device_writer: &DeviceWriter, igmp_server: Option, current_device: Arc>, ip_route: Option, @@ -88,7 +89,7 @@ async fn start_(sender: ChannelSender, return Ok(()); } let len = device_reader.read(&mut buf[12..])? + 12; - match handle(&sender, &mut buf, len, &device_writer, &igmp_server,current_device.load(), &ip_route, &ip_proxy_map, &cipher).await { + match handle(&sender, &mut buf, len, device_writer, &igmp_server, current_device.load(), &ip_route, &ip_proxy_map, &cipher).await { Ok(_) => {} Err(e) => { log::warn!("{:?}", e) diff --git a/switch/src/tun_tap_device/android.rs b/switch/src/tun_tap_device/android.rs index 508877b..3603912 100644 --- a/switch/src/tun_tap_device/android.rs +++ b/switch/src/tun_tap_device/android.rs @@ -9,7 +9,7 @@ pub struct DeviceReader(RawFd); impl DeviceWriter { pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> { unsafe { - let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len() ); + let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len()); if amount < 0 { return Err(io::Error::last_os_error()); } @@ -21,12 +21,18 @@ impl DeviceWriter { let buf = &buf[14..]; self.write_ipv4_tun(buf) } + pub fn close(&self) -> io::Result<()> { + // unsafe { + // libc::close(self.0); + // } + Ok(()) + } } impl DeviceReader { pub fn read(&self, buf: &mut [u8]) -> io::Result { unsafe { - let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len() ); + let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len()); if amount < 0 { return Err(io::Error::last_os_error()); diff --git a/switch/src/tun_tap_device/linux.rs b/switch/src/tun_tap_device/linux.rs index 0055129..de319b8 100644 --- a/switch/src/tun_tap_device/linux.rs +++ b/switch/src/tun_tap_device/linux.rs @@ -15,7 +15,6 @@ impl DeviceWriter { .destination(gateway) .address(address) .netmask(netmask) - .mtu(1420) // .queues(2) .up(); let mut dev = self.lock.lock(); @@ -56,6 +55,7 @@ pub fn create_device(device_type: DeviceType, netmask: Ipv4Addr, gateway: Ipv4Addr, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, + mtu: u16, ) -> io::Result<(DeviceWriter, DeviceReader,DriverInfo)> { let mut config = tun::Configuration::default(); @@ -63,7 +63,7 @@ pub fn create_device(device_type: DeviceType, .destination(gateway) .address(address) .netmask(netmask) - .mtu(1420) + .mtu(mtu.into()) // .queues(2) 用多个队列有兼容性问题 .up(); match device_type { diff --git a/switch/src/tun_tap_device/linux_mac.rs b/switch/src/tun_tap_device/linux_mac.rs index f1f035e..797e6d2 100644 --- a/switch/src/tun_tap_device/linux_mac.rs +++ b/switch/src/tun_tap_device/linux_mac.rs @@ -5,7 +5,6 @@ use bytes::BufMut; use tun::platform::posix::{Reader, Writer}; use std::net::Ipv4Addr; use std::os::unix::io::AsRawFd; -use crossbeam_utils::atomic::AtomicCell; #[cfg(any(target_os = "linux"))] use tun::platform::linux::Device; #[cfg(any(target_os = "macos"))] @@ -38,17 +37,15 @@ pub struct DeviceWriter { writer: DeviceW, pub lock: Arc>, pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, - ip: Arc>, packet_information: bool, } impl DeviceWriter { - pub fn new(writer: DeviceW,lock: Arc>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, ip: Ipv4Addr, packet_information: bool) -> Self { + pub fn new(writer: DeviceW,lock: Arc>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, _ip: Ipv4Addr, packet_information: bool) -> Self { Self { writer, lock, in_ips, - ip: Arc::new(AtomicCell::new(ip)), packet_information, } } @@ -107,9 +104,6 @@ impl DeviceWriter { } } } - pub fn ip(&self) -> Ipv4Addr { - self.ip.load() - } pub fn close(&self) -> io::Result<()> { unsafe { match &self.writer { diff --git a/switch/src/tun_tap_device/mac.rs b/switch/src/tun_tap_device/mac.rs index 8146a0f..a9874fc 100644 --- a/switch/src/tun_tap_device/mac.rs +++ b/switch/src/tun_tap_device/mac.rs @@ -15,7 +15,6 @@ impl DeviceWriter { .destination(gateway) .address(address) .netmask(netmask) - .mtu(1420) .up(); let mut dev = self.lock.lock(); if let Err(e) = dev.configure(&config) { @@ -42,7 +41,8 @@ pub fn create_device(device_type: DeviceType, netmask: Ipv4Addr, gateway: Ipv4Addr, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, -) -> io::Result<(DeviceWriter, DeviceReader,DriverInfo)> { + mtu: u16, +) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> { match device_type { DeviceType::Tun => {} DeviceType::Tap => { @@ -55,7 +55,7 @@ pub fn create_device(device_type: DeviceType, .destination(gateway) .address(address) .netmask(netmask) - .mtu(1420) + .mtu(mtu.into()) .up(); let dev = tun::create(&config).unwrap(); @@ -75,8 +75,8 @@ pub fn create_device(device_type: DeviceType, let writer = queue.writer(); let driver_info = DriverInfo { device_type, - name:name.to_string(), - version:String::new(), + name: name.to_string(), + version: String::new(), mac: None, }; Ok(( diff --git a/switch/src/tun_tap_device/mod.rs b/switch/src/tun_tap_device/mod.rs index 374b263..e5c99c0 100644 --- a/switch/src/tun_tap_device/mod.rs +++ b/switch/src/tun_tap_device/mod.rs @@ -44,6 +44,7 @@ impl DeviceType { } } +#[derive(Clone)] pub struct DriverInfo { pub device_type: DeviceType, pub name: String, diff --git a/switch/src/tun_tap_device/windows.rs b/switch/src/tun_tap_device/windows.rs index 5c8068a..3bcae56 100644 --- a/switch/src/tun_tap_device/windows.rs +++ b/switch/src/tun_tap_device/windows.rs @@ -1,8 +1,8 @@ use std::{io, thread}; use std::net::Ipv4Addr; +use std::os::windows::process::CommandExt; use std::sync::Arc; use std::time::Duration; -use crossbeam_utils::atomic::AtomicCell; use libloading::Library; use parking_lot::Mutex; use packet::ethernet; @@ -37,16 +37,14 @@ pub struct DeviceWriter { device: Arc, lock: Arc>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, - ip: Arc>, } impl DeviceWriter { - pub fn new(device: Arc, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, ip: Ipv4Addr) -> Self { + pub fn new(device: Arc, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, _ip: Ipv4Addr) -> Self { Self { device, lock: Arc::new(Default::default()), in_ips, - ip: Arc::new(AtomicCell::new(ip)), } } } @@ -120,7 +118,6 @@ impl DeviceWriter { log::warn!("{:?}", e); } dev.set_ip(address, netmask)?; - self.ip.store(address); for (address, netmask) in &self.in_ips { dev.add_route(*address, *netmask, gateway, 1)?; } @@ -132,9 +129,6 @@ impl DeviceWriter { delete_cache(); Ok(()) } - pub fn ip(&self) -> Ipv4Addr { - self.ip.load() - } pub fn close(&self) -> io::Result<()> { match self.device.as_ref() { Device::Tun(dev) => { @@ -198,6 +192,7 @@ fn create_tun( netmask: Ipv4Addr, gateway: Ipv4Addr, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, + mtu: u16, ) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> { unsafe { match Library::new("wintun.dll") { @@ -241,7 +236,7 @@ fn create_tun( let version = format!("{:?}", tun_device.version()?); tun_device.set_ip(address, netmask)?; tun_device.set_metric(1)?; - tun_device.set_mtu(1420)?; + tun_device.set_mtu(mtu)?; // ip代理路由 for (address, netmask) in &in_ips { tun_device.add_route(*address, *netmask, gateway, 1)?; @@ -271,6 +266,7 @@ fn delete_cache() { //清除路由缓存 let delete_cache = "netsh interface ip delete destinationcache"; let out = std::process::Command::new("cmd") + .creation_flags(0x08000000) .arg("/C") .arg(delete_cache) .output() @@ -297,6 +293,7 @@ fn create_tap( netmask: Ipv4Addr, gateway: Ipv4Addr, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, + mtu: u16, ) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> { let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) { Ok(tap_device) => tap_device, @@ -313,7 +310,7 @@ fn create_tap( let mac_str = format!("mac:{:x?}", mac); tap_device.set_ip(address, netmask)?; tap_device.set_metric(1)?; - tap_device.set_mtu(1420)?; + tap_device.set_mtu(mtu)?; tap_device.set_status(true)?; tap_device.add_route(address, netmask, gateway, 1)?; for (address, netmask) in &in_ips { @@ -350,13 +347,14 @@ fn delete_tap() { pub fn create_device(device_type: DeviceType, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr, - in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, ) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> { + in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, + mtu: u16) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> { match device_type { DeviceType::Tun => { - create_tun(address, netmask, gateway, in_ips) + create_tun(address, netmask, gateway, in_ips, mtu) } DeviceType::Tap => { - create_tap(address, netmask, gateway, in_ips) + create_tap(address, netmask, gateway, in_ips, mtu) } } } diff --git a/switch/win-tun-tap/src/netsh.rs b/switch/win-tun-tap/src/netsh.rs index ab83580..3b2cefc 100644 --- a/switch/win-tun-tap/src/netsh.rs +++ b/switch/win-tun-tap/src/netsh.rs @@ -1,10 +1,12 @@ use std::io; use std::net::Ipv4Addr; +use std::os::windows::process::CommandExt; /// 设置网卡名称 pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> { let cmd = format!(" netsh interface set interface name={:?} newname={:?}", old_name, new_name); let out = std::process::Command::new("cmd") + .creation_flags(0x08000000) //winapi-0.3.9/src/um/winbase.rs:283 .arg("/C") .arg(&cmd) .output()?; @@ -21,6 +23,7 @@ pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> i index, address, netmask, ); let out = std::process::Command::new("cmd") + .creation_flags(0x08000000) .arg("/C") .arg(&set_address) .output()?; @@ -37,6 +40,7 @@ pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> { index, mtu ); let out = std::process::Command::new("cmd") + .creation_flags(0x08000000) .arg("/C") .arg(&set_mtu) .output()?; @@ -49,6 +53,7 @@ pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> { pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> { let set_metric = format!("netsh interface ip set interface {} metric={}", index,metric); let out = std::process::Command::new("cmd") + .creation_flags(0x08000000) .arg("/C") .arg(&set_metric) .output()?; diff --git a/switch/win-tun-tap/src/route.rs b/switch/win-tun-tap/src/route.rs index 9cb0c33..054522d 100644 --- a/switch/win-tun-tap/src/route.rs +++ b/switch/win-tun-tap/src/route.rs @@ -1,5 +1,6 @@ use std::io; use std::net::Ipv4Addr; +use std::os::windows::process::CommandExt; /// 添加路由 pub fn add_route(index: u32, dest: Ipv4Addr, @@ -11,6 +12,7 @@ pub fn add_route(index: u32, dest: Ipv4Addr, ); // 执行添加路由命令 let out = std::process::Command::new("cmd") + .creation_flags(0x08000000) .arg("/C") .arg(&set_route) .output() @@ -33,6 +35,7 @@ pub fn delete_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4 ); // 删除路由 let out = std::process::Command::new("cmd") + .creation_flags(0x08000000) .arg("/C") .arg(delete_route) .output()