调整jni模块、优化cmd模块展示
This commit is contained in:
@@ -65,7 +65,7 @@ jobs:
|
|||||||
# needs: test
|
# needs: test
|
||||||
runs-on: ${{ matrix.OS }}
|
runs-on: ${{ matrix.OS }}
|
||||||
env:
|
env:
|
||||||
NAME: switch-desktop # change with the name of your project
|
NAME: switch-cmd # change with the name of your project
|
||||||
TARGET: ${{ matrix.TARGET }}
|
TARGET: ${{ matrix.TARGET }}
|
||||||
OS: ${{ matrix.OS }}
|
OS: ${{ matrix.OS }}
|
||||||
steps:
|
steps:
|
||||||
@@ -106,7 +106,7 @@ jobs:
|
|||||||
- name: Install rust target
|
- name: Install rust target
|
||||||
run: rustup target add $TARGET
|
run: rustup target add $TARGET
|
||||||
- name: Run build
|
- 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
|
- name: List target
|
||||||
run: find ./target
|
run: find ./target
|
||||||
- name: Compress
|
- name: Compress
|
||||||
@@ -128,7 +128,7 @@ jobs:
|
|||||||
- name: Archive artifact
|
- name: Archive artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: switch-desktop
|
name: switch-cmd
|
||||||
path: |
|
path: |
|
||||||
./artifacts
|
./artifacts
|
||||||
# deploys to github releases on tag
|
# deploys to github releases on tag
|
||||||
@@ -140,7 +140,7 @@ jobs:
|
|||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: switch-desktop
|
name: switch-cmd
|
||||||
path: ./artifacts
|
path: ./artifacts
|
||||||
- name: List
|
- name: List
|
||||||
run: find ./artifacts
|
run: find ./artifacts
|
||||||
|
|||||||
@@ -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]
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod identifier;
|
||||||
|
pub mod args_parse;
|
||||||
@@ -1,12 +1,21 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "switch-mini"
|
name = "switch-cmd"
|
||||||
version = "1.0.7"
|
version = "1.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
switch = {path="../switch"}
|
switch = {path="../switch"}
|
||||||
|
common = {path="../common"}
|
||||||
tokio = { version = "1.28.1", features = ["full"] }
|
tokio = { version = "1.28.1", features = ["full"] }
|
||||||
getopts = "0.2.21"
|
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 = []
|
||||||
@@ -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值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值
|
||||||
|
|
||||||
|
|
||||||
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
## 提供给安卓端使用
|
||||||
@@ -2,7 +2,7 @@ use std::ptr;
|
|||||||
use jni::errors::Error;
|
use jni::errors::Error;
|
||||||
use jni::JNIEnv;
|
use jni::JNIEnv;
|
||||||
use jni::objects::{JClass, JObject, JValue};
|
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::channel::Route;
|
||||||
use switch::core::sync::SwitchSync;
|
use switch::core::sync::SwitchSync;
|
||||||
use switch::handle::PeerDeviceInfo;
|
use switch::handle::PeerDeviceInfo;
|
||||||
@@ -27,6 +27,31 @@ pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_waitStop0(
|
|||||||
let _ = (&mut *switch).wait_stop();
|
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]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_list0(
|
pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_list0(
|
||||||
mut env: JNIEnv,
|
mut env: JNIEnv,
|
||||||
@@ -69,14 +94,14 @@ pub unsafe extern "C" fn Java_top_wherewego_switchjni_Switch_list0(
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||||
.expect("throw");
|
.expect("throw");
|
||||||
return ptr::null_mut()
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||||
.expect("throw");
|
.expect("throw");
|
||||||
return ptr::null_mut()
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 token = to_string_not_null(env, &config, "token")?;
|
||||||
let name = to_string_not_null(env, &config, "name")?;
|
let name = to_string_not_null(env, &config, "name")?;
|
||||||
let device_id = to_string_not_null(env, &config, "deviceId")?;
|
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 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) => {
|
Ok(mut rs) => {
|
||||||
if let Some(addr) = rs.next() {
|
if let Some(addr) = rs.next() {
|
||||||
addr
|
addr
|
||||||
@@ -75,9 +76,9 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<SwitchUtilSync, Error>
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let config = Config::new(false,
|
let config = Config::new(false,
|
||||||
token, device_id, name,
|
token, device_id, name,
|
||||||
server_address,
|
server_address, server_address_str,
|
||||||
nat_test_server, vec![],
|
nat_test_server, vec![],
|
||||||
vec![], None, false, );
|
vec![], password, false, None);
|
||||||
match SwitchUtilSync::new(config) {
|
match SwitchUtilSync::new(config) {
|
||||||
Ok(switch_util) => {
|
Ok(switch_util) => {
|
||||||
Ok(switch_util)
|
Ok(switch_util)
|
||||||
|
|||||||
@@ -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
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "switch"
|
name = "switch"
|
||||||
version = "1.0.7"
|
version = "1.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# 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]
|
[build-dependencies]
|
||||||
protobuf-codegen = "3.2.0"
|
protobuf-codegen = "3.2.0"
|
||||||
protoc-bin-vendored = "3.0.0"
|
protoc-bin-vendored = "3.0.0"
|
||||||
|
|
||||||
|
|||||||
@@ -107,11 +107,11 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
// impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||||
fn header_mut(&mut self) -> &mut [u8] {
|
// fn header_mut(&mut self) -> &mut [u8] {
|
||||||
&mut self.buffer.as_mut()[..8]
|
// &mut self.buffer.as_mut()[..8]
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||||
/// 设置源端口
|
/// 设置源端口
|
||||||
|
|||||||
@@ -302,8 +302,8 @@ impl Channel {
|
|||||||
let context = self.context;
|
let context = self.context;
|
||||||
let main_channel = context.inner.main_channel.clone();
|
let main_channel = context.inner.main_channel.clone();
|
||||||
let handler = self.handler.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.worker("main_channel_1"), 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_2"), context.clone(), handler, main_channel, head_reserve, true));
|
||||||
let mut cur_status = Status::Cone;
|
let mut cur_status = Status::Cone;
|
||||||
let mut status_receiver = context.inner.status_receiver.clone();
|
let mut status_receiver = context.inner.status_receiver.clone();
|
||||||
loop {
|
loop {
|
||||||
@@ -314,7 +314,8 @@ impl Channel {
|
|||||||
rs=status_receiver.changed()=>{
|
rs=status_receiver.changed()=>{
|
||||||
match rs {
|
match rs {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
match *status_receiver.borrow() {
|
let s = status_receiver.borrow().clone();
|
||||||
|
match s {
|
||||||
Status::Cone => {
|
Status::Cone => {
|
||||||
cur_status = Status::Cone;
|
cur_status = Status::Cone;
|
||||||
}
|
}
|
||||||
@@ -329,7 +330,7 @@ impl Channel {
|
|||||||
let udp = Arc::new(udp);
|
let udp = Arc::new(udp);
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
let handler = self.handler.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) => {
|
Err(e) => {
|
||||||
log::error!("{}",e);
|
log::error!("{}",e);
|
||||||
|
|||||||
+59
-47
@@ -1,5 +1,5 @@
|
|||||||
use std::{io, thread};
|
use std::io;
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -34,12 +34,12 @@ pub mod status;
|
|||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Switch {
|
pub struct Switch {
|
||||||
name: String,
|
name: String,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
context: Context,
|
context: Context,
|
||||||
switch_status_manager: SwitchStatusManger,
|
switch_status_manager: SwitchStatusManger,
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
|
||||||
device_writer: DeviceWriter,
|
device_writer: DeviceWriter,
|
||||||
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
|
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
|
||||||
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
||||||
@@ -113,9 +113,11 @@ impl SwitchUtil {
|
|||||||
}
|
}
|
||||||
tun_tap_device::DeviceType::Tun
|
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 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));
|
let _ = self.iface.insert((device_writer, device_reader));
|
||||||
Ok(driver_info)
|
Ok(driver_info)
|
||||||
}
|
}
|
||||||
@@ -154,7 +156,7 @@ impl SwitchUtil {
|
|||||||
let register = Arc::new(registration_handler::Register::new(channel_sender.clone(),
|
let register = Arc::new(registration_handler::Register::new(channel_sender.clone(),
|
||||||
config.server_address, config.token.clone(),
|
config.server_address, config.token.clone(),
|
||||||
config.device_id.clone(), config.name.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 peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>> = Arc::new(SkipMap::new());
|
||||||
let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected));
|
let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected));
|
||||||
let virtual_ip = response.virtual_ip;
|
let virtual_ip = response.virtual_ip;
|
||||||
@@ -188,14 +190,14 @@ impl SwitchUtil {
|
|||||||
};
|
};
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||||
if config.tap {
|
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());
|
igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone());
|
||||||
} else {
|
} 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());
|
igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone());
|
||||||
}
|
}
|
||||||
#[cfg(any(target_os = "android"))]
|
#[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());
|
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(),
|
device_writer.clone(), connect_status.clone(),
|
||||||
peer_nat_info_map.clone(), ip_proxy_map, out_external_route,
|
peer_nat_info_map.clone(), ip_proxy_map, out_external_route,
|
||||||
cone_sender, symmetric_sender, cipher);
|
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 nat_test = nat_test.clone();
|
||||||
let device_list = device_list.clone();
|
let device_list = device_list.clone();
|
||||||
let current_device = current_device.clone();
|
let current_device = current_device.clone();
|
||||||
//其他任务处理
|
// 定时心跳
|
||||||
thread::spawn(move || {
|
heartbeat_handler::start_heartbeat(other_worker.worker("heartbeat"), channel_sender.clone(), device_list.clone(), current_device.clone(), config.server_address_str);
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
// 空闲检查
|
||||||
.enable_all()
|
heartbeat_handler::start_idle(other_worker.worker("idle"), idle, channel_sender.clone());
|
||||||
.build().unwrap()
|
// 打洞处理
|
||||||
.block_on(async move {
|
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());
|
||||||
heartbeat_handler::start_heartbeat(other_worker.clone(), channel_sender.clone(), device_list.clone(), current_device.clone());
|
tokio::spawn(punch_handler::start_punch(other_worker, nat_test,
|
||||||
// 空闲检查
|
device_list, channel_sender, current_device));
|
||||||
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;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
context.switch(nat_test.nat_info().nat_type);
|
context.switch(nat_test.nat_info().nat_type);
|
||||||
Ok(Switch {
|
Ok(Switch {
|
||||||
@@ -251,7 +240,6 @@ impl SwitchUtil {
|
|||||||
current_device,
|
current_device,
|
||||||
context,
|
context,
|
||||||
switch_status_manager,
|
switch_status_manager,
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
|
||||||
device_writer,
|
device_writer,
|
||||||
nat_test,
|
nat_test,
|
||||||
device_list,
|
device_list,
|
||||||
@@ -295,14 +283,33 @@ impl Switch {
|
|||||||
pub fn stop(&self) -> io::Result<()> {
|
pub fn stop(&self) -> io::Result<()> {
|
||||||
self.context.close();
|
self.context.close();
|
||||||
self.switch_status_manager.stop_all();
|
self.switch_status_manager.stop_all();
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
|
||||||
self.device_writer.close()?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub async fn wait_stop(&mut self) {
|
pub async fn wait_stop(&mut self) {
|
||||||
self.switch_status_manager.wait().await;
|
self.switch_status_manager.wait().await;
|
||||||
let _ = self.stop();
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -312,11 +319,13 @@ pub struct Config {
|
|||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub server_address: SocketAddr,
|
pub server_address: SocketAddr,
|
||||||
|
pub server_address_str: String,
|
||||||
pub nat_test_server: Vec<SocketAddr>,
|
pub nat_test_server: Vec<SocketAddr>,
|
||||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
pub out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
pub out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
pub key: Option<[u8; 32]>,
|
pub key: Option<[u8; 32]>,
|
||||||
pub simulate_multicast: bool,
|
pub simulate_multicast: bool,
|
||||||
|
pub mtu: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -325,9 +334,10 @@ impl Config {
|
|||||||
device_id: String,
|
device_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
server_address: SocketAddr,
|
server_address: SocketAddr,
|
||||||
|
server_address_str: String,
|
||||||
nat_test_server: Vec<SocketAddr>,
|
nat_test_server: Vec<SocketAddr>,
|
||||||
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
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 key = if let Some(password) = password {
|
||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
hasher.update(password.as_bytes());
|
hasher.update(password.as_bytes());
|
||||||
@@ -342,11 +352,13 @@ impl Config {
|
|||||||
device_id,
|
device_id,
|
||||||
name,
|
name,
|
||||||
server_address,
|
server_address,
|
||||||
|
server_address_str,
|
||||||
nat_test_server,
|
nat_test_server,
|
||||||
in_ips,
|
in_ips,
|
||||||
out_ips,
|
out_ips,
|
||||||
key,
|
key,
|
||||||
simulate_multicast,
|
simulate_multicast,
|
||||||
|
mtu,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,15 +10,17 @@ pub enum SwitchStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SwitchWorker {
|
pub struct SwitchWorker {
|
||||||
|
_name: String,
|
||||||
wg: WaitGroup,
|
wg: WaitGroup,
|
||||||
status_s: Arc<Sender<SwitchStatus>>,
|
status_s: Arc<Sender<SwitchStatus>>,
|
||||||
status_r: Receiver<SwitchStatus>,
|
status_r: Receiver<SwitchStatus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for SwitchWorker {
|
impl SwitchWorker {
|
||||||
fn clone(&self) -> Self {
|
pub fn worker(&self, name: &str) -> Self {
|
||||||
self.wg.add();
|
self.wg.add();
|
||||||
SwitchWorker {
|
SwitchWorker {
|
||||||
|
_name: name.to_string(),
|
||||||
wg: self.wg.clone(),
|
wg: self.wg.clone(),
|
||||||
status_s: self.status_s.clone(),
|
status_s: self.status_s.clone(),
|
||||||
status_r: self.status_r.clone(),
|
status_r: self.status_r.clone(),
|
||||||
@@ -53,6 +55,7 @@ impl SwitchWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SwitchStatusManger {
|
pub struct SwitchStatusManger {
|
||||||
wg: WaitGroup,
|
wg: WaitGroup,
|
||||||
status_s: Arc<Sender<SwitchStatus>>,
|
status_s: Arc<Sender<SwitchStatus>>,
|
||||||
@@ -74,9 +77,10 @@ impl SwitchStatusManger {
|
|||||||
pub async fn wait(&mut self) {
|
pub async fn wait(&mut self) {
|
||||||
self.wg.wait().await
|
self.wg.wait().await
|
||||||
}
|
}
|
||||||
pub fn worker(&self) -> SwitchWorker {
|
pub fn worker(&self, name: &str) -> SwitchWorker {
|
||||||
self.wg.add();
|
self.wg.add();
|
||||||
SwitchWorker {
|
SwitchWorker {
|
||||||
|
_name: name.to_string(),
|
||||||
wg: self.wg.clone(),
|
wg: self.wg.clone(),
|
||||||
status_s: self.status_s.clone(),
|
status_s: self.status_s.clone(),
|
||||||
status_r: self.status_r.clone(),
|
status_r: self.status_r.clone(),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub struct SwitchSync {
|
|||||||
|
|
||||||
impl SwitchUtilSync {
|
impl SwitchUtilSync {
|
||||||
pub fn new(config: Config) -> io::Result<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))?;
|
let switch_util = runtime.block_on(SwitchUtil::new(config))?;
|
||||||
Ok(SwitchUtilSync {
|
Ok(SwitchUtilSync {
|
||||||
switch_util,
|
switch_util,
|
||||||
@@ -38,9 +38,15 @@ impl SwitchUtilSync {
|
|||||||
pub fn build(self) -> crate::Result<SwitchSync> {
|
pub fn build(self) -> crate::Result<SwitchSync> {
|
||||||
let runtime = self.runtime;
|
let runtime = self.runtime;
|
||||||
let switch = runtime.block_on(self.switch_util.build())?;
|
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 {
|
Ok(SwitchSync {
|
||||||
switch,
|
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())
|
self.runtime.block_on(self.switch.wait_stop())
|
||||||
}
|
}
|
||||||
pub fn wait_stop_ms(&mut self, ms: u64) -> bool {
|
pub fn wait_stop_ms(&mut self, ms: u64) -> bool {
|
||||||
self.runtime.block_on(tokio::time::timeout(Duration::from_millis(ms),
|
self.runtime.block_on(self.switch.wait_stop_ms(Duration::from_millis(ms)))
|
||||||
self.switch.wait_stop())).is_ok()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
// 目标ip,子网掩码,网关
|
// 目标ip,子网掩码,网关
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ExternalRoute {
|
pub struct ExternalRoute {
|
||||||
route_table: Vec<(u32, u32, Ipv4Addr)>,
|
route_table: Arc<Vec<(u32, u32, Ipv4Addr)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternalRoute {
|
impl ExternalRoute {
|
||||||
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
|
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
route_table
|
route_table:Arc::new(route_table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
|
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
|
||||||
let ip = u32::from_be_bytes(ip.octets());
|
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 {
|
if *mask & ip == *mask & *dest {
|
||||||
return Some(*gateway);
|
return Some(*gateway);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -49,13 +49,14 @@ pub fn start_heartbeat(
|
|||||||
sender: ChannelSender,
|
sender: ChannelSender,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
server_address_str: String,
|
||||||
) {
|
) {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_=worker.stop_wait()=>{
|
_=worker.stop_wait()=>{
|
||||||
return;
|
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 {
|
if let Err(e) = rs {
|
||||||
log::warn!("心跳任务停止:{:?}", e);
|
log::warn!("心跳任务停止:{:?}", e);
|
||||||
}
|
}
|
||||||
@@ -76,6 +77,7 @@ async fn start_heartbeat_(
|
|||||||
sender: ChannelSender,
|
sender: ChannelSender,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
server_address_str: String,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let mut net_packet = NetPacket::new([0u8; 16])?;
|
let mut net_packet = NetPacket::new([0u8; 16])?;
|
||||||
net_packet.set_version(Version::V1);
|
net_packet.set_version(Version::V1);
|
||||||
@@ -88,20 +90,33 @@ async fn start_heartbeat_(
|
|||||||
if sender.is_close() {
|
if sender.is_close() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let current_device = current_device.load();
|
let mut current_dev = current_device.load();
|
||||||
net_packet.set_source(current_device.virtual_ip());
|
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 mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||||
let epoch = { device_list.lock().0 };
|
let epoch = { device_list.lock().0 };
|
||||||
ping.set_epoch(epoch);
|
ping.set_epoch(epoch);
|
||||||
}
|
}
|
||||||
set_now_time(&mut net_packet)?;
|
set_now_time(&mut net_packet)?;
|
||||||
net_packet.set_destination(current_device.virtual_gateway());
|
net_packet.set_destination(current_dev.virtual_gateway());
|
||||||
if let Err(e) = sender.send_main(net_packet.buffer(), current_device.connect_server).await
|
if let Err(e) = sender.send_main(net_packet.buffer(), current_dev.connect_server).await
|
||||||
{
|
{
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"connect_server:{:?},e:{:?}",
|
"connect_server:{:?},e:{:?}",
|
||||||
current_device.connect_server,
|
current_dev.connect_server,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -109,7 +124,7 @@ async fn start_heartbeat_(
|
|||||||
let mut route_list: Option<Vec<(Ipv4Addr, Vec<Route>)>> = None;
|
let mut route_list: Option<Vec<(Ipv4Addr, Vec<Route>)>> = None;
|
||||||
let peer_list = { device_list.lock().1.clone() };
|
let peer_list = { device_list.lock().1.clone() };
|
||||||
for peer in peer_list {
|
for peer in peer_list {
|
||||||
if peer.virtual_ip == current_device.virtual_ip {
|
if peer.virtual_ip == current_dev.virtual_ip {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
set_now_time(&mut net_packet)?;
|
set_now_time(&mut net_packet)?;
|
||||||
@@ -121,7 +136,7 @@ async fn start_heartbeat_(
|
|||||||
}
|
}
|
||||||
} else {
|
} 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,8 +78,6 @@ pub async fn start_punch(
|
|||||||
}
|
}
|
||||||
num += 1;
|
num += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.stop_all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_punch_(
|
async fn start_punch_(
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use crate::channel::{Route, RouteKey};
|
|||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::external_route::ExternalRoute;
|
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::handle::registration_handler::Register;
|
||||||
use crate::igmp_server::IgmpServer;
|
use crate::igmp_server::IgmpServer;
|
||||||
use crate::ip_proxy::IpProxyMap;
|
use crate::ip_proxy::IpProxyMap;
|
||||||
@@ -362,7 +362,9 @@ impl ChannelDataHandler {
|
|||||||
.collect();
|
.collect();
|
||||||
let route = Route::from(*route_key, 2, 99);
|
let route = Route::from(*route_key, 2, 99);
|
||||||
for x in &ip_list {
|
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();
|
let mut dev = self.device_list.lock();
|
||||||
if dev.0 != device_list_t.epoch as u16 {
|
if dev.0 != device_list_t.epoch as u16 {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crossbeam_utils::atomic::AtomicCell;
|
|||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
use crate::channel::sender::ChannelSender;
|
use crate::channel::sender::ChannelSender;
|
||||||
|
use crate::handle::PeerDeviceInfo;
|
||||||
|
|
||||||
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
||||||
use crate::protocol::error_packet::InErrorPacket;
|
use crate::protocol::error_packet::InErrorPacket;
|
||||||
@@ -24,7 +25,8 @@ pub struct RegResponse {
|
|||||||
pub virtual_ip: Ipv4Addr,
|
pub virtual_ip: Ipv4Addr,
|
||||||
pub virtual_gateway: Ipv4Addr,
|
pub virtual_gateway: Ipv4Addr,
|
||||||
pub virtual_netmask: Ipv4Addr,
|
pub virtual_netmask: Ipv4Addr,
|
||||||
pub epoch: u32,
|
pub epoch: u16,
|
||||||
|
pub device_info_list: Vec<PeerDeviceInfo>,
|
||||||
pub public_ip: Ipv4Addr,
|
pub public_ip: Ipv4Addr,
|
||||||
pub public_port: u16,
|
pub public_port: u16,
|
||||||
}
|
}
|
||||||
@@ -62,11 +64,23 @@ pub async fn registration(
|
|||||||
service_packet::Protocol::RegistrationResponse => {
|
service_packet::Protocol::RegistrationResponse => {
|
||||||
match RegistrationResponse::parse_from_bytes(net_packet.payload()) {
|
match RegistrationResponse::parse_from_bytes(net_packet.payload()) {
|
||||||
Ok(response) => {
|
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 {
|
Ok(RegResponse {
|
||||||
virtual_ip: Ipv4Addr::from(response.virtual_ip),
|
virtual_ip: Ipv4Addr::from(response.virtual_ip),
|
||||||
virtual_gateway: Ipv4Addr::from(response.virtual_gateway),
|
virtual_gateway: Ipv4Addr::from(response.virtual_gateway),
|
||||||
virtual_netmask: Ipv4Addr::from(response.virtual_netmask),
|
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_ip: Ipv4Addr::from(response.public_ip),
|
||||||
public_port: response.public_port as u16,
|
public_port: response.public_port as u16,
|
||||||
})
|
})
|
||||||
@@ -134,7 +148,7 @@ fn registration_request_packet(
|
|||||||
request.device_id = device_id;
|
request.device_id = device_id;
|
||||||
request.name = name;
|
request.name = name;
|
||||||
request.is_fast = is_fast;
|
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 bytes = request.write_to_bytes()?;
|
||||||
let buf = vec![0u8; 12 + bytes.len()];
|
let buf = vec![0u8; 12 + bytes.len()];
|
||||||
let mut net_packet = NetPacket::new(buf)?;
|
let mut net_packet = NetPacket::new(buf)?;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender,
|
|||||||
ip_route: Option<ExternalRoute>,
|
ip_route: Option<ExternalRoute>,
|
||||||
ip_proxy_map: Option<IpProxyMap>,
|
ip_proxy_map: Option<IpProxyMap>,
|
||||||
cipher: Option<Aes256Gcm>) {
|
cipher: Option<Aes256Gcm>) {
|
||||||
thread::spawn(move || {
|
thread::Builder::new().name("tap_handler".into()).spawn(move || {
|
||||||
tokio::runtime::Builder::new_current_thread()
|
tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all().build().unwrap()
|
.enable_all().build().unwrap()
|
||||||
.block_on(async move {
|
.block_on(async move {
|
||||||
@@ -36,7 +36,7 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender,
|
|||||||
}
|
}
|
||||||
worker.stop_all();
|
worker.stop_all();
|
||||||
});
|
});
|
||||||
});
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_(sender: ChannelSender,
|
async fn start_(sender: ChannelSender,
|
||||||
|
|||||||
@@ -62,21 +62,22 @@ pub fn start(worker: SwitchWorker, sender: ChannelSender,
|
|||||||
ip_route: Option<ExternalRoute>,
|
ip_route: Option<ExternalRoute>,
|
||||||
ip_proxy_map: Option<IpProxyMap>,
|
ip_proxy_map: Option<IpProxyMap>,
|
||||||
cipher: Option<Aes256Gcm>) {
|
cipher: Option<Aes256Gcm>) {
|
||||||
thread::spawn(move || {
|
thread::Builder::new().name("tun_handler".into()).spawn(move || {
|
||||||
tokio::runtime::Builder::new_current_thread()
|
tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all().build().unwrap()
|
.enable_all().build().unwrap()
|
||||||
.block_on(async move {
|
.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 {
|
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);
|
log::warn!("stop:{}",e);
|
||||||
}
|
}
|
||||||
|
let _ = device_writer.close();
|
||||||
worker.stop_all();
|
worker.stop_all();
|
||||||
})
|
})
|
||||||
});
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_(sender: ChannelSender,
|
async fn start_(sender: ChannelSender,
|
||||||
device_reader: DeviceReader,
|
device_reader: DeviceReader,
|
||||||
device_writer: DeviceWriter,
|
device_writer: &DeviceWriter,
|
||||||
igmp_server: Option<IgmpServer>,
|
igmp_server: Option<IgmpServer>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
ip_route: Option<ExternalRoute>,
|
ip_route: Option<ExternalRoute>,
|
||||||
@@ -88,7 +89,7 @@ async fn start_(sender: ChannelSender,
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let len = device_reader.read(&mut buf[12..])? + 12;
|
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(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("{:?}", e)
|
log::warn!("{:?}", e)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub struct DeviceReader(RawFd);
|
|||||||
impl DeviceWriter {
|
impl DeviceWriter {
|
||||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||||
unsafe {
|
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 {
|
if amount < 0 {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
@@ -21,12 +21,18 @@ impl DeviceWriter {
|
|||||||
let buf = &buf[14..];
|
let buf = &buf[14..];
|
||||||
self.write_ipv4_tun(buf)
|
self.write_ipv4_tun(buf)
|
||||||
}
|
}
|
||||||
|
pub fn close(&self) -> io::Result<()> {
|
||||||
|
// unsafe {
|
||||||
|
// libc::close(self.0);
|
||||||
|
// }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceReader {
|
impl DeviceReader {
|
||||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
unsafe {
|
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 {
|
if amount < 0 {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error());
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ impl DeviceWriter {
|
|||||||
.destination(gateway)
|
.destination(gateway)
|
||||||
.address(address)
|
.address(address)
|
||||||
.netmask(netmask)
|
.netmask(netmask)
|
||||||
.mtu(1420)
|
|
||||||
// .queues(2)
|
// .queues(2)
|
||||||
.up();
|
.up();
|
||||||
let mut dev = self.lock.lock();
|
let mut dev = self.lock.lock();
|
||||||
@@ -56,6 +55,7 @@ pub fn create_device(device_type: DeviceType,
|
|||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
|
mtu: u16,
|
||||||
) -> io::Result<(DeviceWriter, DeviceReader,DriverInfo)> {
|
) -> io::Result<(DeviceWriter, DeviceReader,DriverInfo)> {
|
||||||
let mut config = tun::Configuration::default();
|
let mut config = tun::Configuration::default();
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ pub fn create_device(device_type: DeviceType,
|
|||||||
.destination(gateway)
|
.destination(gateway)
|
||||||
.address(address)
|
.address(address)
|
||||||
.netmask(netmask)
|
.netmask(netmask)
|
||||||
.mtu(1420)
|
.mtu(mtu.into())
|
||||||
// .queues(2) 用多个队列有兼容性问题
|
// .queues(2) 用多个队列有兼容性问题
|
||||||
.up();
|
.up();
|
||||||
match device_type {
|
match device_type {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use bytes::BufMut;
|
|||||||
use tun::platform::posix::{Reader, Writer};
|
use tun::platform::posix::{Reader, Writer};
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
|
||||||
#[cfg(any(target_os = "linux"))]
|
#[cfg(any(target_os = "linux"))]
|
||||||
use tun::platform::linux::Device;
|
use tun::platform::linux::Device;
|
||||||
#[cfg(any(target_os = "macos"))]
|
#[cfg(any(target_os = "macos"))]
|
||||||
@@ -38,17 +37,15 @@ pub struct DeviceWriter {
|
|||||||
writer: DeviceW,
|
writer: DeviceW,
|
||||||
pub lock: Arc<Mutex<Device>>,
|
pub lock: Arc<Mutex<Device>>,
|
||||||
pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
ip: Arc<AtomicCell<Ipv4Addr>>,
|
|
||||||
packet_information: bool,
|
packet_information: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceWriter {
|
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 {
|
Self {
|
||||||
writer,
|
writer,
|
||||||
lock,
|
lock,
|
||||||
in_ips,
|
in_ips,
|
||||||
ip: Arc::new(AtomicCell::new(ip)),
|
|
||||||
packet_information,
|
packet_information,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,9 +104,6 @@ impl DeviceWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn ip(&self) -> Ipv4Addr {
|
|
||||||
self.ip.load()
|
|
||||||
}
|
|
||||||
pub fn close(&self) -> io::Result<()> {
|
pub fn close(&self) -> io::Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
match &self.writer {
|
match &self.writer {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ impl DeviceWriter {
|
|||||||
.destination(gateway)
|
.destination(gateway)
|
||||||
.address(address)
|
.address(address)
|
||||||
.netmask(netmask)
|
.netmask(netmask)
|
||||||
.mtu(1420)
|
|
||||||
.up();
|
.up();
|
||||||
let mut dev = self.lock.lock();
|
let mut dev = self.lock.lock();
|
||||||
if let Err(e) = dev.configure(&config) {
|
if let Err(e) = dev.configure(&config) {
|
||||||
@@ -42,7 +41,8 @@ pub fn create_device(device_type: DeviceType,
|
|||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
) -> io::Result<(DeviceWriter, DeviceReader,DriverInfo)> {
|
mtu: u16,
|
||||||
|
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||||
match device_type {
|
match device_type {
|
||||||
DeviceType::Tun => {}
|
DeviceType::Tun => {}
|
||||||
DeviceType::Tap => {
|
DeviceType::Tap => {
|
||||||
@@ -55,7 +55,7 @@ pub fn create_device(device_type: DeviceType,
|
|||||||
.destination(gateway)
|
.destination(gateway)
|
||||||
.address(address)
|
.address(address)
|
||||||
.netmask(netmask)
|
.netmask(netmask)
|
||||||
.mtu(1420)
|
.mtu(mtu.into())
|
||||||
.up();
|
.up();
|
||||||
|
|
||||||
let dev = tun::create(&config).unwrap();
|
let dev = tun::create(&config).unwrap();
|
||||||
@@ -75,8 +75,8 @@ pub fn create_device(device_type: DeviceType,
|
|||||||
let writer = queue.writer();
|
let writer = queue.writer();
|
||||||
let driver_info = DriverInfo {
|
let driver_info = DriverInfo {
|
||||||
device_type,
|
device_type,
|
||||||
name:name.to_string(),
|
name: name.to_string(),
|
||||||
version:String::new(),
|
version: String::new(),
|
||||||
mac: None,
|
mac: None,
|
||||||
};
|
};
|
||||||
Ok((
|
Ok((
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ impl DeviceType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct DriverInfo {
|
pub struct DriverInfo {
|
||||||
pub device_type: DeviceType,
|
pub device_type: DeviceType,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
|
||||||
use libloading::Library;
|
use libloading::Library;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use packet::ethernet;
|
use packet::ethernet;
|
||||||
@@ -37,16 +37,14 @@ pub struct DeviceWriter {
|
|||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
lock: Arc<Mutex<()>>,
|
lock: Arc<Mutex<()>>,
|
||||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
ip: Arc<AtomicCell<Ipv4Addr>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceWriter {
|
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 {
|
Self {
|
||||||
device,
|
device,
|
||||||
lock: Arc::new(Default::default()),
|
lock: Arc::new(Default::default()),
|
||||||
in_ips,
|
in_ips,
|
||||||
ip: Arc::new(AtomicCell::new(ip)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +118,6 @@ impl DeviceWriter {
|
|||||||
log::warn!("{:?}", e);
|
log::warn!("{:?}", e);
|
||||||
}
|
}
|
||||||
dev.set_ip(address, netmask)?;
|
dev.set_ip(address, netmask)?;
|
||||||
self.ip.store(address);
|
|
||||||
for (address, netmask) in &self.in_ips {
|
for (address, netmask) in &self.in_ips {
|
||||||
dev.add_route(*address, *netmask, gateway, 1)?;
|
dev.add_route(*address, *netmask, gateway, 1)?;
|
||||||
}
|
}
|
||||||
@@ -132,9 +129,6 @@ impl DeviceWriter {
|
|||||||
delete_cache();
|
delete_cache();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn ip(&self) -> Ipv4Addr {
|
|
||||||
self.ip.load()
|
|
||||||
}
|
|
||||||
pub fn close(&self) -> io::Result<()> {
|
pub fn close(&self) -> io::Result<()> {
|
||||||
match self.device.as_ref() {
|
match self.device.as_ref() {
|
||||||
Device::Tun(dev) => {
|
Device::Tun(dev) => {
|
||||||
@@ -198,6 +192,7 @@ fn create_tun(
|
|||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
|
mtu: u16,
|
||||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||||
unsafe {
|
unsafe {
|
||||||
match Library::new("wintun.dll") {
|
match Library::new("wintun.dll") {
|
||||||
@@ -241,7 +236,7 @@ fn create_tun(
|
|||||||
let version = format!("{:?}", tun_device.version()?);
|
let version = format!("{:?}", tun_device.version()?);
|
||||||
tun_device.set_ip(address, netmask)?;
|
tun_device.set_ip(address, netmask)?;
|
||||||
tun_device.set_metric(1)?;
|
tun_device.set_metric(1)?;
|
||||||
tun_device.set_mtu(1420)?;
|
tun_device.set_mtu(mtu)?;
|
||||||
// ip代理路由
|
// ip代理路由
|
||||||
for (address, netmask) in &in_ips {
|
for (address, netmask) in &in_ips {
|
||||||
tun_device.add_route(*address, *netmask, gateway, 1)?;
|
tun_device.add_route(*address, *netmask, gateway, 1)?;
|
||||||
@@ -271,6 +266,7 @@ fn delete_cache() {
|
|||||||
//清除路由缓存
|
//清除路由缓存
|
||||||
let delete_cache = "netsh interface ip delete destinationcache";
|
let delete_cache = "netsh interface ip delete destinationcache";
|
||||||
let out = std::process::Command::new("cmd")
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(0x08000000)
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(delete_cache)
|
.arg(delete_cache)
|
||||||
.output()
|
.output()
|
||||||
@@ -297,6 +293,7 @@ fn create_tap(
|
|||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
|
mtu: u16,
|
||||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||||
Ok(tap_device) => tap_device,
|
Ok(tap_device) => tap_device,
|
||||||
@@ -313,7 +310,7 @@ fn create_tap(
|
|||||||
let mac_str = format!("mac:{:x?}", mac);
|
let mac_str = format!("mac:{:x?}", mac);
|
||||||
tap_device.set_ip(address, netmask)?;
|
tap_device.set_ip(address, netmask)?;
|
||||||
tap_device.set_metric(1)?;
|
tap_device.set_metric(1)?;
|
||||||
tap_device.set_mtu(1420)?;
|
tap_device.set_mtu(mtu)?;
|
||||||
tap_device.set_status(true)?;
|
tap_device.set_status(true)?;
|
||||||
tap_device.add_route(address, netmask, gateway, 1)?;
|
tap_device.add_route(address, netmask, gateway, 1)?;
|
||||||
for (address, netmask) in &in_ips {
|
for (address, netmask) in &in_ips {
|
||||||
@@ -350,13 +347,14 @@ fn delete_tap() {
|
|||||||
pub fn create_device(device_type: DeviceType, address: Ipv4Addr,
|
pub fn create_device(device_type: DeviceType, address: Ipv4Addr,
|
||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: 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 {
|
match device_type {
|
||||||
DeviceType::Tun => {
|
DeviceType::Tun => {
|
||||||
create_tun(address, netmask, gateway, in_ips)
|
create_tun(address, netmask, gateway, in_ips, mtu)
|
||||||
}
|
}
|
||||||
DeviceType::Tap => {
|
DeviceType::Tap => {
|
||||||
create_tap(address, netmask, gateway, in_ips)
|
create_tap(address, netmask, gateway, in_ips, mtu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
/// 设置网卡名称
|
/// 设置网卡名称
|
||||||
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
|
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 cmd = format!(" netsh interface set interface name={:?} newname={:?}", old_name, new_name);
|
||||||
let out = std::process::Command::new("cmd")
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(0x08000000) //winapi-0.3.9/src/um/winbase.rs:283
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(&cmd)
|
.arg(&cmd)
|
||||||
.output()?;
|
.output()?;
|
||||||
@@ -21,6 +23,7 @@ pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> i
|
|||||||
index, address, netmask,
|
index, address, netmask,
|
||||||
);
|
);
|
||||||
let out = std::process::Command::new("cmd")
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(0x08000000)
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(&set_address)
|
.arg(&set_address)
|
||||||
.output()?;
|
.output()?;
|
||||||
@@ -37,6 +40,7 @@ pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> {
|
|||||||
index, mtu
|
index, mtu
|
||||||
);
|
);
|
||||||
let out = std::process::Command::new("cmd")
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(0x08000000)
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(&set_mtu)
|
.arg(&set_mtu)
|
||||||
.output()?;
|
.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<()> {
|
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
|
||||||
let set_metric = format!("netsh interface ip set interface {} metric={}", index,metric);
|
let set_metric = format!("netsh interface ip set interface {} metric={}", index,metric);
|
||||||
let out = std::process::Command::new("cmd")
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(0x08000000)
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(&set_metric)
|
.arg(&set_metric)
|
||||||
.output()?;
|
.output()?;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
/// 添加路由
|
/// 添加路由
|
||||||
pub fn add_route(index: u32, dest: Ipv4Addr,
|
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")
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(0x08000000)
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(&set_route)
|
.arg(&set_route)
|
||||||
.output()
|
.output()
|
||||||
@@ -33,6 +35,7 @@ pub fn delete_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4
|
|||||||
);
|
);
|
||||||
// 删除路由
|
// 删除路由
|
||||||
let out = std::process::Command::new("cmd")
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(0x08000000)
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(delete_route)
|
.arg(delete_route)
|
||||||
.output()
|
.output()
|
||||||
|
|||||||
Reference in New Issue
Block a user