调整jni模块、优化cmd模块展示

This commit is contained in:
lubeilin
2023-07-17 01:31:05 +08:00
parent 24140c2145
commit c2b7b02f3f
39 changed files with 1184 additions and 390 deletions
+4 -4
View File
@@ -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
+8
View File
@@ -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]
+50
View File
@@ -0,0 +1,50 @@
use std::net::Ipv4Addr;
pub fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, 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::<Ipv4Addr>() {
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::<Ipv4Addr>() {
dest
} else {
return Err("not ipv4".to_string());
};
let mask = if let Ok(m) = mask.parse::<u32>() {
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)
}
+69
View File
@@ -0,0 +1,69 @@
use std::process::Command;
#[cfg(target_os = "windows")]
pub fn get_unique_identifier() -> Option<String> {
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<String> {
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<String> {
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())
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod identifier;
pub mod args_parse;
@@ -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 = []
+35
View File
@@ -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值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值
+84
View File
@@ -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<Self> {
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<Vec<DeviceItem>> {
self.udp.send(b"list")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Vec<DeviceItem>>(&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<Vec<RouteItem>> {
self.udp.send(b"route")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Vec<RouteItem>>(&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<Info> {
self.udp.send(b"info")?;
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Info>(&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<String> {
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())
}
}
+34
View File
@@ -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,
}
+141
View File
@@ -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<RouteItem> {
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<DeviceItem> {
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<String> = 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<String> = 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,
}
}
+105
View File
@@ -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<String> {
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)
}
+133
View File
@@ -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<RouteItem>) {
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<DeviceItem>) {
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<DeviceItem>) {
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)
}
+23
View File
@@ -0,0 +1,23 @@
use console::Style;
pub fn println_table(table: Vec<Vec<(String, Style)>>) {
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!()
}
}
+269
View File
@@ -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<String> = 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())), "<token>");
opts.optopt("n", "", "给设备一个名字", "<name>");
opts.optopt("d", "", "设备唯一标识符,凭id分配ip", "<id>");
#[cfg(not(feature = "mini"))]
opts.optflag("c", "", "关闭交互式命令");
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
opts.optopt("e", "", "NAT探测服务器地址,使用逗号分隔", "<addr1,addr2>");
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", "<in-ip>");
opts.optmulti("o", "", "配置点对网时使用,--out-ip 192.168.10.0/24,192.168.1.10,表示允许目标为192.168.10.0/24的数据从网卡192.168.1.10转发出去", "<out-ip>");
opts.optopt("w", "", "使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "<password>");
opts.optflag("m", "", "模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
opts.optopt("u", "", "虚拟网卡mtu值", "<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::<Vec<_>>();
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<String> = 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<String> = 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()
}
+1
View File
@@ -0,0 +1 @@
## 提供给安卓端使用
+28 -3
View File
@@ -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();
}
}
}
+5 -4
View File
@@ -53,9 +53,10 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<SwitchUtilSync, Error>
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<SwitchUtilSync, Error>
.collect::<Vec<_>>();
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)
-256
View File
@@ -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<String> = 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::<Vec<_>>();
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<String> = 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<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, 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::<Ipv4Addr>() {
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::<Ipv4Addr>() {
dest
} else {
return Err("参数错误".to_string());
};
let mask = if let Ok(m) = mask.parse::<u32>() {
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)
}
+2 -1
View File
@@ -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"
+5 -5
View File
@@ -107,11 +107,11 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
fn header_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..8]
}
}
// impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
// fn header_mut(&mut self) -> &mut [u8] {
// &mut self.buffer.as_mut()[..8]
// }
// }
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
/// 设置源端口
+5 -4
View File
@@ -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);
+59 -47
View File
@@ -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<AtomicCell<CurrentDeviceInfo>>,
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::<Vec<(Ipv4Addr, Ipv4Addr)>>();
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<Mutex<(u16, Vec<PeerDeviceInfo>)>> = Arc::new(Mutex::new((0, Vec::new())));
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> = Arc::new(Mutex::new((response.epoch, response.device_info_list)));
let peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>> = 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<SocketAddr>,
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<u16>,
}
@@ -325,9 +334,10 @@ impl Config {
device_id: String,
name: String,
server_address: SocketAddr,
server_address_str: String,
nat_test_server: Vec<SocketAddr>,
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>,
password: Option<String>, simulate_multicast: bool, ) -> Self {
password: Option<String>, simulate_multicast: bool, mtu: Option<u16>, ) -> 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,
}
}
}
+7 -3
View File
@@ -10,15 +10,17 @@ pub enum SwitchStatus {
}
pub struct SwitchWorker {
_name: String,
wg: WaitGroup,
status_s: Arc<Sender<SwitchStatus>>,
status_r: Receiver<SwitchStatus>,
}
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<Sender<SwitchStatus>>,
@@ -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(),
+9 -4
View File
@@ -17,7 +17,7 @@ pub struct SwitchSync {
impl SwitchUtilSync {
pub fn new(config: Config) -> io::Result<SwitchUtilSync> {
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<SwitchSync> {
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)))
}
}
+4 -3
View File
@@ -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<Vec<(u32, u32, Ipv4Addr)>>,
}
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<Ipv4Addr> {
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);
}
+24 -9
View File
@@ -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<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
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<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
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<Vec<(Ipv4Addr, Vec<Route>)>> = 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;
}
-2
View File
@@ -78,8 +78,6 @@ pub async fn start_punch(
}
num += 1;
}
worker.stop_all();
}
async fn start_punch_(
+4 -2
View File
@@ -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 {
+17 -3
View File
@@ -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<PeerDeviceInfo>,
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<PeerDeviceInfo> = 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)?;
+2 -2
View File
@@ -25,7 +25,7 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender,
ip_route: Option<ExternalRoute>,
ip_proxy_map: Option<IpProxyMap>,
cipher: Option<Aes256Gcm>) {
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,
+7 -6
View File
@@ -62,21 +62,22 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender,
ip_route: Option<ExternalRoute>,
ip_proxy_map: Option<IpProxyMap>,
cipher: Option<Aes256Gcm>) {
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<IgmpServer>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: Option<ExternalRoute>,
@@ -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)
+8 -2
View File
@@ -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<usize> {
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());
+2 -2
View File
@@ -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 {
+1 -7
View File
@@ -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<Mutex<Device>>,
pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
ip: Arc<AtomicCell<Ipv4Addr>>,
packet_information: bool,
}
impl DeviceWriter {
pub fn new(writer: DeviceW,lock: Arc<Mutex<Device>>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, ip: Ipv4Addr, packet_information: bool) -> Self {
pub fn new(writer: DeviceW,lock: Arc<Mutex<Device>>, 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 {
+5 -5
View File
@@ -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((
+1
View File
@@ -44,6 +44,7 @@ impl DeviceType {
}
}
#[derive(Clone)]
pub struct DriverInfo {
pub device_type: DeviceType,
pub name: String,
+11 -13
View File
@@ -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<Device>,
lock: Arc<Mutex<()>>,
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
ip: Arc<AtomicCell<Ipv4Addr>>,
}
impl DeviceWriter {
pub fn new(device: Arc<Device>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, ip: Ipv4Addr) -> Self {
pub fn new(device: Arc<Device>, 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)
}
}
}
+5
View File
@@ -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()?;
+3
View File
@@ -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()