Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f104e191ed | ||
|
|
6311d75ac0 | ||
|
|
c3f134e332 | ||
|
|
5bccdf3bbe | ||
|
|
9e881eeecd | ||
|
|
fbe01d8cbf | ||
|
|
d336d938a9 | ||
|
|
598923c95a | ||
|
|
0afe4c4417 | ||
|
|
dff51caf35 | ||
|
|
7c30f2691a | ||
|
|
c6aca2c2dc | ||
|
|
28ac8cf88e | ||
|
|
62b2af54a2 | ||
|
|
a2d45da44d | ||
|
|
d937f392d3 | ||
|
|
2c9abf314a | ||
|
|
ab7abd0c1f | ||
|
|
71a2e3c592 | ||
|
|
aa6d3a6843 | ||
|
|
9b42c5d092 | ||
|
|
2f7817ce5b | ||
|
|
e7c6bcf9a9 | ||
|
|
b6b8971b12 | ||
|
|
ba4a0e008b | ||
|
|
4baccc5047 | ||
|
|
6cf71c8068 | ||
|
|
8e556a20ee | ||
|
|
5f28a5044a | ||
|
|
16d295bf32 | ||
|
|
32163e077e | ||
|
|
6a5a40a7d3 | ||
|
|
161ecc865c | ||
|
|
1a5d40ff2d | ||
|
|
6b988e0612 | ||
|
|
8d44934382 | ||
|
|
6b140b0f71 | ||
|
|
c2b7b02f3f | ||
|
|
24140c2145 | ||
|
|
a6050e5f59 | ||
|
|
50e97fd95f | ||
|
|
890e5f7391 | ||
|
|
be3bf82e35 | ||
|
|
e8af503130 | ||
|
|
466174ef88 | ||
|
|
ba2c792e2a | ||
|
|
17f3fcf9b0 | ||
|
|
11d1ff4b42 | ||
|
|
b640bc50ef | ||
|
|
4bbd5282ee | ||
|
|
d7fd504f8f | ||
|
|
cf4375b405 | ||
|
|
45da060c1a | ||
|
|
4dc84914dd | ||
|
|
c1ee7ac11c | ||
|
|
409b57c171 | ||
|
|
ff4580b9bf | ||
|
|
6daa75d2f2 | ||
|
|
59f07f2d75 | ||
|
|
44035685c8 |
@@ -40,34 +40,50 @@ jobs:
|
||||
include:
|
||||
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: x86_64-unknown-linux-gnu # tested in a debian container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-unknown-linux-gnu # tested on aws t4g.nano
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: armv7-unknown-linux-gnueabihf # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: arm-unknown-linux-gnueabihf # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: i686-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-latest
|
||||
FEATURES: ring-cipher
|
||||
# needs: test
|
||||
runs-on: ${{ matrix.OS }}
|
||||
env:
|
||||
NAME: switch-desktop # change with the name of your project
|
||||
NAME: vnt-cli # change with the name of your project
|
||||
TARGET: ${{ matrix.TARGET }}
|
||||
OS: ${{ matrix.OS }}
|
||||
FEATURES: ${{ matrix.FEATURES }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Init submodules
|
||||
@@ -86,7 +102,7 @@ jobs:
|
||||
# dependencies are only needed on ubuntu as that's the only place where
|
||||
# we make cross-compilation
|
||||
if [[ $OS =~ ^ubuntu.*$ ]]; then
|
||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf
|
||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools
|
||||
fi
|
||||
# some additional configuration for cross-compilation on linux
|
||||
cat >>~/.cargo/config <<EOF
|
||||
@@ -106,7 +122,7 @@ jobs:
|
||||
- name: Install rust target
|
||||
run: rustup target add $TARGET
|
||||
- name: Run build
|
||||
run: cargo build --package switch-desktop --release --verbose --target $TARGET
|
||||
run: cargo build --package vnt-cli --release --verbose --target $TARGET --features $FEATURES
|
||||
- name: List target
|
||||
run: find ./target
|
||||
- name: Compress
|
||||
@@ -123,12 +139,12 @@ jobs:
|
||||
else
|
||||
TAG=$GITHUB_SHA
|
||||
fi
|
||||
mv ./target/$TARGET/release/$EXEC ./$EXEC
|
||||
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz $EXEC
|
||||
mv ./target/$TARGET/release/$EXEC ./artifacts/$EXEC
|
||||
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz -C ./artifacts $EXEC
|
||||
- name: Archive artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: switch-desktop
|
||||
name: vnt-cli
|
||||
path: |
|
||||
./artifacts
|
||||
# deploys to github releases on tag
|
||||
@@ -140,7 +156,7 @@ jobs:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: switch-desktop
|
||||
name: vnt-cli
|
||||
path: ./artifacts
|
||||
- name: List
|
||||
run: find ./artifacts
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "switch/p2p_channel"]
|
||||
path = switch/p2p_channel
|
||||
url = https://github.com/lbl8603/p2p_channel
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = ["switch","switch-desktop"]
|
||||
members = ["vnt","common","vnt-cli","vnt-jni"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = 'z'
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
# switch
|
||||
A virtual network tool (VPN)
|
||||
# Vnt
|
||||
|
||||
A virtual network tool (VPN)
|
||||
|
||||
将不同网络下的多个设备虚拟到一个局域网下
|
||||
|
||||
|
||||
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
|
||||
### 快速使用:
|
||||
|
||||
1. 指定一个token,在多台设备上运行该程序,例如:
|
||||
```shell
|
||||
# linux上
|
||||
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop start --token 123456
|
||||
# 在另一台linux上使用nohup后台运行,不在命令行指定配置时,将在home/.switch_desktop/config文件中读取配置
|
||||
[root@izj6cemne76ykdzkataftfz switch]# nohup ./switch-desktop start &
|
||||
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli -k 123456
|
||||
# 在另一台linux上使用nohup后台运行
|
||||
root@izj6cemne76ykdzkataftfz vnt# nohup ./vnt-cli -k 123456 &
|
||||
# windows上
|
||||
D:\switch\bin_v1>switch-desktop.exe start --token 123456
|
||||
D:\vnt\bin_v1>vnt-cli.exe -k 123456
|
||||
```
|
||||
2. 可以执行status命令查看当前设备的虚拟ip
|
||||
2. 可以执行info命令查看当前设备的虚拟ip
|
||||
```shell
|
||||
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop status
|
||||
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli --info
|
||||
Name: Ubuntu 18.04 (bionic) [64-bit]
|
||||
Virtual ip: 10.26.0.2
|
||||
Virtual gateway: 10.26.0.1
|
||||
@@ -30,59 +30,105 @@
|
||||
```
|
||||
3. 也可以执行list命令查看其他设备的虚拟ip
|
||||
```shell
|
||||
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop list
|
||||
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli --list
|
||||
Name Virtual Ip P2P/Relay Rt Status
|
||||
Windows 10.0.22621 (Windows 11 Professional) [64-bit] 10.26.0.3 p2p 2 Online
|
||||
CentOS 7.9.2009 (Core) [64-bit] 10.26.0.4 p2p 35 Online
|
||||
```
|
||||
4. 最后可以用虚拟ip实现设备间相互访问
|
||||
1. ping
|
||||
|
||||
<img width="506" alt="ping" src="https://raw.githubusercontent.com/lbl8603/switch/dev/documents/img/ping.jpg">
|
||||
2. ssh
|
||||
|
||||
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/switch/dev/documents/img/ssh.jpg">
|
||||
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/vnt/dev/documents/img/ssh.jpg">
|
||||
5. 帮助,使用-h命令查看
|
||||
|
||||
### 更多玩法
|
||||
|
||||
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
|
||||
2. 安装samba服务,共享磁盘
|
||||
3. 搭配公网服务器nginx反向代理,在公网访问本地文件
|
||||
4. 点对网(结合启动参数'--in-ip'和'--out-ip')
|
||||
|
||||
3. 搭配公网服务器nginx反向代理,在公网访问内网文件或服务
|
||||
4. 点对网,访问内网其他机器、IP代理(结合启动参数'-i'和'-o')
|
||||
|
||||
### 使用须知
|
||||
|
||||
- token的作用是标识一个虚拟局域网,当使用公共服务器时,建议使用一个唯一值当token(比如uuid),否则有可能连接到其他人创建的虚拟局域网中
|
||||
- 建议指定deviceId,默认使用MAC地址,在某些环境下可能发生变化
|
||||
- 公共服务器目前的配置是2核4G 4Mbps,有需要再扩展~
|
||||
- 默认使用公共服务器,目前的配置是2核4G 4Mbps,有需要再扩展~
|
||||
- 需要root/管理员权限
|
||||
- 使用命令行运行
|
||||
- Mac和Linux下需要加可执行权限(例如:chmod +x ./switch-macos)
|
||||
- 自己搭注册和中继服务器(https://github.com/lbl8603/switch-server)
|
||||
- vnt-cli需要使用命令行运行
|
||||
- Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli)
|
||||
- 可以自己搭注册和中继服务器([server](https://github.com/lbl8603/vnts))
|
||||
|
||||
### 编译
|
||||
前提条件:安装rust编译环境(https://www.rust-lang.org/zh-CN/tools/install)
|
||||
|
||||
到项目根目录下执行 cargo build -p switch-desktop
|
||||
|
||||
|
||||
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
|
||||
|
||||
到项目根目录下执行 cargo build -p vnt-cli
|
||||
|
||||
### 支持平台
|
||||
|
||||
- Mac
|
||||
- Linux
|
||||
- Windows
|
||||
- 使用tun网卡 依赖wintun.dll(https://www.wintun.net/)
|
||||
- 使用tap网卡 依赖tap-windows(https://build.openvpn.net/downloads/releases/)
|
||||
- 使用tun网卡 依赖wintun.dll([win-tun](https://www.wintun.net/))(将dll放到同目录下,建议使用版本0.14.1)
|
||||
- 使用tap网卡 依赖tap-windows([win-tap](https://build.openvpn.net/downloads/releases/))(建议使用版本9.24.7)
|
||||
- Android
|
||||
- [SwitchApp](https://github.com/lbl8603/SwitchApp)
|
||||
|
||||
### 特性
|
||||
|
||||
- IP层数据转发
|
||||
- tun虚拟网卡
|
||||
- tap虚拟网卡
|
||||
- tun虚拟网卡
|
||||
- tap虚拟网卡
|
||||
- NAT穿透
|
||||
- 点对点穿透
|
||||
- 服务端中继转发
|
||||
- 客户端中继转发
|
||||
- 点对点穿透
|
||||
- 服务端中继转发
|
||||
- 客户端中继转发
|
||||
- IP代理
|
||||
- p2p组播/广播
|
||||
- 客户端数据加密
|
||||
|
||||
### Todo
|
||||
- 支持安卓
|
||||
- 数据加密
|
||||
|
||||
- 桌面UI(测试中)
|
||||
- 服务端数据加密
|
||||
- 支持Ipv6
|
||||
|
||||
### 常见问题
|
||||
<details> <summary>展开</summary>
|
||||
|
||||
#### 问题1: 设置网络地址失败
|
||||
|
||||
##### 可能原因:
|
||||
|
||||
vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
|
||||
|
||||
##### 解决方法:
|
||||
|
||||
1. 方法一:找到冲突的IP,将其改成别的
|
||||
2. 方法二:自建服务器,指定其他不会冲突的网段
|
||||
3. 方法三:增加参数-d <device-id> ,设置不同的id会让服务端分配不同的IP,从而绕开有冲突的IP
|
||||
|
||||
#### 问题2: windows系统上wintun.dll加载失败
|
||||
|
||||
##### 可能原因:
|
||||
没有下载wintun.dll 或者使用的wintun.dll有问题
|
||||
##### 解决方法:
|
||||
1. 下载最新版的wintun.dll [下载链接](https://www.wintun.net/builds/wintun-0.14.1.zip)
|
||||
2. 解压后找到对应架构的目录,通常是amd64
|
||||
3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下)
|
||||
4. 再次启动vnt-cli
|
||||
|
||||
#### 问题3: 丢包严重,或是不能正常组网通信
|
||||
##### 可能原因:
|
||||
某些宽带下(比如广电宽带)UDP丢包严重
|
||||
##### 解决方法:
|
||||
1. 使用TCP模式中继转发(vnt-cli增加--tcp参数)
|
||||
2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--relay参数)
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
### 交流群
|
||||
|
||||
QQ:1034868233
|
||||
### 其他
|
||||
可使用社区小伙伴搭建的中继服务器
|
||||
1. -s vnt.8443.eu.org:29871
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "1.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,79 @@
|
||||
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 = to_ip(mask)?;
|
||||
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
|
||||
}
|
||||
Ok(in_ips_c)
|
||||
}
|
||||
|
||||
pub fn out_ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32)>, String> {
|
||||
let mut in_ips_c = vec![];
|
||||
for x in ips {
|
||||
let mut split = x.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 = to_ip(mask)?;
|
||||
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask));
|
||||
}
|
||||
Ok(in_ips_c)
|
||||
}
|
||||
|
||||
pub fn to_ip(mask: &str) -> Result<u32, String> {
|
||||
if let Ok(m) = mask.parse::<u32>() {
|
||||
let mut mask = 0 as u32;
|
||||
for i in 0..m {
|
||||
mask = mask | (1 << (31 - i));
|
||||
}
|
||||
Ok(mask)
|
||||
} else {
|
||||
Err("not netmask".to_string())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
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"))
|
||||
.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;
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB |
@@ -1,59 +0,0 @@
|
||||
use std::io;
|
||||
use console::style;
|
||||
use crate::console_out;
|
||||
|
||||
pub mod client;
|
||||
pub mod server;
|
||||
pub mod entity;
|
||||
|
||||
pub enum CommandEnum {
|
||||
Route,
|
||||
List,
|
||||
ListAll,
|
||||
Status,
|
||||
#[cfg(any(unix))]
|
||||
Stop,
|
||||
}
|
||||
|
||||
pub fn command(cmd: CommandEnum) {
|
||||
if let Err(e) = command_(cmd) {
|
||||
println!("{}:{:?}", style("连接后台服务错误(Connection background service error)").red(), e);
|
||||
}
|
||||
}
|
||||
|
||||
fn command_(cmd: CommandEnum) -> io::Result<()> {
|
||||
match client::CommandClient::new() {
|
||||
Ok(command_client) => {
|
||||
match cmd {
|
||||
CommandEnum::Route => {
|
||||
let list = command_client.route()?;
|
||||
console_out::console_route_table(list);
|
||||
}
|
||||
CommandEnum::List => {
|
||||
let list = command_client.list()?;
|
||||
console_out::console_device_list(list);
|
||||
}
|
||||
CommandEnum::ListAll => {
|
||||
let list = command_client.list()?;
|
||||
console_out::console_device_list_all(list);
|
||||
}
|
||||
CommandEnum::Status => {
|
||||
let status = command_client.status()?;
|
||||
console_out::console_status(status);
|
||||
}
|
||||
#[cfg(any(unix))]
|
||||
CommandEnum::Stop => {
|
||||
command_client.stop()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e);
|
||||
println!(
|
||||
"{}:{:?}",
|
||||
style("连接后台服务错误(Connection background service error)").red(), e
|
||||
);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
use std::sync::Arc;
|
||||
|
||||
use switch::core::Switch;
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Status};
|
||||
|
||||
|
||||
pub struct CommandServer {}
|
||||
|
||||
impl CommandServer {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandServer {
|
||||
pub fn start(&self, switch: Arc<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,
|
||||
))) {
|
||||
Ok(udp) => {
|
||||
break udp;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::AddrInUse {
|
||||
port += 1;
|
||||
} else {
|
||||
log::error!("创建udp失败 {:?}", e);
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
crate::config::update_command_port(port)?;
|
||||
let mut buf = [0u8; 64];
|
||||
loop {
|
||||
let (len, addr) = udp.recv_from(&mut buf)?;
|
||||
match std::str::from_utf8(&buf[..len]) {
|
||||
Ok(cmd) => {
|
||||
if let Ok(out) = command(cmd, &switch) {
|
||||
udp.send_to(out.as_bytes(), addr)?;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_status(switch: &Switch) -> Status {
|
||||
let current_device = switch.current_device();
|
||||
let nat_info = switch.nat_info();
|
||||
let name = switch.name().to_string();
|
||||
let virtual_ip = current_device.virtual_ip().to_string();
|
||||
let virtual_gateway = current_device.virtual_gateway().to_string();
|
||||
let virtual_netmask = current_device.virtual_netmask.to_string();
|
||||
let connect_status = format!("{:?}", switch.connection_status());
|
||||
let relay_server = current_device.connect_server.to_string();
|
||||
let nat_type = format!("{:?}", nat_info.nat_type);
|
||||
let public_ips: Vec<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();
|
||||
Status {
|
||||
name,
|
||||
virtual_ip,
|
||||
virtual_gateway,
|
||||
virtual_netmask,
|
||||
connect_status,
|
||||
relay_server,
|
||||
nat_type,
|
||||
public_ips,
|
||||
local_ip,
|
||||
}
|
||||
}
|
||||
|
||||
fn command(cmd: &str, switch: &Switch) -> io::Result<String> {
|
||||
let out_str = match cmd {
|
||||
"route" => {
|
||||
match serde_json::to_string(&command_route(switch)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"list" => {
|
||||
match serde_json::to_string(&command_list(switch)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"status" => {
|
||||
match serde_json::to_string(&command_status(switch)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"stop" => {
|
||||
switch.stop()?;
|
||||
"stopping".to_string()
|
||||
}
|
||||
_ => {
|
||||
format!("command '{}' not fount. \n Try to enter: 'help'\n", cmd)
|
||||
}
|
||||
};
|
||||
Ok(out_str)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use crate::config::get_home;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn log_service_init() -> io::Result<()> {
|
||||
log_init_(crate::config::get_win_server_home().join("switch-service.log"))
|
||||
}
|
||||
|
||||
pub fn log_init() -> io::Result<()> {
|
||||
log_init_(get_home().join("switch-desktop.log"))
|
||||
}
|
||||
|
||||
fn log_init_(file_name: PathBuf) -> io::Result<()> {
|
||||
let stderr = log4rs::append::console::ConsoleAppender::builder()
|
||||
.target(log4rs::append::console::Target::Stderr)
|
||||
.build();
|
||||
let logfile = log4rs::append::file::FileAppender::builder()
|
||||
// Pattern: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html
|
||||
.encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new(
|
||||
"{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n",
|
||||
)))
|
||||
.build(file_name)?;
|
||||
match log4rs::Config::builder()
|
||||
.appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile)))
|
||||
.appender(
|
||||
log4rs::config::Appender::builder()
|
||||
.filter(Box::new(log4rs::filter::threshold::ThresholdFilter::new(
|
||||
log::LevelFilter::Error,
|
||||
)))
|
||||
.build("stderr", Box::new(stderr)),
|
||||
)
|
||||
.build(
|
||||
log4rs::config::Root::builder()
|
||||
.appender("logfile")
|
||||
.appender("stderr")
|
||||
.build(log::LevelFilter::Info),
|
||||
) {
|
||||
Ok(config) => {
|
||||
let _ = log4rs::init_config(config);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,455 +0,0 @@
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::StartArgs;
|
||||
|
||||
pub mod log_config;
|
||||
lazy_static! {
|
||||
pub static ref SWITCH_HOME_PATH: Mutex<Option<PathBuf>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn get_win_server_home() -> PathBuf {
|
||||
SWITCH_HOME_PATH.lock().as_ref().unwrap().clone()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn set_win_server_home(home: PathBuf) {
|
||||
let _ = SWITCH_HOME_PATH.lock().insert(home);
|
||||
}
|
||||
|
||||
pub struct StartConfig {
|
||||
pub tap: bool,
|
||||
pub name: String,
|
||||
pub token: String,
|
||||
pub server: SocketAddr,
|
||||
pub nat_test_server: Vec<SocketAddr>,
|
||||
pub device_id: String,
|
||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
#[cfg(any(unix))]
|
||||
pub off_command_server: bool,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
|
||||
println!("========参数配置========");
|
||||
let tap = start_args.tap;
|
||||
if tap {
|
||||
println!("use tap");
|
||||
} else {
|
||||
println!("use tun");
|
||||
}
|
||||
if start_args.token.is_none() {
|
||||
return Err("找不到token(Token not found)".to_string());
|
||||
}
|
||||
let token = start_args.token.unwrap();
|
||||
if token.is_empty() {
|
||||
return Err("token不能为空(Token cannot be empty)".to_string());
|
||||
}
|
||||
if token.len() > 64 {
|
||||
return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string());
|
||||
}
|
||||
println!("token:{:?}", token);
|
||||
let name = start_args.name.unwrap_or_else(|| {
|
||||
os_info::get().to_string()
|
||||
});
|
||||
let name = name.trim();
|
||||
let name = if name.len() > 64 {
|
||||
name[..64].to_string()
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
println!("name:{:?}", name);
|
||||
let device_id = start_args.device_id.unwrap_or_else(|| {
|
||||
if let Ok(Some(mac_address)) = mac_address::get_mac_address() {
|
||||
mac_address.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
});
|
||||
if device_id.is_empty() || device_id.len() > 64 {
|
||||
return Err("设备id不能为空并且长度不能大于64字符(The device id cannot be empty and the length cannot be greater than 64 characters)".to_string());
|
||||
}
|
||||
println!("device_id:{:?}", device_id);
|
||||
let in_ips = start_args.in_ip.unwrap_or_else(|| {
|
||||
vec![]
|
||||
});
|
||||
let out_ips = start_args.out_ip.unwrap_or_else(|| {
|
||||
vec![]
|
||||
});
|
||||
println!("in_ips:{:?}", in_ips);
|
||||
let in_ips_c = if let Ok(in_ips_c) = ips_parse(&in_ips) {
|
||||
in_ips_c
|
||||
} else {
|
||||
return Err("in_ips 参数错误 示例:--in_ip 192.168.10.0/24,10.26.0.3".to_string());
|
||||
};
|
||||
println!("out_ips:{:?}", out_ips);
|
||||
let out_ips_c = if let Ok(out_ips_c) = ips_parse(&out_ips) {
|
||||
out_ips_c
|
||||
} else {
|
||||
return Err("out_ips 参数错误 示例:--out_ip 192.168.10.0/24,192.168.0.5".to_string());
|
||||
};
|
||||
|
||||
|
||||
let server = match start_args.server.unwrap_or_else(|| {
|
||||
"nat1.wherewego.top:29871".to_string()
|
||||
}).to_socket_addrs() {
|
||||
Ok(mut server) => {
|
||||
if let Some(addr) = server.next() {
|
||||
addr
|
||||
} else {
|
||||
return Err("中继服务器地址错误( Relay server address error)".to_string());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e));
|
||||
}
|
||||
};
|
||||
println!("中继服务器:{:?}", server);
|
||||
let nat_test_server = start_args.nat_test_server.unwrap_or_else(|| {
|
||||
"nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string()
|
||||
}).split(",").flat_map(|a| a.to_socket_addrs()).flatten()
|
||||
.collect::<Vec<_>>();
|
||||
if nat_test_server.is_empty() {
|
||||
return Err("NAT检测服务地址错误(NAT detection service address error)".to_string());
|
||||
}
|
||||
println!("NAT探测服务器:{:?}", nat_test_server);
|
||||
let base_config = StartConfig {
|
||||
tap,
|
||||
name,
|
||||
token,
|
||||
server,
|
||||
nat_test_server,
|
||||
device_id,
|
||||
in_ips: in_ips_c,
|
||||
out_ips: out_ips_c,
|
||||
#[cfg(any(unix))]
|
||||
off_command_server: start_args.off_command_server,
|
||||
};
|
||||
println!("========参数配置========");
|
||||
Ok(base_config)
|
||||
}
|
||||
|
||||
pub fn read_config_file(config_path: PathBuf) -> Result<StartConfig, String> {
|
||||
println!("========读取配置文件========");
|
||||
let args_config = if let Ok(config) = read_config(config_path) {
|
||||
config
|
||||
} else {
|
||||
return Err("读取配置文件失败".to_string());
|
||||
};
|
||||
|
||||
let tap = args_config.tap;
|
||||
if tap {
|
||||
println!("use tap");
|
||||
} else {
|
||||
println!("use tun");
|
||||
}
|
||||
let token = args_config.token;
|
||||
if token.is_empty() {
|
||||
return Err("token不能为空(Token cannot be empty)".to_string());
|
||||
}
|
||||
if token.len() > 64 {
|
||||
return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string());
|
||||
}
|
||||
println!("token:{:?}", token);
|
||||
let name = args_config.name;
|
||||
let name = name.trim();
|
||||
let name = if name.len() > 64 {
|
||||
name[..64].to_string()
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
println!("name:{:?}", name);
|
||||
let device_id = if !args_config.device_id.is_empty() {
|
||||
args_config.device_id
|
||||
} else {
|
||||
if let Ok(Some(mac_address)) = mac_address::get_mac_address() {
|
||||
mac_address.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
};
|
||||
if device_id.is_empty() || device_id.len() > 64 {
|
||||
return Err("设备id不能为空并且长度不能大于64字符(The device id cannot be empty and the length cannot be greater than 64 characters)".to_string());
|
||||
}
|
||||
println!("device_id:{:?}", device_id);
|
||||
let in_ips = args_config.in_ips;
|
||||
let out_ips = args_config.out_ips;
|
||||
println!("in_ips:{:?}", in_ips);
|
||||
let in_ips_c = if let Ok(in_ips_c) = ips_parse(&in_ips) {
|
||||
in_ips_c
|
||||
} else {
|
||||
return Err("in_ips 参数错误 示例:--in_ip 192.168.10.0/24,10.26.0.3".to_string());
|
||||
};
|
||||
println!("out_ips:{:?}", out_ips);
|
||||
let out_ips_c = if let Ok(out_ips_c) = ips_parse(&out_ips) {
|
||||
out_ips_c
|
||||
} else {
|
||||
return Err("out_ips 参数错误 示例:--out_ip 192.168.10.0/24,192.168.0.5".to_string());
|
||||
};
|
||||
let server = match {
|
||||
if !args_config.server.is_empty() {
|
||||
args_config.server
|
||||
} else {
|
||||
"nat1.wherewego.top:29871".to_string()
|
||||
}
|
||||
}.to_socket_addrs()
|
||||
{
|
||||
Ok(mut server) => {
|
||||
if let Some(addr) = server.next() {
|
||||
addr
|
||||
} else {
|
||||
return Err("中继服务器地址错误( Relay server address error)".to_string());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e));
|
||||
}
|
||||
};
|
||||
println!("中继服务器:{:?}", server);
|
||||
let nat_test_server = if args_config.nat_test_server.is_empty() {
|
||||
vec!["nat1.wherewego.top:35061".to_string(), "nat1.wherewego.top:35062".to_string(), "nat2.wherewego.top:35061".to_string(), "nat2.wherewego.top:35062".to_string()]
|
||||
} else {
|
||||
args_config.nat_test_server
|
||||
}.iter().flat_map(|a| a.to_socket_addrs()).flatten()
|
||||
.collect::<Vec<_>>();
|
||||
if nat_test_server.is_empty() {
|
||||
return Err("NAT检测服务地址错误(NAT detection service address error)".to_string());
|
||||
}
|
||||
println!("NAT探测服务器:{:?}", nat_test_server);
|
||||
let base_config = StartConfig {
|
||||
tap,
|
||||
name,
|
||||
token,
|
||||
server,
|
||||
nat_test_server,
|
||||
device_id,
|
||||
in_ips: in_ips_c,
|
||||
out_ips: out_ips_c,
|
||||
#[cfg(any(unix))]
|
||||
off_command_server: args_config.off_command_server,
|
||||
};
|
||||
println!("========参数配置========");
|
||||
Ok(base_config)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct RuntimeData {
|
||||
#[serde(default = "default_pid")]
|
||||
pub pid: u32,
|
||||
pub command_port: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ArgsConfig {
|
||||
#[serde(default = "default_false")]
|
||||
pub tap: bool,
|
||||
#[serde(default = "default_version")]
|
||||
pub version: String,
|
||||
#[serde(default = "default_str")]
|
||||
pub token: String,
|
||||
#[serde(default = "default_str")]
|
||||
pub name: String,
|
||||
#[serde(default = "default_str")]
|
||||
pub server: String,
|
||||
#[serde(default = "default_vec")]
|
||||
pub nat_test_server: Vec<String>,
|
||||
#[serde(default = "default_str")]
|
||||
pub device_id: String,
|
||||
#[serde(default = "default_vec")]
|
||||
pub in_ips: Vec<String>,
|
||||
#[serde(default = "default_vec")]
|
||||
pub out_ips: Vec<String>,
|
||||
#[cfg(any(unix))]
|
||||
#[serde(default = "default_false")]
|
||||
pub off_command_server: bool,
|
||||
}
|
||||
|
||||
fn default_false() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn default_version() -> String {
|
||||
"1.0".to_string()
|
||||
}
|
||||
|
||||
fn default_str() -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
fn default_vec() -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn default_pid() -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
// impl ArgsConfig {
|
||||
// pub fn new(tap: bool, token: String, name: String, server: SocketAddr,
|
||||
// nat_test_server: &Vec<SocketAddr>, device_id: String,
|
||||
// in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>, ) -> Self {
|
||||
//
|
||||
// Self {
|
||||
// tap,
|
||||
// version: "1.0".to_string(),
|
||||
// token,
|
||||
// name,
|
||||
// command_port: None,
|
||||
// server: server.to_string(),
|
||||
// nat_test_server: nat_test_server.iter().map(|v| v.to_string()).collect::<Vec<String>>(),
|
||||
// device_id,
|
||||
// pid: 0,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn lock_file() -> io::Result<File> {
|
||||
let path = get_home().join(".lock");
|
||||
let file = File::create(path)?;
|
||||
file.sync_all()?;
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
|
||||
fn save_runtime_data(config: RuntimeData) -> io::Result<()> {
|
||||
let config_path = get_runtime_data_path();
|
||||
let str = serde_yaml::to_string(&config).unwrap();
|
||||
let mut file = File::create(config_path)?;
|
||||
file.write_all(str.as_bytes())?;
|
||||
file.sync_all()
|
||||
}
|
||||
|
||||
pub fn update_pid(pid: u32) -> io::Result<()> {
|
||||
let mut config = read_runtime_data()?;
|
||||
config.pid = pid;
|
||||
return save_runtime_data(config);
|
||||
}
|
||||
|
||||
#[cfg(any(unix))]
|
||||
pub fn read_pid() -> io::Result<u32> {
|
||||
let config = read_runtime_data()?;
|
||||
Ok(config.pid)
|
||||
}
|
||||
|
||||
pub fn update_command_port(port: u16) -> io::Result<()> {
|
||||
let mut config = read_runtime_data()?;
|
||||
config.command_port = Some(port);
|
||||
return save_runtime_data(config);
|
||||
}
|
||||
|
||||
pub fn read_command_port() -> io::Result<u16> {
|
||||
let config = read_runtime_data()?;
|
||||
if let Some(p) = config.command_port {
|
||||
Ok(p)
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "not fount config"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_home() -> PathBuf {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if let Some(path) = SWITCH_HOME_PATH.lock().as_ref() {
|
||||
return path.clone();
|
||||
}
|
||||
}
|
||||
let home = dirs::home_dir().unwrap().join(".switch_desktop");
|
||||
if !home.exists() {
|
||||
std::fs::create_dir(&home).unwrap();
|
||||
}
|
||||
home
|
||||
}
|
||||
|
||||
pub fn get_runtime_data_path() -> PathBuf {
|
||||
let home = get_home();
|
||||
home.join(".data")
|
||||
}
|
||||
|
||||
fn read_runtime_data() -> io::Result<RuntimeData> {
|
||||
let config_path = get_runtime_data_path();
|
||||
let mut file = if config_path.exists() {
|
||||
File::open(config_path)?
|
||||
} else {
|
||||
OpenOptions::new().read(true).write(true).truncate(false).create(true).open(config_path)?
|
||||
};
|
||||
let mut str = String::new();
|
||||
file.read_to_string(&mut str)?;
|
||||
match serde_yaml::from_str::<RuntimeData>(&str) {
|
||||
Ok(config) => Ok(config),
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
Err(io::Error::new(io::ErrorKind::Other, "config error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_config(config_path: PathBuf) -> io::Result<ArgsConfig> {
|
||||
let mut file = File::open(config_path)?;
|
||||
let mut str = String::new();
|
||||
file.read_to_string(&mut str)?;
|
||||
match serde_yaml::from_str::<ArgsConfig>(&str) {
|
||||
Ok(config) => Ok(config),
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
Err(io::Error::new(io::ErrorKind::Other, "config error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use clap::{Parser, Subcommand};
|
||||
use console::style;
|
||||
|
||||
use switch::core::Switch;
|
||||
|
||||
use crate::config::log_config::log_init;
|
||||
|
||||
mod command;
|
||||
mod config;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
|
||||
#[cfg(any(unix))]
|
||||
mod unix;
|
||||
mod console_out;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(
|
||||
author = "Lu Beilin",
|
||||
version,
|
||||
about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信"
|
||||
)]
|
||||
pub struct BaseArgs {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Commands {
|
||||
/// 启动
|
||||
Start(StartArgs),
|
||||
/// 停止后台服务
|
||||
Stop,
|
||||
/// 安装服务
|
||||
/// Install service
|
||||
#[cfg(target_os = "windows")]
|
||||
Install(InstallArgs),
|
||||
/// 卸载服务
|
||||
/// Uninstall service
|
||||
#[cfg(target_os = "windows")]
|
||||
Uninstall,
|
||||
/// 配置
|
||||
#[cfg(target_os = "windows")]
|
||||
Config(ConfigArgs),
|
||||
/// 查看路由
|
||||
/// View route
|
||||
Route,
|
||||
/// 查看设备列表
|
||||
/// View device list
|
||||
List {
|
||||
/// 查看所有
|
||||
#[arg(short, long)]
|
||||
all: bool
|
||||
},
|
||||
/// 查看设备当前状态
|
||||
/// View the current status of the device
|
||||
Status,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug,Default)]
|
||||
pub struct StartArgs {
|
||||
/// 不超过64个字符
|
||||
/// 相同token的设备之间才能通信。
|
||||
/// 建议使用uuid保证唯一性。
|
||||
/// No more than 64 characters
|
||||
/// Only devices with the same token can communicate with each other.
|
||||
/// It is recommended to use uuid to ensure uniqueness
|
||||
#[arg(long)]
|
||||
token: Option<String>,
|
||||
/// 给设备一个名称,为空时默认用系统版本信息
|
||||
/// Give the device a name. If it is blank, the system version information will be used by default
|
||||
#[arg(long, action)]
|
||||
name: Option<String>,
|
||||
/// 设备唯一标识,为空时默认使用MAC地址,不超过64个字符
|
||||
/// Unique identification of the device. If it is blank, the MAC address is used by default. No more than 64 characters
|
||||
#[arg(long)]
|
||||
device_id: Option<String>,
|
||||
/// 注册和中继服务器地址
|
||||
/// Register and relay server address
|
||||
#[arg(long)]
|
||||
server: Option<String>,
|
||||
/// NAT检测服务地址,使用逗号分隔
|
||||
/// NAT detection service address. Use comma to separate
|
||||
#[arg(long)]
|
||||
nat_test_server: Option<String>,
|
||||
/// 关闭命令服务,关闭后不能在其他进程直接使用route、list等命令查看信息
|
||||
/// Turn off the command service. After turning off, you cannot directly use the route, list and other commands to view information in other processes
|
||||
#[cfg(any(unix))]
|
||||
#[arg(long)]
|
||||
off_command_server: bool,
|
||||
/// 记录日志,输出在 home/.switch_desktop 目录下,长时间使用时不建议开启
|
||||
/// Output the log in the "home/.switch_desktop" directory
|
||||
#[arg(long)]
|
||||
log: bool,
|
||||
/// 使用tap网卡
|
||||
#[arg(long)]
|
||||
tap: bool,
|
||||
/// 配置点对网时使用,--in-ip 192.168.10.0/24,10.26.0.3,表示允许接收网段192.168.10.0/24的数据并转发到10.26.0.3
|
||||
/// Use when configuring peer-to-peer networks
|
||||
#[arg(long)]
|
||||
in_ip:Option<Vec<String>>,
|
||||
/// 配置点对网时使用,--out-ip 192.168.10.0/24,192.168.1.10,表示允许目标为192.168.10.0/24的数据从网卡192.168.1.10转发出去
|
||||
/// Use when configuring peer-to-peer networks
|
||||
#[arg(long)]
|
||||
out_ip:Option<Vec<String>>,
|
||||
/// 读取配置文件 --config config_file_path
|
||||
/// Read configuration file
|
||||
#[arg(long)]
|
||||
config:Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct InstallArgs {
|
||||
/// 安装路径
|
||||
/// Service installation path
|
||||
#[arg(long)]
|
||||
path: String,
|
||||
/// 服务开机自启动
|
||||
/// Autostart on system startup
|
||||
#[arg(long)]
|
||||
auto: bool,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct ConfigArgs {
|
||||
/// 服务开机自启动
|
||||
/// Autostart on system startup
|
||||
#[arg(long)]
|
||||
auto: bool,
|
||||
}
|
||||
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
if args.len() == 3 && args[1] == windows::SERVICE_FLAG {
|
||||
//以服务的方式启动
|
||||
config::set_win_server_home(std::path::PathBuf::from(&args[2]));
|
||||
windows::service::start();
|
||||
return;
|
||||
} else {
|
||||
let args = BaseArgs::parse();
|
||||
if let Commands::Start(start_args) = &args.command {
|
||||
if start_args.log {
|
||||
let _ = log_init();
|
||||
}
|
||||
}
|
||||
windows::main0(args).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
if sudo::RunningAs::Root != sudo::check() {
|
||||
println!(
|
||||
"{}",
|
||||
style("需要使用root权限执行(Need to execute with root permission)...").red()
|
||||
);
|
||||
sudo::escalate_if_needed().unwrap();
|
||||
}
|
||||
let args = BaseArgs::parse();
|
||||
if let Commands::Start(start_args) = &args.command {
|
||||
if start_args.log {
|
||||
let _ = log_init();
|
||||
}
|
||||
}
|
||||
unix::main0(args).await;
|
||||
}
|
||||
|
||||
pub fn console_listen(switch: &Switch) {
|
||||
use console::Term;
|
||||
let term = Term::stdout();
|
||||
println!("{}", style("启动成功 started").green());
|
||||
let current_device = switch.current_device();
|
||||
println!(
|
||||
"当前虚拟ip(virtual ip): {:?}",
|
||||
style(current_device.virtual_ip()).green()
|
||||
);
|
||||
println!(
|
||||
"虚拟网关(virtual gateway): {:?}",
|
||||
style(current_device.virtual_gateway()).green()
|
||||
);
|
||||
loop {
|
||||
println!(
|
||||
"{}",
|
||||
style("Please enter the command (Usage: list,status,exit,help):").color256(102)
|
||||
);
|
||||
match term.read_line() {
|
||||
Ok(cmd) => {
|
||||
if cmd.is_empty() {
|
||||
log::warn!("非正常返回");
|
||||
return;
|
||||
}
|
||||
if command(cmd.trim(), &switch).is_err() {
|
||||
println!("{}", style("stopping").red());
|
||||
if let Err(e) = switch.stop() {
|
||||
println!("stop:{:?}", e);
|
||||
}
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("read_line:{:?}", e);
|
||||
println!("{}", style("stopping...").red());
|
||||
if let Err(e) = switch.stop() {
|
||||
log::error!("stop:{:?}", e);
|
||||
}
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("{}", style("stopped").red());
|
||||
}
|
||||
|
||||
|
||||
fn command(cmd: &str, switch: &Switch) -> Result<(), ()> {
|
||||
match cmd {
|
||||
"route" => {
|
||||
let list = command::server::command_route(switch);
|
||||
console_out::console_route_table(list);
|
||||
}
|
||||
"list" => {
|
||||
let list = command::server::command_list(switch);
|
||||
console_out::console_device_list(list);
|
||||
}
|
||||
"status" => {
|
||||
let status = command::server::command_status(switch);
|
||||
console_out::console_status(status);
|
||||
}
|
||||
"help" | "h" => {
|
||||
println!("Options: ");
|
||||
println!(
|
||||
"{} , Query the virtual IP of other devices",
|
||||
style("list").green()
|
||||
);
|
||||
println!("{} , View current device status", style("status").green());
|
||||
println!("{} , Exit the program", style("exit").green());
|
||||
}
|
||||
"exit" => {
|
||||
return Err(());
|
||||
}
|
||||
_ => {
|
||||
println!("command '{}' not fount. ", style(cmd).red());
|
||||
println!("Try to enter: '{}'", style("help").green());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use console::style;
|
||||
use fs2::FileExt;
|
||||
|
||||
use switch::core::{Config, Switch};
|
||||
|
||||
use crate::{BaseArgs, Commands, config};
|
||||
use crate::command::{command, CommandEnum};
|
||||
|
||||
|
||||
pub async fn main0(base_args: BaseArgs) {
|
||||
match base_args.command {
|
||||
Commands::Start(args) => {
|
||||
let start_config = if let Some(config_path) = &args.config {
|
||||
match config::read_config_file(config_path.into()) {
|
||||
Ok(start_config) => {
|
||||
start_config
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", style(&e).red());
|
||||
log::error!("{:?}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match config::default_config(args) {
|
||||
Ok(start_config) => {
|
||||
start_config
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", style(&e).red());
|
||||
log::error!("{:?}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
let off_command_server = start_config.off_command_server;
|
||||
let config = Config::new(
|
||||
start_config.tap,
|
||||
start_config.token.clone(),
|
||||
start_config.device_id.clone(),
|
||||
start_config.name.clone(),
|
||||
start_config.server,
|
||||
start_config.nat_test_server.clone(),
|
||||
start_config.in_ips.clone(),
|
||||
start_config.out_ips.clone(),
|
||||
);
|
||||
let lock = match config::lock_file() {
|
||||
Ok(lock) => {
|
||||
lock
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e);
|
||||
println!("文件锁定失败:{:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if lock.try_lock_exclusive().is_err() {
|
||||
println!("{}", style("文件被重复打开").red());
|
||||
return;
|
||||
}
|
||||
let switch = match Switch::start(config).await {
|
||||
Ok(switch) => {
|
||||
switch
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
println!("启动switch失败:{:?}", e);
|
||||
lock.unlock().unwrap();
|
||||
return;
|
||||
}
|
||||
};
|
||||
let switch = Arc::new(switch);
|
||||
let command_server = crate::command::server::CommandServer::new();
|
||||
if off_command_server {
|
||||
crate::console_listen(&switch);
|
||||
log::info!("前台任务结束");
|
||||
} else {
|
||||
if let Err(e) = config::update_pid(std::process::id()) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
let switch1 = switch.clone();
|
||||
let handle = std::thread::Builder::new().name("cmd-server".into()).spawn(move || {
|
||||
if let Err(e) = command_server.start(switch1) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
}).unwrap();
|
||||
crate::console_listen(&switch);
|
||||
if let Err(e) = handle.join() {
|
||||
log::error!("后台任务异常{:?}",e);
|
||||
} else {
|
||||
log::info!("后台任务结束");
|
||||
}
|
||||
}
|
||||
lock.unlock().unwrap();
|
||||
}
|
||||
Commands::Stop => {
|
||||
command(CommandEnum::Stop);
|
||||
if let Ok(pid) = config::read_pid() {
|
||||
if pid != 0 {
|
||||
let kill_cmd = format!("kill {}", pid);
|
||||
let kill_out = std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&kill_cmd)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !kill_out.status.success() {
|
||||
println!("cmd:{:?},err:{:?}", kill_cmd, kill_out);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("stopped")
|
||||
}
|
||||
Commands::Route => {
|
||||
command(CommandEnum::Route);
|
||||
}
|
||||
Commands::List { all } => {
|
||||
if all {
|
||||
command(CommandEnum::ListAll);
|
||||
} else {
|
||||
command(CommandEnum::List);
|
||||
}
|
||||
}
|
||||
Commands::Status => {
|
||||
command(CommandEnum::Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,370 +0,0 @@
|
||||
use std::{io, thread};
|
||||
use std::ffi::OsString;
|
||||
use std::net::UdpSocket;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use console::style;
|
||||
use fs2::FileExt;
|
||||
use windows_service::Error;
|
||||
use windows_service::service::{
|
||||
ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType, ServiceState, ServiceType,
|
||||
};
|
||||
use windows_service::service_manager::{ServiceManager, ServiceManagerAccess};
|
||||
|
||||
use switch::core::{Config, Switch};
|
||||
|
||||
use crate::{BaseArgs, Commands, config};
|
||||
use crate::command::{command, CommandEnum};
|
||||
|
||||
pub mod service;
|
||||
mod windows_admin_check;
|
||||
|
||||
pub const SERVICE_FLAG: &'static str = "start_switch_service_v1_";
|
||||
pub const SERVICE_NAME: &'static str = "switch-service-v1";
|
||||
pub const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
|
||||
|
||||
fn admin_check() -> bool {
|
||||
if !windows_admin_check::is_app_elevated() {
|
||||
println!(
|
||||
"{}",
|
||||
style("请使用管理员权限运行(Please run with administrator privileges)").red()
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn not_started() -> bool {
|
||||
match service_state() {
|
||||
Ok(state) => {
|
||||
if state == ServiceState::Running {
|
||||
return false;
|
||||
} else {
|
||||
println!("服务未启动")
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
pub async fn main0(base_args: BaseArgs) {
|
||||
match base_args.command {
|
||||
Commands::Start(args) => {
|
||||
if admin_check() {
|
||||
return;
|
||||
}
|
||||
{
|
||||
// 允许应用通过防火墙
|
||||
let _udp = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
}
|
||||
let start_config = if let Some(config_path) = &args.config {
|
||||
match config::read_config_file(config_path.into()) {
|
||||
Ok(start_config) => {
|
||||
start_config
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", style(&e).red());
|
||||
log::error!("{:?}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match config::default_config(args) {
|
||||
Ok(start_config) => {
|
||||
start_config
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", style(&e).red());
|
||||
log::error!("{:?}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
match service_state() {
|
||||
Ok(state) => {
|
||||
if state == ServiceState::Stopped {
|
||||
match start() {
|
||||
Ok(_) => {
|
||||
//需要检查启动状态
|
||||
thread::sleep(Duration::from_secs(2));
|
||||
println!("{}", style("启动成功(Start successfully)").green());
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
println!("{}:{}", style("启动失败").red(),e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("服务未停止(Service not stopped)");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
match e {
|
||||
Error::Winapi(ref e) => {
|
||||
if let Some(code) = e.raw_os_error() {
|
||||
if code == 1060 {
|
||||
//指定的服务未安装。
|
||||
println!(
|
||||
"{}",
|
||||
style("服务未安装,在当前进程启动(The service is not installed and started in the current process)").red()
|
||||
);
|
||||
let config = Config::new(
|
||||
start_config.tap,
|
||||
start_config.token,
|
||||
start_config.device_id,
|
||||
start_config.name,
|
||||
start_config.server,
|
||||
start_config.nat_test_server,
|
||||
start_config.in_ips,
|
||||
start_config.out_ips,
|
||||
);
|
||||
let lock = match config::lock_file() {
|
||||
Ok(lock) => {
|
||||
lock
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("文件锁定失败:{:?}",e);
|
||||
println!("文件锁定失败:{:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if lock.try_lock_exclusive().is_err() {
|
||||
println!("{}", style("文件被重复打开").red());
|
||||
return;
|
||||
}
|
||||
match Switch::start(config).await {
|
||||
Ok(switch) => {
|
||||
crate::console_listen(&switch);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
println!("启动switch失败:{:?}", e);
|
||||
}
|
||||
}
|
||||
lock.unlock().unwrap();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
println!("{:?}", e);
|
||||
}
|
||||
};
|
||||
pause();
|
||||
}
|
||||
Commands::Stop => {
|
||||
if not_started() {
|
||||
return;
|
||||
}
|
||||
if admin_check() {
|
||||
return;
|
||||
}
|
||||
match stop() {
|
||||
Ok(_) => {
|
||||
println!("{}", style("停止成功(Stopped successfully)").green())
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
println!("停止失败:{}",e);
|
||||
}
|
||||
}
|
||||
pause();
|
||||
}
|
||||
Commands::Install(args) => {
|
||||
if admin_check() {
|
||||
return;
|
||||
}
|
||||
let path: PathBuf = args.path.into();
|
||||
if !path.exists() {
|
||||
std::fs::create_dir_all(&path).unwrap();
|
||||
}
|
||||
if !path.is_dir() {
|
||||
println!("参数必须为文件目录(Parameter must be a file directory)");
|
||||
} else {
|
||||
if let Err(e) = install(path, args.auto) {
|
||||
log::error!("{:?}", e);
|
||||
println!("安装失败:{}",e);
|
||||
} else {
|
||||
println!("{}", style("安装成功(Installation succeeded)").green())
|
||||
}
|
||||
}
|
||||
pause();
|
||||
}
|
||||
Commands::Uninstall => {
|
||||
if admin_check() {
|
||||
return;
|
||||
}
|
||||
if let Err(e) = uninstall() {
|
||||
log::error!("{:?}", e);
|
||||
println!("卸载失败:{}",e);
|
||||
} else {
|
||||
println!("{}", style("卸载成功(Uninstall succeeded)").green())
|
||||
}
|
||||
pause();
|
||||
}
|
||||
Commands::Config(args) => {
|
||||
if let Err(e) = change(args.auto) {
|
||||
log::error!("{:?}", e);
|
||||
println!("配置失败:{}",e);
|
||||
} else {
|
||||
println!("{}", style("配置成功(Config succeeded)").green())
|
||||
}
|
||||
pause();
|
||||
}
|
||||
Commands::Route => {
|
||||
if not_started() {
|
||||
return;
|
||||
}
|
||||
command(CommandEnum::Route);
|
||||
}
|
||||
Commands::List { all } => {
|
||||
if not_started() {
|
||||
return;
|
||||
}
|
||||
if all {
|
||||
command(CommandEnum::ListAll);
|
||||
} else {
|
||||
command(CommandEnum::List);
|
||||
}
|
||||
}
|
||||
Commands::Status => {
|
||||
if not_started() {
|
||||
return;
|
||||
}
|
||||
command(CommandEnum::Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pause() {
|
||||
println!(
|
||||
"{}",
|
||||
style("按任意键退出(Press any key to exit)...").green()
|
||||
);
|
||||
use console::Term;
|
||||
let term = Term::stdout();
|
||||
let _ = term.read_char().unwrap();
|
||||
}
|
||||
|
||||
fn install(path: PathBuf, auto: bool) -> Result<(), Error> {
|
||||
let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
let current_exe_path = std::env::current_exe().unwrap();
|
||||
let service_path = path.join("switch-service-v1.exe");
|
||||
std::fs::copy(current_exe_path, service_path.as_path()).unwrap();
|
||||
if let Err(e) = std::fs::copy("wintun.dll", path.join("wintun.dll").as_path()) {
|
||||
if e.kind() == io::ErrorKind::NotFound {
|
||||
println!("Not fount 'wintun.dll'. Please put 'wintun.dll' in the current directory");
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
panic!("{:?}", e)
|
||||
}
|
||||
}
|
||||
let mut launch_arguments = Vec::new();
|
||||
launch_arguments.push(OsString::from(SERVICE_FLAG));
|
||||
launch_arguments.push(OsString::from(
|
||||
config::get_home().to_str().unwrap(),
|
||||
));
|
||||
let start_type = if auto {
|
||||
ServiceStartType::AutoStart
|
||||
} else {
|
||||
ServiceStartType::OnDemand
|
||||
};
|
||||
let service_info = ServiceInfo {
|
||||
name: OsString::from(SERVICE_NAME),
|
||||
display_name: OsString::from("switch service v1"),
|
||||
service_type: SERVICE_TYPE,
|
||||
start_type,
|
||||
error_control: ServiceErrorControl::Normal,
|
||||
executable_path: service_path.into(),
|
||||
launch_arguments,
|
||||
dependencies: vec![],
|
||||
account_name: None, // run as System
|
||||
account_password: None,
|
||||
};
|
||||
let service = service_manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?;
|
||||
service.set_description("A VPN")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn change(auto: bool) -> Result<(), Error> {
|
||||
let manager_access = ServiceManagerAccess::CONNECT;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
|
||||
let service_access = ServiceAccess::QUERY_CONFIG | ServiceAccess::CHANGE_CONFIG;
|
||||
let service = service_manager.open_service(SERVICE_NAME, service_access)?;
|
||||
let config = service.query_config()?;
|
||||
let start_type = if auto {
|
||||
ServiceStartType::AutoStart
|
||||
} else {
|
||||
ServiceStartType::OnDemand
|
||||
};
|
||||
let mut launch_arguments = Vec::new();
|
||||
launch_arguments.push(OsString::from(SERVICE_FLAG));
|
||||
launch_arguments.push(OsString::from(
|
||||
config::get_home().to_str().unwrap(),
|
||||
));
|
||||
let service_info = ServiceInfo {
|
||||
name: OsString::from(SERVICE_NAME),
|
||||
display_name: config.display_name,
|
||||
service_type: SERVICE_TYPE,
|
||||
start_type,
|
||||
error_control: config.error_control,
|
||||
executable_path: config.executable_path,
|
||||
launch_arguments,
|
||||
dependencies: config.dependencies,
|
||||
account_name: None, // run as System
|
||||
account_password: None,
|
||||
};
|
||||
service.change_config(&service_info)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn uninstall() -> Result<(), Error> {
|
||||
let manager_access = ServiceManagerAccess::CONNECT;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
|
||||
let service_access = ServiceAccess::QUERY_STATUS | ServiceAccess::STOP | ServiceAccess::DELETE;
|
||||
let service = service_manager.open_service(SERVICE_NAME, service_access)?;
|
||||
|
||||
let service_status = service.query_status()?;
|
||||
if service_status.current_state != ServiceState::Stopped {
|
||||
service.stop()?;
|
||||
// Wait for service to stop
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
service.delete()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start() -> Result<(), Error> {
|
||||
let manager_access = ServiceManagerAccess::CONNECT;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::START)?;
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
service.start(&args[1..])
|
||||
}
|
||||
|
||||
fn service_state() -> Result<ServiceState, Error> {
|
||||
let manager_access = ServiceManagerAccess::CONNECT;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
|
||||
let service_access = ServiceAccess::QUERY_STATUS;
|
||||
let service = service_manager.open_service(SERVICE_NAME, service_access)?;
|
||||
let service_status = service.query_status()?;
|
||||
return Ok(service_status.current_state);
|
||||
}
|
||||
|
||||
fn stop() -> Result<(), Error> {
|
||||
let manager_access = ServiceManagerAccess::CONNECT;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::STOP)?;
|
||||
service.stop()?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
// #[macro_use]
|
||||
// extern crate windows_service;
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use clap::Parser;
|
||||
|
||||
use windows_service::{define_windows_service, service_control_handler, service_dispatcher};
|
||||
use windows_service::service::{
|
||||
ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
|
||||
};
|
||||
use windows_service::service_control_handler::ServiceControlHandlerResult;
|
||||
|
||||
use switch::core::{Config, Switch};
|
||||
|
||||
use crate::{BaseArgs, Commands, config, StartArgs};
|
||||
use crate::windows::SERVICE_NAME;
|
||||
|
||||
define_windows_service!(ffi_service_main, switch_service_main);
|
||||
pub fn switch_service_main(arguments: Vec<OsString>) {
|
||||
let base_args = BaseArgs::parse_from(arguments);
|
||||
match base_args.command {
|
||||
Commands::Start(args) => {
|
||||
if args.log {
|
||||
let _ = config::log_config::log_service_init();
|
||||
}
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
match service_main(args).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!("启动服务失败:{:?}",e);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn service_main(args: StartArgs) -> windows_service::Result<()> {
|
||||
log::info!("service_main:{:?}",args);
|
||||
let parker = crossbeam::sync::Parker::new();
|
||||
let un_parker = parker.unparker().clone();
|
||||
let event_handler = move |control_event| -> ServiceControlHandlerResult {
|
||||
match control_event {
|
||||
// Notifies a service to report its current status information to the service
|
||||
// control manager. Always return NoError even if not implemented.
|
||||
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
|
||||
|
||||
// Handle stop
|
||||
ServiceControl::Stop => {
|
||||
un_parker.unpark();
|
||||
log::info!("handler 服务停止");
|
||||
ServiceControlHandlerResult::NoError
|
||||
}
|
||||
_ => ServiceControlHandlerResult::NotImplemented,
|
||||
}
|
||||
};
|
||||
|
||||
// Register system service event handler.
|
||||
// The returned status handle should be used to report service status changes to the system.
|
||||
let status_handle =
|
||||
service_control_handler::register(SERVICE_NAME, event_handler)?;
|
||||
|
||||
// Tell the system that service is running
|
||||
status_handle.set_service_status(ServiceStatus {
|
||||
service_type: crate::windows::SERVICE_TYPE,
|
||||
current_state: ServiceState::Running,
|
||||
controls_accepted: ServiceControlAccept::STOP,
|
||||
exit_code: ServiceExitCode::Win32(0),
|
||||
checkpoint: 0,
|
||||
wait_hint: Duration::default(),
|
||||
process_id: None,
|
||||
})?;
|
||||
match start_switch(args).await {
|
||||
Ok(switch) => {
|
||||
parker.park();
|
||||
if let Err(e) = switch.stop() {
|
||||
log::warn!("switch stop:{:?}",e)
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e);
|
||||
}
|
||||
}
|
||||
status_handle.set_service_status(ServiceStatus {
|
||||
service_type: crate::windows::SERVICE_TYPE,
|
||||
current_state: ServiceState::Stopped,
|
||||
controls_accepted: ServiceControlAccept::empty(),
|
||||
exit_code: ServiceExitCode::Win32(0),
|
||||
checkpoint: 0,
|
||||
wait_hint: Duration::default(),
|
||||
process_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
async fn start_switch(args: StartArgs) -> switch::Result<Arc<Switch>> {
|
||||
let start_config = if let Some(config_path) = &args.config {
|
||||
match config::read_config_file(config_path.into()) {
|
||||
Ok(start_config) => {
|
||||
start_config
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
return Err(switch::error::Error::Stop(e));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match config::default_config(args) {
|
||||
Ok(start_config) => {
|
||||
start_config
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
return Err(switch::error::Error::Stop(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
let config = Config::new(
|
||||
start_config.tap,
|
||||
start_config.token,
|
||||
start_config.device_id,
|
||||
start_config.name,
|
||||
start_config.server,
|
||||
start_config.nat_test_server,
|
||||
start_config.in_ips,
|
||||
start_config.out_ips,
|
||||
);
|
||||
let switch = Switch::start(config).await?;
|
||||
log::info!("switch-service服务启动");
|
||||
let switch = Arc::new(switch);
|
||||
let command_server = crate::command::server::CommandServer::new();
|
||||
let switch1 = switch.clone();
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = config::update_pid(std::process::id()) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
if let Err(e) = command_server.start(switch1) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
});
|
||||
Ok(switch)
|
||||
}
|
||||
|
||||
pub fn start() {
|
||||
log::info!("以服务的方式启动");
|
||||
service_dispatcher::start(SERVICE_NAME, ffi_service_main).unwrap();
|
||||
}
|
||||
Submodule switch/p2p_channel deleted from 9d2e02f629
@@ -1,25 +0,0 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("the buffer is too small")]
|
||||
SmallBuffer,
|
||||
|
||||
#[error("the packet is invalid")]
|
||||
InvalidPacket,
|
||||
#[error("Unimplemented")]
|
||||
Unimplemented,
|
||||
// #[error("the vaue is invalid for the field")]
|
||||
// InvalidValue,
|
||||
//
|
||||
// #[error("the value has already been defined")]
|
||||
// AlreadyDefined,
|
||||
//
|
||||
// #[error(transparent)]
|
||||
// Io(#[from] io::Error),
|
||||
//
|
||||
// #[error(transparent)]
|
||||
// Nul(#[from] ffi::NulError),
|
||||
}
|
||||
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
@@ -1,185 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use p2p_channel::boot::Boot;
|
||||
use p2p_channel::channel::{Channel, Route, RouteKey};
|
||||
use p2p_channel::punch::NatInfo;
|
||||
|
||||
use crate::{tap_device, tun_device};
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::{ConnectStatus, CurrentDeviceInfo, CurrentDeviceInfoExt, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tap_handler, tun_handler};
|
||||
use crate::nat::NatTest;
|
||||
use crate::tap_device::TapWriter;
|
||||
use crate::tun_device::TunWriter;
|
||||
|
||||
pub struct Switch {
|
||||
name: String,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
tun_writer: Option<TunWriter>,
|
||||
tap_writer: Option<TapWriter>,
|
||||
nat_channel: Channel<Ipv4Addr>,
|
||||
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
|
||||
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
||||
/// 1. 网络中的虚拟ip列表
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
nat_test: NatTest,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
}
|
||||
|
||||
impl Switch {
|
||||
pub async fn start(config: Config) -> crate::Result<Switch> {
|
||||
log::info!("config:{:?}",config);
|
||||
|
||||
let (mut channel, punch, idle) = Boot::new::<Ipv4Addr>(80, 15000, 0)?;
|
||||
let response = registration_handler::registration(&mut channel, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone())?;
|
||||
let register = Arc::new(registration_handler::Register::new(channel.sender()?, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone()));
|
||||
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> = Arc::new(Mutex::new((0, Vec::new())));
|
||||
let peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>> = Arc::new(SkipMap::new());
|
||||
let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected));
|
||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||
|
||||
let local_ip = crate::nat::local_ip()?;
|
||||
let local_port = channel.local_addr()?.port();
|
||||
// NAT检测
|
||||
let nat_test = NatTest::new(config.nat_test_server.clone(), Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_port);
|
||||
let in_ips = config.in_ips.iter().map(|(dest, mask, _)| { (Ipv4Addr::from(*dest), Ipv4Addr::from(*mask)) }).collect::<Vec<(Ipv4Addr, Ipv4Addr)>>();
|
||||
|
||||
let out_ips = config.out_ips.iter().map(|(_, _, ip)| *ip).collect::<Vec<Ipv4Addr>>();
|
||||
let out_external_route = ExternalRoute::new(config.out_ips);
|
||||
let in_external_route = ExternalRoute::new(config.in_ips);
|
||||
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address)));
|
||||
let ip_proxy_map = crate::ip_proxy::init_proxy(channel.sender()?,out_ips,current_device.clone()).await?;
|
||||
let ( current_device_ext,tun_writer, tap_writer) = if config.tap {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
//删除switch的tun网卡避免ip冲突,因为非正常退出会保留网卡
|
||||
tun_device::delete_tun();
|
||||
}
|
||||
let (tap_writer, tap_reader, mac) = tap_device::create_tap(virtual_ip, virtual_netmask, virtual_gateway)?;
|
||||
let current_device_ext = Arc::new(AtomicCell::new(CurrentDeviceInfoExt::new( mac)));
|
||||
//tap数据处理
|
||||
tap_handler::start(channel.sender()?, tap_reader.clone(), tap_writer.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone());
|
||||
(current_device_ext, None, Some(tap_writer))
|
||||
} else {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
//删除switch的tap网卡避免ip冲突,非正常退出会保留网卡
|
||||
tap_device::delete_tap();
|
||||
}
|
||||
// tun通道
|
||||
let (tun_writer, tun_reader) = tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway,in_ips)?;
|
||||
let current_device_ext = Arc::new(AtomicCell::new(CurrentDeviceInfoExt::new( [0, 0, 0, 0, 0, 0])));
|
||||
//tun数据接收处理
|
||||
tun_handler::start(channel.sender()?, tun_reader.clone(), tun_writer.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone());
|
||||
(current_device_ext,Some(tun_writer), None)
|
||||
};
|
||||
//外部数据接收处理
|
||||
let channel_recv_handler = recv_handler::RecvHandler::new(channel.try_clone()?, current_device.clone(), current_device_ext,device_list.clone(), register.clone(),
|
||||
nat_test.clone(), tun_writer.clone(), tap_writer.clone(),
|
||||
connect_status.clone(), peer_nat_info_map.clone(), ip_proxy_map, out_external_route);
|
||||
recv_handler::start(channel_recv_handler);
|
||||
// 定时心跳
|
||||
heartbeat_handler::start_heartbeat(channel.sender()?, device_list.clone(), current_device.clone());
|
||||
// 空闲检查
|
||||
heartbeat_handler::start_idle(idle, channel.sender()?);
|
||||
// 打洞处理
|
||||
punch_handler::start_cone(punch.try_clone()?, current_device.clone());
|
||||
punch_handler::start_symmetric(punch, current_device.clone());
|
||||
punch_handler::start_punch(nat_test.clone(), device_list.clone(), channel.sender()?, current_device.clone());
|
||||
log::info!("switch启动成功");
|
||||
Ok(Switch {
|
||||
name: config.name,
|
||||
current_device,
|
||||
tun_writer,
|
||||
tap_writer,
|
||||
nat_channel: channel,
|
||||
nat_test,
|
||||
device_list,
|
||||
connect_status,
|
||||
peer_nat_info_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Switch {
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
pub fn current_device(&self) -> CurrentDeviceInfo {
|
||||
self.current_device.load()
|
||||
}
|
||||
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
|
||||
self.peer_nat_info_map.get(ip).map(|e| e.value().clone())
|
||||
}
|
||||
pub fn connection_status(&self) -> ConnectStatus {
|
||||
self.connect_status.load()
|
||||
}
|
||||
pub fn nat_info(&self) -> NatInfo {
|
||||
self.nat_test.nat_info()
|
||||
}
|
||||
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
|
||||
let device_list_lock = self.device_list.lock();
|
||||
let (_epoch, device_list) = device_list_lock.clone();
|
||||
drop(device_list_lock);
|
||||
device_list
|
||||
}
|
||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
|
||||
self.nat_channel.route(ip)
|
||||
}
|
||||
pub fn route_key(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
|
||||
self.nat_channel.route_to_id(route_key)
|
||||
}
|
||||
pub fn route_table(&self) -> Vec<(Ipv4Addr, Route)> {
|
||||
self.nat_channel.route_table()
|
||||
}
|
||||
pub fn stop(&self) -> io::Result<()> {
|
||||
if let Some(tap) = &self.tap_writer {
|
||||
tap.close()?;
|
||||
}
|
||||
if let Some(tun) = &self.tun_writer {
|
||||
tun.close()?;
|
||||
}
|
||||
self.nat_channel.close()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
pub tap: bool,
|
||||
pub token: String,
|
||||
pub device_id: String,
|
||||
pub name: String,
|
||||
pub server_address: SocketAddr,
|
||||
pub nat_test_server: Vec<SocketAddr>,
|
||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(tap: bool, token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
server_address: SocketAddr,
|
||||
nat_test_server: Vec<SocketAddr>,
|
||||
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>, ) -> Self {
|
||||
Self {
|
||||
tap,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address,
|
||||
nat_test_server,
|
||||
in_ips,
|
||||
out_ips,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
// 目标ip,子网掩码,网关
|
||||
|
||||
pub struct ExternalRoute {
|
||||
route_table: Vec<(u32, u32, Ipv4Addr)>,
|
||||
}
|
||||
|
||||
impl ExternalRoute {
|
||||
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
|
||||
Self {
|
||||
route_table
|
||||
}
|
||||
}
|
||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
for (dest, mask, gateway) in &self.route_table {
|
||||
if *mask & ip == *mask & *dest {
|
||||
return Some(*gateway);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
|
||||
use chrono::Local;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use rand::prelude::SliceRandom;
|
||||
|
||||
use p2p_channel::channel::sender::Sender;
|
||||
use p2p_channel::channel::Route;
|
||||
use p2p_channel::idle::Idle;
|
||||
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::protocol::control_packet::PingPacket;
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||
|
||||
pub fn start_idle(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) {
|
||||
thread::Builder::new()
|
||||
.name("idle".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = start_idle_(idle, sender) {
|
||||
log::info!("空闲检测线程停止:{:?}", e);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn start_idle_(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) -> io::Result<()> {
|
||||
loop {
|
||||
let (idle_status, peer_ips, route) = idle.next_idle()?;
|
||||
log::warn!(
|
||||
"peer_ip:{:?},route:{:?},idle_status:{:?}",
|
||||
peer_ips,
|
||||
route,
|
||||
idle_status
|
||||
);
|
||||
for peer_ip in peer_ips {
|
||||
sender.remove_route(&peer_ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_heartbeat(
|
||||
sender: Sender<Ipv4Addr>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) {
|
||||
thread::Builder::new()
|
||||
.name("heartbeat".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = start_heartbeat_(sender, device_list, current_device) {
|
||||
log::info!("空闲检测线程停止:{:?}", e);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn set_now_time(packet: &mut NetPacket<[u8; 16]>) -> io::Result<()> {
|
||||
let current_time = Local::now().timestamp_millis() as u16;
|
||||
let mut ping = PingPacket::new(packet.payload_mut())?;
|
||||
ping.set_time(current_time);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_heartbeat_(
|
||||
sender: Sender<Ipv4Addr>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) -> io::Result<()> {
|
||||
let mut net_packet = NetPacket::new([0u8; 16])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Control);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
let mut count = 0;
|
||||
loop {
|
||||
let current_device = current_device.load();
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
{
|
||||
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||
let epoch = { device_list.lock().0 };
|
||||
ping.set_epoch(epoch);
|
||||
}
|
||||
if count < 7 || count % 7 == 0 {
|
||||
let mut route_list: Option<Vec<(Ipv4Addr, Route)>> = None;
|
||||
let peer_list = device_list.lock().1.clone();
|
||||
for peer in peer_list {
|
||||
set_now_time(&mut net_packet)?;
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_destination(peer.virtual_ip);
|
||||
if sender
|
||||
.send_to_id(net_packet.buffer(), &peer.virtual_ip)
|
||||
.is_err()
|
||||
{
|
||||
//没有路由则发送到网关
|
||||
let _ = sender.send_to_addr(net_packet.buffer(), current_device.connect_server);
|
||||
//再随机发送到其他地址,看有没有客户端符合转发条件
|
||||
let route_list = route_list.get_or_insert_with(|| {
|
||||
let mut l = sender.route_table();
|
||||
l.shuffle(&mut rand::thread_rng());
|
||||
l
|
||||
});
|
||||
let mut num = 0;
|
||||
net_packet.first_set_ttl(2);
|
||||
for (peer_ip, route) in route_list.iter() {
|
||||
if peer_ip != &peer.virtual_ip && route.metric == 1 {
|
||||
set_now_time(&mut net_packet)?;
|
||||
let _ = sender.send_to_route(net_packet.buffer(), &route.route_key());
|
||||
num += 1;
|
||||
}
|
||||
if num >= 3 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
set_now_time(&mut net_packet)?;
|
||||
net_packet.set_destination(current_device.virtual_gateway());
|
||||
if let Err(e) = sender.send_to_addr(net_packet.buffer(), current_device.connect_server)
|
||||
{
|
||||
log::warn!(
|
||||
"connect_server:{:?},e:{:?}",
|
||||
current_device.connect_server,
|
||||
e
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (peer_ip, route) in sender.route_table().iter() {
|
||||
set_now_time(&mut net_packet)?;
|
||||
net_packet.set_destination(*peer_ip);
|
||||
if let Err(e) = sender.send_to_route(net_packet.buffer(), &route.route_key()) {
|
||||
log::warn!("peer_ip:{:?},route:{:?},e:{:?}", peer_ip, route, e);
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
|
||||
count += 1;
|
||||
thread::sleep(Duration::from_millis(5000));
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::nat::NatTest;
|
||||
use crate::proto::message::{PunchInfo, PunchNatType};
|
||||
use crate::protocol::{control_packet, turn_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use p2p_channel::channel::sender::Sender;
|
||||
use p2p_channel::punch::{NatInfo, NatType, Punch};
|
||||
use parking_lot::Mutex;
|
||||
use protobuf::Message;
|
||||
use rand::prelude::SliceRandom;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
|
||||
pub fn start_cone(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
||||
thread::Builder::new()
|
||||
.name("punch-cone".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = start_(true, punch, current_device) {
|
||||
log::warn!("锥形网络打洞处理线程停止 {:?}", e);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn start_symmetric(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
||||
thread::Builder::new()
|
||||
.name("punch-symmetric".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = start_(false, punch, current_device) {
|
||||
log::warn!("对称网络打洞处理线程停止 {:?}", e);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn start_(
|
||||
is_cone: bool,
|
||||
mut punch: Punch<Ipv4Addr>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) -> io::Result<()> {
|
||||
let mut packet = NetPacket::new([0u8; 12])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.first_set_ttl(1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
loop {
|
||||
let (peer_ip, nat_info) = if is_cone {
|
||||
punch.next_cone(None)?
|
||||
} else {
|
||||
punch.next_symmetric(None)?
|
||||
};
|
||||
if let Some(route) = punch.sender().route(&peer_ip) {
|
||||
if route.metric == 1 {
|
||||
//直连地址不需要打洞
|
||||
continue;
|
||||
}
|
||||
}
|
||||
packet.set_source(current_device.load().virtual_ip());
|
||||
packet.set_destination(peer_ip);
|
||||
log::info!("发起打洞,目标:{:?},{:?}", peer_ip, nat_info);
|
||||
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info) {
|
||||
log::warn!("peer_ip:{:?},e:{:?}", peer_ip, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_punch(
|
||||
nat_test: NatTest,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
sender: Sender<Ipv4Addr>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) {
|
||||
thread::Builder::new()
|
||||
.name("punch-send-request".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = start_punch_(nat_test, device_list, sender, current_device) {
|
||||
log::warn!("对称网络打洞处理线程停止 {:?}", e);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn start_punch_(
|
||||
nat_test: NatTest,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
sender: Sender<Ipv4Addr>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) -> crate::Result<()> {
|
||||
loop {
|
||||
if sender.is_close() {
|
||||
return Ok(());
|
||||
}
|
||||
let current_device = current_device.load();
|
||||
let nat_info = nat_test.nat_info();
|
||||
{
|
||||
let mut list = device_list.lock().clone().1;
|
||||
list.shuffle(&mut rand::thread_rng());
|
||||
let mut count = 0;
|
||||
for info in list {
|
||||
if info.virtual_ip <= current_device.virtual_ip {
|
||||
continue;
|
||||
}
|
||||
if let Some(route) = sender.route(&info.virtual_ip) {
|
||||
if route.metric == 1 {
|
||||
//直连地址不需要打洞
|
||||
continue;
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
if count > 3 {
|
||||
break;
|
||||
}
|
||||
let buf = punch_packet(current_device.virtual_ip(), &nat_info, info.virtual_ip)?;
|
||||
sender.send_to_addr(&buf, current_device.connect_server)?;
|
||||
}
|
||||
}
|
||||
match nat_info.nat_type {
|
||||
NatType::Symmetric => {
|
||||
thread::sleep(Duration::from_secs(28));
|
||||
}
|
||||
NatType::Cone => {
|
||||
thread::sleep(Duration::from_secs(20));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn punch_packet(
|
||||
virtual_ip: Ipv4Addr,
|
||||
nat_info: &NatInfo,
|
||||
dest: Ipv4Addr,
|
||||
) -> crate::Result<Vec<u8>> {
|
||||
let mut punch_reply = PunchInfo::new();
|
||||
punch_reply.reply = false;
|
||||
punch_reply.public_ip_list = nat_info
|
||||
.public_ips
|
||||
.iter()
|
||||
.map(|i| match i {
|
||||
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
|
||||
IpAddr::V6(_) => {
|
||||
panic!()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.local_ip = match nat_info.local_ip {
|
||||
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
|
||||
IpAddr::V6(_) => {
|
||||
panic!()
|
||||
}
|
||||
};
|
||||
punch_reply.local_port = nat_info.local_port as u32;
|
||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 12 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_source(virtual_ip);
|
||||
net_packet.set_destination(dest);
|
||||
net_packet.set_payload(&bytes);
|
||||
Ok(net_packet.into_buffer())
|
||||
}
|
||||
@@ -1,479 +0,0 @@
|
||||
use std::thread;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
|
||||
use chrono::Local;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use parking_lot::Mutex;
|
||||
use protobuf::Message;
|
||||
|
||||
use p2p_channel::channel::{Channel, Route, RouteKey};
|
||||
use p2p_channel::punch::NatInfo;
|
||||
use packet::ethernet;
|
||||
use packet::icmp::{icmp, Kind};
|
||||
use packet::icmp::icmp::HeaderOther;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, CurrentDeviceInfoExt, PeerDeviceInfo};
|
||||
use crate::handle::registration_handler::Register;
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::nat;
|
||||
use crate::nat::NatTest;
|
||||
use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationResponse};
|
||||
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, service_packet, turn_packet, Version};
|
||||
use crate::protocol::control_packet::ControlPacket;
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::tap_device::TapWriter;
|
||||
use crate::tun_device::TunWriter;
|
||||
|
||||
pub fn start(mut handler: RecvHandler) {
|
||||
thread::Builder::new().name("udp-recv-handler".into()).spawn(move || {
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
match handler.channel.recv_from(&mut buf, None) {
|
||||
Ok((len, route)) => {
|
||||
if let Err(e) = handler.handle(&mut buf[..len], &route) {
|
||||
log::warn!("数据处理失败:{:?},e:{:?}",route,e);
|
||||
if let Error::Stop(_) = e {
|
||||
let _ = handler.channel.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}",e);
|
||||
// 检查关闭状态
|
||||
if handler.channel.is_close() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
pub struct RecvHandler {
|
||||
channel: Channel<Ipv4Addr>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
current_device_ext: Arc<AtomicCell<CurrentDeviceInfoExt>>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
register: Arc<Register>,
|
||||
nat_test: NatTest,
|
||||
tun_writer: Option<TunWriter>,
|
||||
tap_writer: Option<TapWriter>,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: IpProxyMap,
|
||||
out_external_route: ExternalRoute,
|
||||
}
|
||||
|
||||
impl RecvHandler {
|
||||
pub fn new(channel: Channel<Ipv4Addr>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
current_device_ext: Arc<AtomicCell<CurrentDeviceInfoExt>>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
register: Arc<Register>,
|
||||
nat_test: NatTest,
|
||||
tun_writer: Option<TunWriter>,
|
||||
tap_writer: Option<TapWriter>,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: IpProxyMap,
|
||||
out_external_route: ExternalRoute,
|
||||
) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
current_device,
|
||||
current_device_ext,
|
||||
device_list,
|
||||
register,
|
||||
nat_test,
|
||||
tun_writer,
|
||||
tap_writer,
|
||||
connect_status,
|
||||
peer_nat_info_map,
|
||||
ip_proxy_map,
|
||||
out_external_route,
|
||||
}
|
||||
}
|
||||
// pub fn try_clone(&self) -> io::Result<Self> {
|
||||
// Ok(Self {
|
||||
// channel: self.channel.try_clone()?,
|
||||
// current_device: self.current_device.clone(),
|
||||
// device_list: self.device_list.clone(),
|
||||
// register: self.register.clone(),
|
||||
// nat_test: self.nat_test.clone(),
|
||||
// tun_writer: self.tun_writer.clone(),
|
||||
// tap_writer: self.tap_writer.clone(),
|
||||
// connect_status: self.connect_status.clone(),
|
||||
// peer_nat_info_map: self.peer_nat_info_map.clone(),
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
impl RecvHandler {
|
||||
fn handle(&self, buf: &mut [u8], route_key: &RouteKey) -> crate::Result<()> {
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
if net_packet.ttl() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let source = net_packet.source();
|
||||
let current_device = self.current_device.load();
|
||||
if source == current_device.virtual_ip() {
|
||||
return Ok(());
|
||||
}
|
||||
let destination = net_packet.destination();
|
||||
if !destination.is_broadcast() && destination != current_device.broadcast_address
|
||||
&& current_device.virtual_ip() != destination && self.connect_status.load() == ConnectStatus::Connected {
|
||||
if !check_dest(source, current_device.virtual_netmask, current_device.virtual_network) {
|
||||
log::warn!("转发数据,源地址错误:{:?},当前网络:{:?},route_key:{:?}",source,current_device.virtual_network,route_key);
|
||||
return Ok(());
|
||||
}
|
||||
if !check_dest(destination, current_device.virtual_netmask, current_device.virtual_network) {
|
||||
log::warn!("转发数据,目的地址错误:{:?},当前网络:{:?},route_key:{:?}",destination,current_device.virtual_network,route_key);
|
||||
return Ok(());
|
||||
}
|
||||
net_packet.set_ttl(net_packet.ttl() - 1);
|
||||
let ttl = net_packet.ttl();
|
||||
if ttl > 0 {
|
||||
// 转发
|
||||
if let Some(route) = self.channel.route(&destination) {
|
||||
if route.metric <= net_packet.ttl() {
|
||||
self.channel.send_to_route(net_packet.buffer(), &route.route_key())?;
|
||||
}
|
||||
} else if (ttl > 1 || destination == current_device.virtual_gateway())
|
||||
&& source != current_device.virtual_gateway() {
|
||||
//网关默认要转发一次,生存时间不够的发到网关也会被丢弃
|
||||
self.channel.send_to_addr(net_packet.buffer(), current_device.connect_server)?;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
match net_packet.protocol() {
|
||||
Protocol::Ipv4Turn => {
|
||||
let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?;
|
||||
if ipv4.destination_ip() == destination && ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
|
||||
if icmp_packet.kind() == Kind::EchoRequest {
|
||||
//开启ping
|
||||
icmp_packet.set_kind(Kind::EchoReply);
|
||||
icmp_packet.update_checksum();
|
||||
ipv4.set_source_ip(destination);
|
||||
ipv4.set_destination_ip(source);
|
||||
ipv4.update_checksum();
|
||||
net_packet.set_source(destination);
|
||||
net_packet.set_destination(source);
|
||||
self.channel.send_to_route(net_packet.buffer(), route_key)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
if ipv4.destination_ip() != destination {
|
||||
if let Some(gate_way) = self.out_external_route.route(&ipv4.destination_ip()) {
|
||||
match ipv4.protocol() {
|
||||
ipv4::protocol::Protocol::Tcp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||
let source_port = tcp_packet.source_port();
|
||||
let dest_port = tcp_packet.destination_port();
|
||||
tcp_packet.set_destination_port(self.ip_proxy_map.tcp_proxy_port);
|
||||
tcp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
self.ip_proxy_map.tcp_proxy_map.insert(SocketAddrV4::new(source, source_port),
|
||||
(SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port)));
|
||||
}
|
||||
ipv4::protocol::Protocol::Udp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let mut udp_packet = packet::udp::udp::UdpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||
let source_port = udp_packet.source_port();
|
||||
let dest_port = udp_packet.destination_port();
|
||||
udp_packet.set_destination_port(self.ip_proxy_map.udp_proxy_port);
|
||||
udp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
println!("{:?}",ipv4);
|
||||
self.ip_proxy_map.udp_proxy_map.insert(SocketAddrV4::new(source, source_port),
|
||||
(SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port)));
|
||||
}
|
||||
ipv4::protocol::Protocol::Icmp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?;
|
||||
match icmp_packet.header_other() {
|
||||
HeaderOther::Identifier(id, seq) => {
|
||||
self.ip_proxy_map.icmp_proxy_map.insert((dest_ip, id, seq), source);
|
||||
self.ip_proxy_map.send_icmp(ipv4.payload(), &gate_way, &dest_ip)?;
|
||||
}
|
||||
_ => {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(tun_writer) = &self.tun_writer {
|
||||
tun_writer.write(net_packet.payload())?;
|
||||
} else {
|
||||
if let Some(tap_writer) = &self.tap_writer {
|
||||
let mut ethernet_packet = ethernet::packet::EthernetPacket::unchecked(vec![0; 14 + ipv4.buffer.len()]);
|
||||
let source = source.octets();
|
||||
ethernet_packet.set_source(&[source[0], source[1], source[2], source[3], 123, 234]);
|
||||
ethernet_packet.set_destination(&self.current_device_ext.load().mac);
|
||||
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||
ethernet_packet.payload_mut().copy_from_slice(ipv4.buffer);
|
||||
tap_writer.write(ðernet_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::Service => {
|
||||
self.service(current_device, source, net_packet, route_key)?;
|
||||
}
|
||||
Protocol::Error => {
|
||||
self.error(current_device, source, net_packet, route_key)?;
|
||||
}
|
||||
Protocol::Control => {
|
||||
self.control(current_device, source, net_packet, route_key)?;
|
||||
}
|
||||
Protocol::OtherTurn => {
|
||||
self.other_turn(current_device, source, net_packet, route_key)?;
|
||||
}
|
||||
Protocol::UnKnow(e) => {
|
||||
log::info!("不支持的协议:{}",e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn service(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
if route_key.addr != current_device.connect_server || source != current_device.virtual_gateway() {
|
||||
return Ok(());
|
||||
}
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationRequest => {}
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
let local_port = self.channel.local_addr()?.port();
|
||||
let local_ip = nat::local_ip()?;
|
||||
let nat_info = self.nat_test.re_test(Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_port);
|
||||
self.channel.set_nat_type(nat_info.nat_type)?;
|
||||
let new_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let current_ip = current_device.virtual_ip();
|
||||
if current_ip != new_ip {
|
||||
// ip发生变化
|
||||
log::info!("ip发生变化,old_ip:{:?},new_ip:{:?}",current_ip,new_ip);
|
||||
let old_netmask = current_device.virtual_netmask;
|
||||
let old_gateway = current_device.virtual_gateway();
|
||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||
if let Some(tun_writer) = &self.tun_writer {
|
||||
tun_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
|
||||
} else {
|
||||
if let Some(tap_writer) = &self.tap_writer {
|
||||
tap_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
|
||||
}
|
||||
}
|
||||
let new_current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway,
|
||||
virtual_netmask, current_device.connect_server);
|
||||
if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) {
|
||||
log::warn!("替换失败:{:?}",e);
|
||||
}
|
||||
}
|
||||
self.connect_status.store(ConnectStatus::Connected);
|
||||
}
|
||||
service_packet::Protocol::PollDeviceList => {}
|
||||
service_packet::Protocol::PushDeviceList => {
|
||||
let device_list_t = DeviceList::parse_from_bytes(net_packet.payload())?;
|
||||
let ip_list = device_list_t
|
||||
.device_info_list
|
||||
.into_iter()
|
||||
.map(|info| {
|
||||
PeerDeviceInfo::new(
|
||||
Ipv4Addr::from(info.virtual_ip),
|
||||
info.name,
|
||||
info.device_status as u8,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let mut dev = self.device_list.lock();
|
||||
if dev.0 != device_list_t.epoch as u16 {
|
||||
dev.0 = device_list_t.epoch as u16;
|
||||
dev.1 = ip_list;
|
||||
}
|
||||
}
|
||||
service_packet::Protocol::UnKnow(u) => {
|
||||
log::warn!("未知服务协议:{}",u);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn error(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
if route_key.addr != current_device.connect_server || source != current_device.virtual_gateway() {
|
||||
return Ok(());
|
||||
}
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
InErrorPacket::TokenError => {
|
||||
return Err(Error::Stop("Token error".to_string()));
|
||||
}
|
||||
InErrorPacket::Disconnect => {
|
||||
self.connect_status.store(ConnectStatus::Connecting);
|
||||
self.register.fast_register()?;
|
||||
}
|
||||
InErrorPacket::AddressExhausted => {
|
||||
//地址用尽
|
||||
return Err(Error::Stop("IP address has been exhausted".to_string()));
|
||||
}
|
||||
InErrorPacket::OtherError(e) => {
|
||||
log::error!("OtherError {:?}", e.message());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn control(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, mut net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
ControlPacket::PingPacket(_) => {
|
||||
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
net_packet.set_destination(source);
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
self.channel.send_to_route(net_packet.buffer(), route_key)?;
|
||||
if metric == 1 {
|
||||
if let Some(current_route) = self.channel.route(&source) {
|
||||
if current_route.metric > 1 {
|
||||
let route = Route::from(*route_key, 1, -1);
|
||||
self.channel.add_route(source, route);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlPacket::PongPacket(pong_packet) => {
|
||||
let current_time = Local::now().timestamp_millis() as u16;
|
||||
if current_time < pong_packet.time() {
|
||||
return Ok(());
|
||||
}
|
||||
let rt = (current_time - pong_packet.time()) as i64;
|
||||
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
||||
if let Some(current_route) = self.channel.route(&source) {
|
||||
if ¤t_route.route_key() == route_key {
|
||||
self.channel.update_route(&source, metric, rt);
|
||||
} else if current_route.metric >= metric && current_route.rt > rt {
|
||||
let route = Route::from(*route_key, metric, rt);
|
||||
self.channel.add_route(source, route);
|
||||
}
|
||||
} else {
|
||||
let route = Route::from(*route_key, metric, rt);
|
||||
self.channel.add_route(source, route);
|
||||
}
|
||||
if route_key.addr == current_device.connect_server && source == current_device.virtual_gateway() {
|
||||
let epoch = self.device_list.lock().0;
|
||||
if pong_packet.epoch() != epoch {
|
||||
let mut poll_device = NetPacket::new([0; 12])?;
|
||||
poll_device.set_source(current_device.virtual_ip());
|
||||
poll_device.set_destination(source);
|
||||
poll_device.set_version(Version::V1);
|
||||
poll_device.first_set_ttl(MAX_TTL);
|
||||
poll_device.set_protocol(Protocol::Service);
|
||||
poll_device.set_transport_protocol(service_packet::Protocol::PollDeviceList.into());
|
||||
self.channel.send_to_route(poll_device.buffer(), route_key)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlPacket::PunchRequest => {
|
||||
// log::info!("PunchRequest route_key:{:?}",route_key);
|
||||
//回应
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into());
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
net_packet.set_destination(source);
|
||||
net_packet.first_set_ttl(1);
|
||||
self.channel.send_to_route(net_packet.buffer(), route_key)?;
|
||||
let route = Route::from(*route_key, 1, -1);
|
||||
self.channel.add_route(source, route);
|
||||
}
|
||||
ControlPacket::PunchResponse => {
|
||||
// log::info!("PunchResponse route_key:{:?}",route_key);
|
||||
let route = Route::from(*route_key, 1, -1);
|
||||
self.channel.add_route(net_packet.source(), route);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn other_turn(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
match turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
turn_packet::Protocol::Punch => {
|
||||
let punch_info = PunchInfo::parse_from_bytes(net_packet.payload())?;
|
||||
let public_ips = punch_info.public_ip_list.
|
||||
iter().map(|v| { IpAddr::from(v.to_be_bytes()) }).collect();
|
||||
let peer_nat_info = NatInfo::new(public_ips,
|
||||
punch_info.public_port as u16,
|
||||
punch_info.public_port_range as u16,
|
||||
IpAddr::from(punch_info.local_ip.to_be_bytes()),
|
||||
punch_info.local_port as u16,
|
||||
punch_info.nat_type.enum_value_or_default().into());
|
||||
self.peer_nat_info_map.insert(source, peer_nat_info.clone());
|
||||
if !punch_info.reply {
|
||||
let mut punch_reply = PunchInfo::new();
|
||||
punch_reply.reply = true;
|
||||
let nat_info = self.nat_test.nat_info();
|
||||
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| {
|
||||
match i {
|
||||
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
|
||||
IpAddr::V6(_) => 0
|
||||
}
|
||||
}).collect();
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.nat_type =
|
||||
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||
punch_reply.local_ip = match nat_info.local_ip {
|
||||
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
|
||||
IpAddr::V6(_) => 0
|
||||
};
|
||||
punch_reply.local_port = nat_info.local_port as u32;
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet =
|
||||
NetPacket::new(vec![0u8; 12 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(
|
||||
turn_packet::Protocol::Punch.into(),
|
||||
);
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
net_packet.set_destination(source);
|
||||
net_packet.set_payload(&bytes);
|
||||
if !peer_nat_info.local_ip.is_unspecified() && peer_nat_info.local_port != 0 {
|
||||
let mut packet = NetPacket::new([0u8; 12])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.first_set_ttl(1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
packet.set_source(current_device.virtual_ip());
|
||||
packet.set_destination(source);
|
||||
let _ = self.channel.send_to_addr(packet.buffer(), SocketAddr::new(peer_nat_info.local_ip, peer_nat_info.local_port));
|
||||
}
|
||||
if let Err(e) = self.channel.punch(source, peer_nat_info) {
|
||||
log::warn!("发送到打洞通道失败 {:?}",e);
|
||||
return Ok(());
|
||||
}
|
||||
self.channel.send_to_route(net_packet.buffer(), route_key)?;
|
||||
} else {
|
||||
let _ = self.channel.punch(source, peer_nat_info);
|
||||
}
|
||||
}
|
||||
turn_packet::Protocol::UnKnow(e) => {
|
||||
log::warn!("不支持的转发协议 {:?},source:{:?}",e,source);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Local;
|
||||
use p2p_channel::channel::sender::Sender;
|
||||
use p2p_channel::channel::Channel;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::protocol::{service_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||
|
||||
///向中继服务器注册,token标识一个虚拟网关,device_id防止多次注册时得到的ip不一致
|
||||
pub fn registration(
|
||||
channel: &mut Channel<Ipv4Addr>,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
) -> Result<RegistrationResponse> {
|
||||
let request_packet =
|
||||
registration_request_packet(token.clone(), device_id.clone(), name.clone(), false)?;
|
||||
let buf = request_packet.buffer();
|
||||
let mut recv_buf = [0u8; 10240];
|
||||
channel.send_to_addr(buf, server_address)?;
|
||||
let (len, route) = channel.recv_from(&mut recv_buf, Some(Duration::from_millis(300)))?;
|
||||
if server_address != route.addr {
|
||||
return Err(Error::Warn(format!("数据来源错误:{:?}", route.addr)));
|
||||
}
|
||||
let net_packet = NetPacket::new(&recv_buf[..len])?;
|
||||
return match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
Ok(response)
|
||||
}
|
||||
_ => Err(Error::Warn(format!("数据错误:{:?}", net_packet))),
|
||||
}
|
||||
}
|
||||
Protocol::Error => {
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload()) {
|
||||
Ok(e) => match e {
|
||||
InErrorPacket::TokenError => Err(Error::Stop("token错误".to_string())),
|
||||
InErrorPacket::Disconnect => Err(Error::Warn("断开连接".to_string())),
|
||||
InErrorPacket::AddressExhausted => Err(Error::Stop("地址用尽".to_string())),
|
||||
InErrorPacket::OtherError(e) => match e.message() {
|
||||
Ok(str) => Err(Error::Warn(str)),
|
||||
Err(e) => Err(Error::Warn(format!("{:?}", e))),
|
||||
},
|
||||
},
|
||||
Err(e) => Err(Error::Warn(format!("{:?}", e))),
|
||||
}
|
||||
}
|
||||
_ => Err(Error::Warn(format!("数据错误:{:?}", net_packet))),
|
||||
};
|
||||
}
|
||||
|
||||
fn registration_request_packet(
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
is_fast: bool,
|
||||
) -> crate::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = RegistrationRequest::new();
|
||||
request.token = token;
|
||||
request.device_id = device_id;
|
||||
request.name = name;
|
||||
request.is_fast = is_fast;
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let buf = vec![0u8; 12 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_payload(&bytes);
|
||||
Ok(net_packet)
|
||||
}
|
||||
|
||||
pub struct Register {
|
||||
sender: Sender<Ipv4Addr>,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
time: AtomicI64,
|
||||
}
|
||||
|
||||
impl Register {
|
||||
pub fn new(
|
||||
sender: Sender<Ipv4Addr>,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
sender,
|
||||
server_address,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
time: AtomicI64::new(0),
|
||||
}
|
||||
}
|
||||
pub fn fast_register(&self) -> io::Result<()> {
|
||||
let last = self.time.load(Ordering::Relaxed);
|
||||
let new = Local::now().timestamp_millis();
|
||||
if new - last < 1000
|
||||
|| self
|
||||
.time
|
||||
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
//短时间不重复注册
|
||||
return Ok(());
|
||||
}
|
||||
log::info!("重新连接");
|
||||
let request_packet = registration_request_packet(
|
||||
self.token.clone(),
|
||||
self.device_id.clone(),
|
||||
self.name.clone(),
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let buf = request_packet.buffer();
|
||||
self.sender.send_to_addr(buf, self.server_address)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use std::{io, thread};
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use p2p_channel::channel::sender::Sender;
|
||||
use packet::arp::arp::ArpPacket;
|
||||
use packet::ethernet;
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
use packet::icmp::icmp::IcmpPacket;
|
||||
use packet::icmp::Kind;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::{check_dest, CurrentDeviceInfo};
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
||||
use crate::tap_device::{TapReader, TapWriter};
|
||||
|
||||
pub fn start(sender: Sender<Ipv4Addr>,
|
||||
tap_reader: TapReader,
|
||||
tap_writer: TapWriter,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: ExternalRoute,
|
||||
ip_proxy_map: IpProxyMap) {
|
||||
thread::Builder::new().name("tap-handler".into()).spawn(move || {
|
||||
if let Err(e) = start_(sender, tap_reader, tap_writer, current_device,ip_route,ip_proxy_map) {
|
||||
log::warn!("{:?}",e);
|
||||
}
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
fn start_(sender: Sender<Ipv4Addr>,
|
||||
tap_reader: TapReader,
|
||||
tap_writer: TapWriter,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: ExternalRoute,
|
||||
ip_proxy_map: IpProxyMap) -> io::Result<()> {
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500]).unwrap();
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||
net_packet.set_ttl(MAX_TTL);
|
||||
let mut buf = [0; 2048];
|
||||
loop {
|
||||
let len = tap_reader.read(&mut buf)?;
|
||||
if len == 0 {
|
||||
continue;
|
||||
}
|
||||
let mut ethernet_packet = EthernetPacket::unchecked(&mut buf[..len]);
|
||||
if let Err(e) = handle(&mut net_packet, ¤t_device, &tap_writer, &mut ethernet_packet, &sender,&ip_route,&ip_proxy_map) {
|
||||
log::error!("tap handle{:?}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(net_packet: &mut NetPacket<Vec<u8>>, current_device: &AtomicCell<CurrentDeviceInfo>, tap_writer: &TapWriter, ethernet_packet: &mut EthernetPacket<&mut [u8]>, sender: &Sender<Ipv4Addr>, ip_route: &ExternalRoute, proxy_map: &IpProxyMap) -> crate::Result<()> {
|
||||
let current_device = current_device.load();
|
||||
match ethernet_packet.protocol() {
|
||||
ethernet::protocol::Protocol::Arp => {
|
||||
let mut out_ethernet_packet = EthernetPacket::unchecked(ethernet_packet.buffer.to_vec());
|
||||
let arp_packet = ArpPacket::unchecked(ethernet_packet.payload());
|
||||
let mut out_arp_packet = ArpPacket::unchecked(out_ethernet_packet.payload_mut());
|
||||
let sender_h = arp_packet.sender_hardware_addr();
|
||||
let sender_p = arp_packet.sender_protocol_addr();
|
||||
let target_p = arp_packet.target_protocol_addr();
|
||||
if target_p == &[0, 0, 0, 0] || sender_p == &[0, 0, 0, 0] || target_p == sender_p {
|
||||
return Ok(());
|
||||
}
|
||||
//回复一个虚假的MAC地址
|
||||
out_arp_packet.set_sender_hardware_addr(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]);
|
||||
out_arp_packet.set_sender_protocol_addr(target_p);
|
||||
out_arp_packet.set_target_hardware_addr(sender_h);
|
||||
out_arp_packet.set_target_protocol_addr(sender_p);
|
||||
out_arp_packet.set_op_code(2);
|
||||
out_ethernet_packet.set_source(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]);
|
||||
out_ethernet_packet.set_destination(sender_h);
|
||||
|
||||
tap_writer.write(&out_ethernet_packet.buffer)?;
|
||||
}
|
||||
ethernet::protocol::Protocol::Ipv4 => {
|
||||
// println!("in ethernet_packet {:?}", ethernet_packet);
|
||||
let mut ipv4_packet = IpV4Packet::unchecked(ethernet_packet.payload_mut());
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
let mut dest_ip = ipv4_packet.destination_ip();
|
||||
if src_ip != current_device.virtual_ip() {
|
||||
return Ok(());
|
||||
}
|
||||
if !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast() {
|
||||
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
||||
//路由的目标不能是自己
|
||||
if r_dest_ip == src_ip {
|
||||
return Ok(());
|
||||
}
|
||||
dest_ip = r_dest_ip;
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}else{
|
||||
match ipv4_packet.protocol() {
|
||||
ipv4::protocol::Protocol::Tcp => {
|
||||
let dest_addr = {
|
||||
let tcp_packet = packet::tcp::tcp::TcpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.tcp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value().1;
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||
tcp_packet.set_source_port(source_addr.port());
|
||||
tcp_packet.update_checksum();
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}
|
||||
}
|
||||
ipv4::protocol::Protocol::Udp => {
|
||||
let dest_addr = {
|
||||
let udp_packet = packet::udp::udp::UdpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.udp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value().1;
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut udp_packet = packet::udp::udp::UdpPacket::new(src_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||
udp_packet.set_source_port(source_addr.port());
|
||||
udp_packet.update_checksum();
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if src_ip == dest_ip {
|
||||
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::unchecked(ipv4_packet.payload_mut());
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
let src = ipv4_packet.source_ip();
|
||||
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||
ipv4_packet.set_destination_ip(src);
|
||||
ipv4_packet.update_checksum();
|
||||
tap_writer.write(ethernet_packet.buffer)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
net_packet.set_source(src_ip);
|
||||
net_packet.set_destination(dest_ip);
|
||||
let data_len = ipv4_packet.buffer.len();
|
||||
net_packet.set_payload(ipv4_packet.buffer);
|
||||
//优先发到直连到地址
|
||||
if sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip).is_err() {
|
||||
sender.send_to_addr(&net_packet.buffer()[..(12 + data_len)], current_device.connect_server)?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// log::warn!("不支持的二层协议:{:?}",p)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
use std::{io, thread};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
|
||||
use p2p_channel::channel::sender::Sender;
|
||||
use packet::icmp:: Kind;
|
||||
use packet::icmp::icmp:: IcmpPacket;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::{check_dest, CurrentDeviceInfo};
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
||||
use crate::tun_device::{TunReader, TunWriter};
|
||||
|
||||
fn icmp(tun_writer: &TunWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
|
||||
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
let src = ipv4_packet.source_ip();
|
||||
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||
ipv4_packet.set_destination_ip(src);
|
||||
ipv4_packet.update_checksum();
|
||||
tun_writer.write(ipv4_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 接收tun数据,并且转发到udp上
|
||||
#[inline]
|
||||
fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, current_device: CurrentDeviceInfo, net_packet: &mut NetPacket<[u8; 1512]>, ip_route: &ExternalRoute, proxy_map: &IpProxyMap) -> Result<()> {
|
||||
let data_len = data.len();
|
||||
let mut ipv4_packet = match IpV4Packet::new(data) {
|
||||
Ok(ipv4_packet) => ipv4_packet,
|
||||
Err(packet::error::Error::Unimplemented) => {
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
};
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
let mut dest_ip = ipv4_packet.destination_ip();
|
||||
// if dest_ip == cur_info.broadcast_address {
|
||||
// // 启动服务后会收到对137端口的广播
|
||||
// // 137端口是在局域网中提供计算机的名字或IP地址查询服务
|
||||
// return Ok(());
|
||||
// }
|
||||
if src_ip != current_device.virtual_ip() {
|
||||
return Ok(());
|
||||
}
|
||||
if src_ip == dest_ip {
|
||||
return icmp(&tun_writer, ipv4_packet);
|
||||
}
|
||||
if !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast() {
|
||||
// println!("非目标 {:?}",ipv4_packet);
|
||||
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
||||
//路由的目标不能是自己
|
||||
if r_dest_ip == src_ip {
|
||||
return Ok(());
|
||||
}
|
||||
dest_ip = r_dest_ip;
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
match ipv4_packet.protocol() {
|
||||
ipv4::protocol::Protocol::Tcp => {
|
||||
let dest_addr = {
|
||||
let tcp_packet = packet::tcp::tcp::TcpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.tcp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value().1;
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||
tcp_packet.set_source_port(source_addr.port());
|
||||
tcp_packet.update_checksum();
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}
|
||||
}
|
||||
ipv4::protocol::Protocol::Udp => {
|
||||
let dest_addr = {
|
||||
let udp_packet = packet::udp::udp::UdpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.udp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value().1;
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut udp_packet = packet::udp::udp::UdpPacket::new(source_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||
udp_packet.set_source_port(source_addr.port());
|
||||
udp_packet.update_checksum();
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
net_packet.set_source(src_ip);
|
||||
net_packet.set_destination(dest_ip);
|
||||
net_packet.set_payload(ipv4_packet.buffer);
|
||||
//优先发到直连到地址
|
||||
if sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip).is_err() {
|
||||
sender.send_to_addr(&net_packet.buffer()[..(12 + data_len)], current_device.connect_server)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn start(sender: Sender<Ipv4Addr>,
|
||||
tun_reader: TunReader,
|
||||
tun_writer: TunWriter,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: ExternalRoute,
|
||||
ip_proxy_map: IpProxyMap) {
|
||||
thread::Builder::new().name("tun-handler".into()).spawn(move || {
|
||||
if let Err(e) = start_(sender, tun_reader, tun_writer, current_device, ip_route, ip_proxy_map) {
|
||||
log::warn!("{:?}",e);
|
||||
}
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn start_(sender: Sender<Ipv4Addr>,
|
||||
tun_reader: TunReader,
|
||||
tun_writer: TunWriter,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: ExternalRoute,
|
||||
ip_proxy_map: IpProxyMap) -> io::Result<()> {
|
||||
let mut net_packet = NetPacket::new([0u8; 4 + 8 + 1500])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||
net_packet.set_ttl(MAX_TTL);
|
||||
loop {
|
||||
let mut data = tun_reader.next()?;
|
||||
match handle(&sender, data.bytes_mut(), &tun_writer, current_device.load(), &mut net_packet, &ip_route, &ip_proxy_map) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
fn start_(sender: Sender<Ipv4Addr>,
|
||||
tun_reader: TunReader,
|
||||
tun_writer: TunWriter,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: ExternalRoute,
|
||||
ip_proxy_map: IpProxyMap) -> io::Result<()> {
|
||||
let mut net_packet = NetPacket::new([0u8; 4 + 8 + 1500])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||
net_packet.set_ttl(MAX_TTL);
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
let len = tun_reader.read(&mut buf)?;
|
||||
match handle(&sender, &mut buf[..len], &tun_writer, current_device.load(), &mut net_packet, &ip_route, &ip_proxy_map) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
use std::{io, thread};
|
||||
use std::collections::HashMap;
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use socket2::{SockAddr, Socket};
|
||||
use tokio::net::{TcpListener, UdpSocket};
|
||||
use p2p_channel::channel::sender::Sender;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::ip_proxy::icmp_proxy::IcmpProxy;
|
||||
use crate::ip_proxy::tcp_proxy::TcpProxy;
|
||||
use crate::ip_proxy::udp_proxy::UdpProxy;
|
||||
|
||||
pub mod icmp_proxy;
|
||||
pub mod tcp_proxy;
|
||||
pub mod udp_proxy;
|
||||
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
Icmp,
|
||||
Tcp,
|
||||
Udp,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IpProxyMap {
|
||||
pub(crate) tcp_proxy_port: u16,
|
||||
pub(crate) udp_proxy_port: u16,
|
||||
//真实源地址 -> (绑定地址,目的地址)
|
||||
pub(crate) tcp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
pub(crate) udp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
// icmp用Identifier来区分,没有Identifier的一律不转发
|
||||
pub(crate) icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||
icmp_sockets: HashMap<Ipv4Addr, Arc<Socket>>,
|
||||
}
|
||||
|
||||
impl IpProxyMap {
|
||||
pub fn send_icmp(&self, buf: &[u8], src: &Ipv4Addr, dest: &Ipv4Addr) -> io::Result<usize> {
|
||||
if let Some(socket) = self.icmp_sockets.get(src) {
|
||||
socket.send_to(buf, &SockAddr::from(SocketAddrV4::new(*dest, 0)))
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("not found src:{},dest:{}", src, dest)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init_proxy(sender: Sender<Ipv4Addr>, bind_ips: Vec<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<IpProxyMap> {
|
||||
let mut icmp_sockets = HashMap::new();
|
||||
let tcp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>> = Arc::new(SkipMap::new());
|
||||
let udp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>> = Arc::new(SkipMap::new());
|
||||
let icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>> = Arc::new(SkipMap::new());
|
||||
let tcp_listener = TcpListener::bind("0.0.0.0:0").await?;
|
||||
let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
let tcp_proxy_port = tcp_listener.local_addr()?.port();
|
||||
let udp_proxy_port = udp_socket.local_addr()?.port();
|
||||
|
||||
{
|
||||
let tcp_proxy_map = tcp_proxy_map.clone();
|
||||
tokio::spawn(async {
|
||||
let tcp_proxy = TcpProxy::new(tcp_listener, tcp_proxy_map);
|
||||
tcp_proxy.start().await
|
||||
});
|
||||
}
|
||||
{
|
||||
let udp_proxy_map = udp_proxy_map.clone();
|
||||
tokio::spawn(async {
|
||||
let udp_proxy = UdpProxy::new(udp_socket, udp_proxy_map);
|
||||
udp_proxy.start().await
|
||||
});
|
||||
}
|
||||
for ip in bind_ips {
|
||||
let addr = SocketAddrV4::new(ip, 0);
|
||||
let icmp_proxy_map = icmp_proxy_map.clone();
|
||||
let icmp_proxy = IcmpProxy::new(addr, icmp_proxy_map, sender.try_clone()?, current_device.clone())?;
|
||||
icmp_sockets.insert(ip, icmp_proxy.icmp_socket());
|
||||
thread::spawn(move || {
|
||||
icmp_proxy.start();
|
||||
});
|
||||
}
|
||||
|
||||
Ok(IpProxyMap {
|
||||
tcp_proxy_port,
|
||||
udp_proxy_port,
|
||||
tcp_proxy_map,
|
||||
udp_proxy_map,
|
||||
icmp_proxy_map,
|
||||
icmp_sockets,
|
||||
})
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
use crate::tun_device::{TunReader, TunWriter};
|
||||
|
||||
pub type TapReader = TunReader;
|
||||
pub type TapWriter = TunWriter;
|
||||
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use tun::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::io;
|
||||
|
||||
pub fn create_tap(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> io::Result<(TunWriter, TunReader, [u8; 6])> {
|
||||
println!("========TAP网卡配置========");
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(1420)
|
||||
.layer(tun::Layer::L2)
|
||||
// .queues(2) 用多个队列有兼容性问题
|
||||
.up();
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
let name = dev.name();
|
||||
println!("name:{:?}", name);
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
|
||||
let mac_out = std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(get_mac_cmd)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !mac_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("获取mac地址错误: {:?}", mac_out)));
|
||||
}
|
||||
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
|
||||
let mut mac = [0; 6];
|
||||
let mut split = mac_str.split(":");
|
||||
for i in 0..6 {
|
||||
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
|
||||
}
|
||||
println!("mac:{:?}", mac);
|
||||
println!("========TAP网卡配置========");
|
||||
Ok((
|
||||
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
||||
TunReader(reader, packet_information),
|
||||
mac
|
||||
))
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use crate::tun_device::{TunReader, TunWriter};
|
||||
|
||||
pub type TapReader = TunReader;
|
||||
pub type TapWriter = TunWriter;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
pub fn create_tap(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> crate::error::Result<(TapWriter, TapReader, [u8; 6])> {
|
||||
unimplemented!()
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
mod linux;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod mac;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::{TapWriter, TapReader};
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::create_tap;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub use linux::{TapWriter, TapReader};
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub use linux::create_tap;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::create_tap;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::delete_tap;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{TapReader, TapWriter};
|
||||
@@ -1,100 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use win_tun_tap::{IFace, TapDevice};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TapWriter(Arc<TapDevice>, Arc<Mutex<()>>);
|
||||
|
||||
impl TapWriter {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
||||
pub fn change_ip(
|
||||
&self,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
old_netmask: Ipv4Addr,
|
||||
old_gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
if let Err(e) =
|
||||
self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
|
||||
{
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
self.0.set_ip(address, netmask)?;
|
||||
self.0.add_route(dest(gateway, netmask), netmask, gateway)
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
self.0.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
|
||||
let ip = ip.octets();
|
||||
let mask = mask.octets();
|
||||
Ipv4Addr::from([
|
||||
ip[0] & mask[0],
|
||||
ip[1] & mask[1],
|
||||
ip[2] & mask[2],
|
||||
ip[3] & mask[3],
|
||||
])
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TapReader(Arc<TapDevice>);
|
||||
|
||||
impl TapReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub const TAP_INTERFACE_NAME: &str = "Switch-Tap-V1";
|
||||
|
||||
pub fn create_tap(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> io::Result<(TapWriter, TapReader, [u8; 6])> {
|
||||
println!("========TAP网卡配置========");
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
let tap_device = TapDevice::create()?;
|
||||
tap_device.set_name(TAP_INTERFACE_NAME)?;
|
||||
tap_device
|
||||
}
|
||||
};
|
||||
let mac = tap_device.get_mac()?;
|
||||
println!("name:{:?}", tap_device.get_name()?);
|
||||
println!("version:{:x?}", tap_device.get_version()?);
|
||||
println!("mac:{:x?}", mac);
|
||||
tap_device.set_ip(address, netmask)?;
|
||||
tap_device.set_mtu(1420)?;
|
||||
tap_device.set_status(true)?;
|
||||
tap_device.add_route(address, netmask, gateway)?;
|
||||
let tap = Arc::new(tap_device);
|
||||
println!("========TAP网卡配置========");
|
||||
Ok((
|
||||
TapWriter(tap.clone(), Arc::default()),
|
||||
TapReader(tap),
|
||||
mac
|
||||
))
|
||||
}
|
||||
|
||||
pub fn delete_tap() {
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(_) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let _ = tap_device.delete();
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
use std::io;
|
||||
use crate::tun_device::{TunReader, TunWriter};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use tun::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
) -> crate::error::Result<(TunWriter, TunReader)> {
|
||||
println!("========TUN网卡配置========");
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(1420)
|
||||
// .queues(2) 用多个队列有兼容性问题
|
||||
.up();
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let name = dev.name();
|
||||
println!("name:{:?}", name);
|
||||
for (address, netmask) in in_ips {
|
||||
add_route(name, address, netmask)?;
|
||||
}
|
||||
println!("========TUN网卡配置========");
|
||||
Ok((
|
||||
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
||||
TunReader(reader, packet_information),
|
||||
))
|
||||
}
|
||||
|
||||
fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!(
|
||||
"ip route add {:?}/{:?} dev {}",
|
||||
address, netmask, name
|
||||
);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", route_add_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
use std::net::Ipv4Addr;
|
||||
use std::process::Command;
|
||||
use std::io;
|
||||
use tun::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::tun_device::{TunReader, TunWriter};
|
||||
|
||||
pub fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
) -> crate::error::Result<(TunWriter, TunReader)> {
|
||||
println!("========TUN网卡配置========");
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(1420)
|
||||
.up();
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
let name = dev.name();
|
||||
config_ip(name, address, netmask, gateway)?;
|
||||
add_route(name, address, netmask)?;
|
||||
for (address, netmask) in in_ips {
|
||||
add_route(name, address, netmask)?;
|
||||
}
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
println!("name:{:?}", name);
|
||||
println!("========TUN网卡配置========");
|
||||
Ok((
|
||||
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
||||
TunReader(reader, packet_information),
|
||||
))
|
||||
}
|
||||
|
||||
fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!(
|
||||
"sudo route -n add -net {:?}/{:?} -interface {}",
|
||||
address, netmask, name
|
||||
);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", route_add_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn config_ip(name: &str, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, address, gateway);
|
||||
let up_eth_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(up_eth_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !up_eth_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", up_eth_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub use linux::create_tun;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::create_tun;
|
||||
#[cfg(any(unix))]
|
||||
pub use unix::{TunReader, TunWriter};
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::create_tun;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::delete_tun;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{TunReader, TunWriter};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub mod linux;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod mac;
|
||||
#[cfg(any(unix))]
|
||||
pub mod unix;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod windows;
|
||||
@@ -1,72 +0,0 @@
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::BufMut;
|
||||
use tun::platform::posix::{Reader, Writer};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use tun::platform::linux::Device;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
use tun::platform::macos::Device;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunReader(pub(crate) Reader, pub(crate) bool);
|
||||
|
||||
impl TunReader {
|
||||
pub fn read(&self, buf: & mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunWriter(pub(crate) Writer, pub(crate) bool, pub(crate) Arc<Mutex<Device>>);
|
||||
|
||||
impl TunWriter {
|
||||
pub fn write(&self, packet: &[u8]) -> io::Result<()> {
|
||||
if self.1 {
|
||||
let mut buf = Vec::<u8>::with_capacity(4 + packet.len());
|
||||
buf.put_u16(0);
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
buf.put_u16(libc::PF_INET as u16);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
buf.put_u16(libc::ETH_P_IP as u16);
|
||||
buf.extend_from_slice(packet);
|
||||
self.0.write_all(&buf)
|
||||
} else {
|
||||
self.0.write_all(packet)
|
||||
}
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()>{
|
||||
unsafe {
|
||||
let raw = self.0.as_raw_fd();
|
||||
if raw >= 0 {
|
||||
libc::close(raw);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let mut config = tun::Configuration::default();
|
||||
use tun::Device;
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(1420)
|
||||
// .queues(2)
|
||||
.up();
|
||||
let mut dev = self.2.lock();
|
||||
if let Err(e) = dev.configure(&config) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Err(e) = crate::tun_device::mac::config_ip(dev.name(), address, netmask, gateway){
|
||||
log::error!("{}",e);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
use std::{io, thread};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use libloading::Library;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use win_tun_tap::{IFace, TunDevice};
|
||||
use win_tun_tap::packet::TunPacket;
|
||||
|
||||
pub const TUN_INTERFACE_NAME: &str = "Switch-V1";
|
||||
pub const TUN_POOL_NAME: &str = "Switch-V1";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunWriter(Arc<TunDevice>, Arc<Mutex<()>>);
|
||||
|
||||
impl TunWriter {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
|
||||
let mut packet = self.0.allocate_send_packet(buf.len() as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(buf);
|
||||
self.0.send_packet(packet);
|
||||
return Ok(());
|
||||
}
|
||||
pub fn change_ip(
|
||||
&self,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
old_netmask: Ipv4Addr,
|
||||
old_gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
if let Err(e) =
|
||||
self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
|
||||
{
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
self.0.set_ip(address, netmask)?;
|
||||
self.0.add_route(dest(gateway, netmask), netmask, gateway)
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
self.0.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
|
||||
let ip = ip.octets();
|
||||
let mask = mask.octets();
|
||||
Ipv4Addr::from([
|
||||
ip[0] & mask[0],
|
||||
ip[1] & mask[1],
|
||||
ip[2] & mask[2],
|
||||
ip[3] & mask[3],
|
||||
])
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunReader(Arc<TunDevice>);
|
||||
|
||||
|
||||
impl TunReader {
|
||||
pub fn next(&self) -> io::Result<TunPacket> {
|
||||
self.0.receive_blocking()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips:Vec<(Ipv4Addr,Ipv4Addr)>
|
||||
) -> io::Result<(TunWriter, TunReader)> {
|
||||
unsafe {
|
||||
println!("========TUN网卡配置========");
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::open(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(tun_device) => {
|
||||
let _ = tun_device.delete();
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("wintun.dll not found");
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("wintun.dll not found {:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
let tun_device = match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(_) => {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("{:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("name:{:?}", tun_device.get_name()?);
|
||||
println!("version:{:?}", tun_device.version()?);
|
||||
log::error!("创建tun成功 {:?}",tun_device.get_name()?);
|
||||
tun_device.set_ip(address, netmask)?;
|
||||
tun_device.set_mtu(1420)?;
|
||||
for (address, netmask) in in_ips {
|
||||
tun_device.add_route(address, netmask, gateway)?;
|
||||
}
|
||||
tun_device.add_route(address, netmask, gateway)?;
|
||||
let device = Arc::new(tun_device);
|
||||
println!("========TUN网卡配置========");
|
||||
Ok((
|
||||
TunWriter(device.clone(), Arc::default()),
|
||||
TunReader(device),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_tun() {
|
||||
unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::open(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(tun_device) => {
|
||||
let _ = tun_device.delete();
|
||||
}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,36 +1,38 @@
|
||||
[package]
|
||||
name = "switch-desktop"
|
||||
version = "1.0.4"
|
||||
name = "vnt-cli"
|
||||
version = "1.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
switch = {path="../switch"}
|
||||
mac_address = "1.1.4"
|
||||
clap = { version = "4.0.32", features = ["derive"] }
|
||||
console = "0.15.2"
|
||||
dirs = "4.0.0"
|
||||
log = "0.4.17"
|
||||
log4rs = "1.2.0"
|
||||
vnt = { path = "../vnt", package = "vnt", optional = true }
|
||||
common = { path = "../common" }
|
||||
tokio = { version = "1.28.1", features = ["full"] }
|
||||
chrono = "0.4.23"
|
||||
|
||||
getopts = "0.2.21"
|
||||
console = "0.15.2"
|
||||
os_info = "3.7.0"
|
||||
dirs = "4.0.0"
|
||||
serde = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
serde_json = "1.0.94"
|
||||
crossbeam = "0.8.2"
|
||||
lazy_static = "1.4.0"
|
||||
parking_lot = "0.12.1"
|
||||
log = "0.4.17"
|
||||
[dependencies.uuid]
|
||||
version = "1.4.1"
|
||||
features = [
|
||||
"v4", # Lets you generate random UUIDs
|
||||
]
|
||||
|
||||
fs2 = "0.4.3"
|
||||
|
||||
os_info = "3.5.1"
|
||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
sudo = "0.6.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||
#runas = "0.2.1"
|
||||
windows-service = "0.5.0"
|
||||
|
||||
[features]
|
||||
default = ["normal"]
|
||||
normal = ["vnt"]
|
||||
ring-cipher = ["vnt/ring-cipher"]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
embed-manifest = "1.4.0"
|
||||
@@ -0,0 +1,63 @@
|
||||
## 模块介绍
|
||||
体积小,可以在服务器、路由器等环境使用
|
||||
## 详细参数说明
|
||||
### -k `<token>`
|
||||
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
|
||||
### -n `<name>`
|
||||
设备名称,方便区分不同设备
|
||||
### -d `<id>`
|
||||
设备id,每台设备的唯一标识,注意不要重复
|
||||
### -c
|
||||
关闭控制台交互式命令,后台运行时可以加此参数
|
||||
### -s `<server>`
|
||||
注册和中继服务器地址,注册和转发数据
|
||||
### -e `<addr1,addr2>`
|
||||
探测客户端NAT类型,不同类型有不同的打洞策略
|
||||
### -a
|
||||
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
|
||||
### -i `<in-ip>`、-o `<out-ip>`
|
||||
|
||||
配置点对网(IP代理)时使用,例如A(虚拟ip:10.26.0.2)通过B(虚拟ip:10.26.0.3,本地出口ip:192.168.0.10)访问C(目标网段192.168.0.0/24),
|
||||
|
||||
则在A配置 **-i 192.168.0.0/24,10.26.0.3** ,表示将192.168.0.0/24网段的数据都转发到10.26.0.3节点
|
||||
|
||||
在B配置 **-o 192.168.0.0/24,192.168.0.10** ,表示允许将192.168.0.0/24的数据从网卡192.168.0.10转发出去
|
||||
|
||||
注:-o 可以不配置出口ip,如直接使用 **-o 192.168.0.0/24** , 这将使用默认ip转发
|
||||
|
||||
### -w `<password>`
|
||||
|
||||
提升通信安全性,使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密。使用相同密码的客户端才能通信
|
||||
|
||||
| 密码位数 | 加密算法 |
|
||||
|---------|-------|
|
||||
| 小于8 | AES128-GCM
|
||||
| 大于等于8 | AES256-GCM |
|
||||
|
||||
### -m
|
||||
模拟组播,高频使用组播通信时,可以尝试开启此参数,默认情况下会把组播当作广播发给所有节点
|
||||
|
||||
默认情况(组播当广播发送):稳定性好,使用组播频率低时更省流量
|
||||
|
||||
模拟组播:高频使用组播时防止广播泛洪,客户端和中继服务器会维护组播成员等信息,注意使用此选项时,虚拟网内所有成员都需要开启此选项
|
||||
|
||||
### -u `<mtu>`
|
||||
|
||||
设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值,默认值为1430
|
||||
|
||||
### --tcp
|
||||
和服务端使用tcp通信。有些网络提供商对UDP限制比较大,这个时候可以选择使用TCP模式,提高稳定性。一般来说udp延迟和消耗更低
|
||||
### --ip `<IP>`
|
||||
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
|
||||
### --relay
|
||||
禁用p2p,在网络环境很差时,只使用服务器中转效果可能更好(可以配合--tcp参数一起使用)
|
||||
### --list
|
||||
在后台运行时,查看其他设备列表
|
||||
### --all
|
||||
在后台运行时,查看其他设备完整信息
|
||||
### --info
|
||||
在后台运行时,查看当前设备信息
|
||||
### --route
|
||||
在后台运行时,查看数据转发路径
|
||||
### --stop
|
||||
停止后台运行
|
||||
@@ -0,0 +1,10 @@
|
||||
// use embed_manifest::{embed_manifest, new_manifest};
|
||||
// use embed_manifest::manifest::ExecutionLevel;
|
||||
|
||||
fn main() {
|
||||
////强制用管理员运行貌似体验更差了
|
||||
// if std::env::var_os("CARGO_CFG_WINDOWS").is_some() {
|
||||
// embed_manifest(new_manifest("vnt")
|
||||
// .requested_execution_level(ExecutionLevel::RequireAdministrator)).expect("unable to embed manifest file");
|
||||
// }
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Status};
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Info};
|
||||
|
||||
pub struct CommandClient {
|
||||
udp: UdpSocket,
|
||||
@@ -10,7 +11,17 @@ pub struct CommandClient {
|
||||
|
||||
impl CommandClient {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let port = crate::config::read_command_port()?;
|
||||
let path_buf = crate::app_home()?.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(
|
||||
@@ -50,11 +61,11 @@ impl CommandClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn status(&self) -> io::Result<Status> {
|
||||
self.udp.send(b"status")?;
|
||||
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::<Status>(&buf[..len]) {
|
||||
match serde_json::from_slice::<Info>(&buf[..len]) {
|
||||
Ok(val) => {
|
||||
Ok(val)
|
||||
}
|
||||
@@ -64,7 +75,6 @@ impl CommandClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(unix))]
|
||||
pub fn stop(&self) -> io::Result<String> {
|
||||
self.udp.send(b"stop")?;
|
||||
let mut buf = [0; 10240];
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Status {
|
||||
pub struct Info {
|
||||
pub name: String,
|
||||
pub virtual_ip: String,
|
||||
pub virtual_gateway: String,
|
||||
@@ -0,0 +1,148 @@
|
||||
use std::io;
|
||||
use vnt::core::Vnt;
|
||||
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(vnt: &Vnt) -> Vec<RouteItem> {
|
||||
let route_table = vnt.route_table();
|
||||
let mut route_list = Vec::with_capacity(route_table.len());
|
||||
for (destination, route) in route_table {
|
||||
let next_hop = vnt.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(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
let info = vnt.current_device();
|
||||
let device_list = vnt.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) = vnt.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) = vnt.route(&peer.virtual_ip) {
|
||||
let nat_traversal_type = if route.metric == 1 {
|
||||
"p2p"
|
||||
} else if route.addr == info.connect_server {
|
||||
"server-relay"
|
||||
} else {
|
||||
"client-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(vnt: &Vnt) -> Info {
|
||||
let current_device = vnt.current_device();
|
||||
let nat_info = vnt.nat_info();
|
||||
let name = vnt.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!("{:?}", vnt.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,102 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use tokio::net::UdpSocket;
|
||||
|
||||
use vnt::core::Vnt;
|
||||
|
||||
|
||||
pub struct CommandServer {}
|
||||
|
||||
impl CommandServer {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandServer {
|
||||
pub async fn start(self, vnt: Vnt) -> 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 = crate::app_home()?.join("command-port");
|
||||
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, &vnt) {
|
||||
let _ = udp.send_to(out.as_bytes(), addr).await;
|
||||
if "stopped" == &out {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn command(cmd: &str, vnt: &Vnt) -> io::Result<String> {
|
||||
let out_str = match cmd {
|
||||
"route" => {
|
||||
match serde_json::to_string(&crate::command::command_route(vnt)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"list" => {
|
||||
match serde_json::to_string(&crate::command::command_list(vnt)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"info" => {
|
||||
match serde_json::to_string(&crate::command::command_info(vnt)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"stop" => {
|
||||
vnt.stop()?;
|
||||
"stopped".to_string()
|
||||
}
|
||||
_ => {
|
||||
format!("command '{}' not found. \n Try to enter: 'help'\n", cmd)
|
||||
}
|
||||
};
|
||||
Ok(out_str)
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
use console::{style, Style};
|
||||
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Status};
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Info};
|
||||
|
||||
pub mod table;
|
||||
|
||||
pub fn console_status(status: Status) {
|
||||
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());
|
||||
@@ -0,0 +1,325 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use console::style;
|
||||
use getopts::Options;
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
use common::args_parse::{ips_parse, out_ips_parse};
|
||||
use vnt::core::{Config, VntUtil};
|
||||
use vnt::handle::registration_handler::ReqEnum;
|
||||
|
||||
mod command;
|
||||
mod console_out;
|
||||
mod root_check;
|
||||
|
||||
pub fn app_home() -> io::Result<PathBuf> {
|
||||
let path = dirs::home_dir().ok_or(io::Error::new(io::ErrorKind::Other, "not home"))?.join(".vnt-cli");
|
||||
if !path.exists() {
|
||||
std::fs::create_dir_all(&path)?;
|
||||
}
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
main0().await;
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
async fn main0() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let program = args[0].clone();
|
||||
let mut opts = Options::new();
|
||||
opts.optopt("k", "", &format!("{}", green("必选,使用相同的token,就能组建一个局域网络".to_string())), "<token>");
|
||||
opts.optopt("n", "", "给设备一个名字,默认使用系统版本", "<name>");
|
||||
opts.optopt("d", "", "设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip", "<id>");
|
||||
opts.optflag("c", "", "关闭交互式命令,使用此参数禁用控制台输入");
|
||||
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
|
||||
opts.optopt("e", "", "NAT探测服务器地址,使用逗号分隔", "<addr1,addr2>");
|
||||
opts.optflag("a", "", "使用tap模式,默认使用tun模式");
|
||||
opts.optmulti("i", "", "配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3 \n表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3", "<in-ip>");
|
||||
opts.optmulti("o", "", "配置点对网时使用,-o 192.168.0.0/24 \n表示允许目标为192.168.0.0/24的数据转发出去", "<out-ip>");
|
||||
opts.optopt("w", "", "使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "<password>");
|
||||
opts.optflag("m", "", "模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
|
||||
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
||||
opts.optflag("", "tcp", "和服务端使用tcp通信,默认使用udp,一般来说udp延迟和消耗更低");
|
||||
opts.optopt("", "ip", "指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配", "<IP>");
|
||||
opts.optflag("", "relay", "仅使用服务器转发,不使用p2p,默认情况允许使用p2p");
|
||||
//"后台运行时,查看其他设备列表"
|
||||
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("h") || args.len() == 1 {
|
||||
print_usage(&program, opts);
|
||||
return;
|
||||
}
|
||||
if !root_check::is_app_elevated() {
|
||||
println!("Please run it with administrator or root privileges");
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
sudo::escalate_if_needed().unwrap();
|
||||
return;
|
||||
}
|
||||
if matches.opt_present("list") {
|
||||
command::command(command::CommandEnum::List);
|
||||
return;
|
||||
} else if matches.opt_present("info") {
|
||||
command::command(command::CommandEnum::Info);
|
||||
return;
|
||||
} else if matches.opt_present("stop") {
|
||||
command::command(command::CommandEnum::Stop);
|
||||
return;
|
||||
} else if matches.opt_present("route") {
|
||||
command::command(command::CommandEnum::Route);
|
||||
return;
|
||||
} else if matches.opt_present("all") {
|
||||
command::command(command::CommandEnum::All);
|
||||
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();
|
||||
let device_id = if device_id.is_empty() {
|
||||
if let Some(id) = common::identifier::get_unique_identifier() {
|
||||
id
|
||||
} else {
|
||||
let path_buf = app_home().unwrap().join("device-id");
|
||||
if let Ok(id) = std::fs::read_to_string(path_buf.as_path()) {
|
||||
id
|
||||
} else {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let _ = std::fs::write(path_buf, &id);
|
||||
id
|
||||
}
|
||||
}
|
||||
} 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 = match server_address_str.to_socket_addrs() {
|
||||
Ok(mut addr) => {
|
||||
if let Some(addr) = addr.next() {
|
||||
addr
|
||||
} else {
|
||||
println!("parameter -s error .");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("parameter -s error {}.", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
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);
|
||||
println!("example: -i 192.168.0.0/24,10.26.0.3");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let out_ip = matches.opt_strs("o");
|
||||
let out_ip = match out_ips_parse(&out_ip) {
|
||||
Ok(out_ip) => { out_ip }
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-o {}", e);
|
||||
println!("example: -o 0.0.0.0/0");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let password: Option<String> = matches.opt_get("w").unwrap();
|
||||
let simulate_multicast = matches.opt_present("m");
|
||||
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 virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
|
||||
let virtual_ip = virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect("--ip error"));
|
||||
if let Some(virtual_ip) = virtual_ip {
|
||||
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast() {
|
||||
println!("--ip invalid");
|
||||
return;
|
||||
}
|
||||
}
|
||||
let tcp_channel = matches.opt_present("tcp");
|
||||
let relay = matches.opt_present("relay");
|
||||
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, tcp_channel, virtual_ip, relay);
|
||||
let mut vnt_util = VntUtil::new(config).await.unwrap();
|
||||
let response = loop {
|
||||
match vnt_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);
|
||||
continue;
|
||||
}
|
||||
ReqEnum::Other(str) => {
|
||||
println!("error:{}", str);
|
||||
continue;
|
||||
}
|
||||
ReqEnum::IpAlreadyExists => {
|
||||
println!("ip already exists");
|
||||
}
|
||||
ReqEnum::InvalidIp => {
|
||||
println!("invalid ip");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
println!(" ====== Connect Successfully ====== ");
|
||||
println!("virtual_gateway:{}", response.virtual_gateway);
|
||||
println!("virtual_ip:{}", green(response.virtual_ip.to_string()));
|
||||
let driver_info = vnt_util.create_iface().unwrap();
|
||||
println!(" ====== Create Network Interface Successfully ====== ");
|
||||
println!("name:{}", driver_info.name);
|
||||
println!("version:{}", driver_info.version);
|
||||
let mut vnt = match vnt_util.build().await {
|
||||
Ok(vnt) => {
|
||||
vnt
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error:{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
println!(" ====== Start Successfully ====== ");
|
||||
let vnt_c = vnt.clone();
|
||||
tokio::spawn(async {
|
||||
if let Err(e) = command::server::CommandServer::new().start(vnt_c).await {
|
||||
println!("command error :{}", e);
|
||||
}
|
||||
});
|
||||
if !unused_cmd {
|
||||
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! {
|
||||
_ = vnt.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(&vnt);
|
||||
console_out::console_device_list(list);
|
||||
}
|
||||
"info"=>{
|
||||
let info = command::command_info(&vnt);
|
||||
console_out::console_info(info);
|
||||
}
|
||||
"route" =>{
|
||||
let route = command::command_route(&vnt);
|
||||
console_out::console_route_table(route);
|
||||
}
|
||||
"all" =>{
|
||||
let list = command::command_list(&vnt);
|
||||
console_out::console_device_list_all(list);
|
||||
}
|
||||
"stop" =>{
|
||||
let _ = vnt.stop();
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
Err(e) => {
|
||||
println!("input err:{}",e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vnt.wait_stop().await;
|
||||
}
|
||||
|
||||
fn print_usage(program: &str, opts: Options) {
|
||||
let brief = format!("Usage: {} [options]", program);
|
||||
println!("version:1.1.2");
|
||||
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,11 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::is_app_elevated;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
mod unix;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub use unix::is_app_elevated;
|
||||
@@ -0,0 +1,3 @@
|
||||
pub fn is_app_elevated() -> bool {
|
||||
sudo::RunningAs::Root == sudo::check()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "vnt-jni"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vnt = {path="../vnt"}
|
||||
|
||||
jni = { version = "0.21.1", default-features = false }
|
||||
[lib]
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
@@ -0,0 +1 @@
|
||||
## 提供给安卓端使用
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod vnt_util;
|
||||
pub mod vnt;
|
||||
@@ -0,0 +1,138 @@
|
||||
use std::ptr;
|
||||
use jni::errors::Error;
|
||||
use jni::JNIEnv;
|
||||
use jni::objects::{JClass, JObject, JValue};
|
||||
use jni::sys::{jboolean, jbyte, jint, jlong, jobject, jobjectArray, jsize};
|
||||
use vnt::channel::Route;
|
||||
use vnt::core::sync::VntSync;
|
||||
use vnt::handle::PeerDeviceInfo;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_stop0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) {
|
||||
let vnt = raw_vnt as *mut VntSync;
|
||||
let _ = (&*vnt).stop();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitStop0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) {
|
||||
let vnt = raw_vnt as *mut VntSync;
|
||||
let _ = (&mut *vnt).wait_stop();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitStopMs0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
ms: jlong,
|
||||
) -> jboolean {
|
||||
let vnt = raw_vnt as *mut VntSync;
|
||||
if (&mut *vnt).wait_stop_ms(ms as _) {
|
||||
jni::sys::JNI_TRUE
|
||||
} else {
|
||||
jni::sys::JNI_FALSE
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) {
|
||||
let vnt = raw_vnt as *mut VntSync;
|
||||
let _ = Box::from_raw(vnt).stop();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) -> jobjectArray {
|
||||
let vnt = raw_vnt as *mut VntSync;
|
||||
let vnt = &mut *vnt;
|
||||
let list = vnt.device_list();
|
||||
|
||||
let arr = match env.new_object_array(
|
||||
list.len() as jsize,
|
||||
"top/wherewego/vnt/jni/PeerDeviceInfo",
|
||||
JObject::null(),
|
||||
) {
|
||||
Ok(arr) => { arr }
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||
.expect("throw");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
for (index, peer) in list.into_iter().enumerate() {
|
||||
let route = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
||||
match route_parse(&mut env, route) {
|
||||
Ok(route) => {
|
||||
JObject::from_raw(route)
|
||||
}
|
||||
Err(_) => {
|
||||
JObject::null()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
JObject::null()
|
||||
};
|
||||
match peer_device_info_parse(&mut env, peer, route) {
|
||||
Ok(peer) => {
|
||||
match env.set_object_array_element(&arr, index as jsize, JObject::from_raw(peer)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||
.expect("throw");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||
.expect("throw");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
arr.as_raw()
|
||||
}
|
||||
|
||||
fn route_parse(env: &mut JNIEnv, route: Route) -> Result<jobject, Error> {
|
||||
let address = route.addr.to_string();
|
||||
let metric = route.metric;
|
||||
let rt = route.rt;
|
||||
let rs = env.new_object(
|
||||
"top/wherewego/vnt/jni/Route",
|
||||
"(Ljava/lang/String;BI)V",
|
||||
&[JValue::Object(&env.new_string(address)?.into()),
|
||||
JValue::Byte(metric as jbyte),
|
||||
JValue::Int(rt as jint)],
|
||||
)?;
|
||||
Ok(rs.as_raw())
|
||||
}
|
||||
|
||||
fn peer_device_info_parse(env: &mut JNIEnv, peer: PeerDeviceInfo, route: JObject) -> Result<jobject, Error> {
|
||||
let virtual_ip = u32::from(peer.virtual_ip);
|
||||
let name = peer.name.to_string();
|
||||
let status = format!("{:?}", peer.status);
|
||||
let rs = env.new_object(
|
||||
"top/wherewego/vnt/jni/PeerDeviceInfo",
|
||||
"(ILjava/lang/String;Ljava/lang/String;Ltop/wherewego/vnt/jni/Route;)V",
|
||||
&[JValue::Int(virtual_ip as jint),
|
||||
JValue::Object(&env.new_string(name)?.into()),
|
||||
JValue::Object(&env.new_string(status)?.into()),
|
||||
JValue::Object(&route)],
|
||||
)?;
|
||||
Ok(rs.as_raw())
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::ptr;
|
||||
|
||||
use jni::errors::Error;
|
||||
use jni::objects::{JClass, JObject, JString, JValue};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use jni::sys::jboolean;
|
||||
use jni::sys::{jint, jlong, jobject};
|
||||
use jni::JNIEnv;
|
||||
use vnt::core::Config;
|
||||
use vnt::core::sync::VntUtilSync;
|
||||
use vnt::handle::registration_handler::{RegResponse, ReqEnum};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use vnt::tun_tap_device::DriverInfo;
|
||||
|
||||
fn to_string_not_null(env: &mut JNIEnv, config: &JObject, name: &'static str) -> Result<String, Error> {
|
||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
||||
if value.is_null() {
|
||||
env.throw_new("Ljava/lang/NullPointerException", name)
|
||||
.expect("throw");
|
||||
return Err(Error::NullPtr(name));
|
||||
}
|
||||
let binding = JString::from(value);
|
||||
let value = env.get_string(binding.as_ref())?;
|
||||
match value.to_str() {
|
||||
Ok(value) => Ok(value.to_string()),
|
||||
Err(_) => {
|
||||
env.throw_new("Ljava/lang/RuntimeException", "not utf-8")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<String>, Error> {
|
||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
||||
if value.is_null() {
|
||||
return Ok(None);
|
||||
}
|
||||
let tmp = JString::from(value);
|
||||
let value = env.get_string(tmp.as_ref())?;
|
||||
match value.to_str() {
|
||||
Ok(value) => Ok(Some(value.to_string())),
|
||||
Err(_) => {
|
||||
env.throw_new("Ljava/lang/RuntimeException", "not utf-8")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<VntUtilSync, Error> {
|
||||
let token = to_string_not_null(env, &config, "token")?;
|
||||
let name = to_string_not_null(env, &config, "name")?;
|
||||
let device_id = to_string_not_null(env, &config, "deviceId")?;
|
||||
let password = to_string(env, &config, "password")?;
|
||||
let server_address_str = to_string_not_null(env, &config, "server")?;
|
||||
let nat_test_server = to_string_not_null(env, &config, "natTestServer")?;
|
||||
let server_address = match server_address_str.to_socket_addrs() {
|
||||
Ok(mut rs) => {
|
||||
if let Some(addr) = rs.next() {
|
||||
addr
|
||||
} else {
|
||||
env.throw_new("Ljava/lang/RuntimeException", "server address err")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("Ljava/lang/RuntimeException", format!("server address {}", e))
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
};
|
||||
let nat_test_server = nat_test_server.split(",").flat_map(|a| a.trim().to_socket_addrs()).flatten()
|
||||
.collect::<Vec<_>>();
|
||||
let config = Config::new(false,
|
||||
token, device_id, name,
|
||||
server_address, server_address_str,
|
||||
nat_test_server, vec![],
|
||||
vec![], password, false, None, false, None, false);
|
||||
match VntUtilSync::new(config) {
|
||||
Ok(vnt_util) => {
|
||||
Ok(vnt_util)
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("Ljava/lang/RuntimeException", format!("vnt start error {}", e))
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_new0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
config: JObject,
|
||||
) -> jlong {
|
||||
match new_sync(&mut env, config) {
|
||||
Ok(vnt_util) => {
|
||||
let ptr = Box::into_raw(Box::new(vnt_util));
|
||||
return ptr as jlong;
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_connect0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
) -> jobject {
|
||||
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
|
||||
match (&mut *raw_vnt_util).connect() {
|
||||
Ok(response) => {
|
||||
match reg_response(&mut env, response) {
|
||||
Ok(res) => {
|
||||
return res;
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw(format!("vnt connect error {}", e)).expect("throw");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
match e {
|
||||
ReqEnum::TokenError => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/TokenErrorException", "TokenError")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::AddressExhausted => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/AddressExhaustedException", "AddressExhausted")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::Timeout => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/TimeoutException", "Timeout")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::ServerError(str) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt connect error {}", str))
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::Other(str) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt connect error {}", str))
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::IpAlreadyExists => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/IpAlreadyExistsException", "IpAlreadyExists")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::InvalidIp => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/InvalidIpException", "InvalidIp")
|
||||
.expect("throw");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_createIface0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
fd: jint,
|
||||
) {
|
||||
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
|
||||
|
||||
(&mut *raw_vnt_util).create_iface(fd as i32);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_createIface0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
) -> jobject {
|
||||
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
|
||||
let rs = (&mut *raw_vnt_util).create_iface();
|
||||
match rs {
|
||||
Ok(driver_info) => {
|
||||
match driver_info_e(&mut env, driver_info) {
|
||||
Ok(res) => {
|
||||
return res;
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw(format!("vnt create iface error {}", e)).expect("throw");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt create iface error {}", e))
|
||||
.expect("throw");
|
||||
}
|
||||
}
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_build0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
) -> jlong {
|
||||
let raw_vnt_util = Box::from_raw(raw_vnt_util as *mut VntUtilSync);
|
||||
match raw_vnt_util.build() {
|
||||
Ok(rs) => {
|
||||
return Box::into_raw(Box::new(rs)) as jlong;
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt start error:{:?}", e))
|
||||
.expect("throw");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn reg_response(env: &mut JNIEnv, response: RegResponse) -> Result<jobject, Error> {
|
||||
let virtual_ip = u32::from(response.virtual_ip);
|
||||
let virtual_gateway = u32::from(response.virtual_gateway);
|
||||
let virtual_netmask = u32::from(response.virtual_netmask);
|
||||
let response = env.new_object(
|
||||
"top/wherewego/vnt/jni/RegResponse",
|
||||
"(III)V",
|
||||
&[JValue::Int(virtual_ip as jint),
|
||||
JValue::Int(virtual_gateway as jint),
|
||||
JValue::Int(virtual_netmask as jint)],
|
||||
)?;
|
||||
Ok(response.into_raw())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn driver_info_e(env: &mut JNIEnv, driver_info: DriverInfo) -> Result<jobject, Error> {
|
||||
let is_tun = driver_info.device_type.is_tun();
|
||||
let name = driver_info.name;
|
||||
let version = driver_info.version;
|
||||
let mac = driver_info.mac.unwrap_or(String::new());
|
||||
let response = env.new_object(
|
||||
"top/wherewego/vnt/jni/DriverInfo",
|
||||
"(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
|
||||
&[JValue::Bool(is_tun as jboolean),
|
||||
JValue::Object(&env.new_string(name)?.into()),
|
||||
JValue::Object(&env.new_string(version)?.into()),
|
||||
JValue::Object(&env.new_string(mac)?.into()), ],
|
||||
)?;
|
||||
Ok(response.into_raw())
|
||||
}
|
||||
@@ -1,35 +1,27 @@
|
||||
[package]
|
||||
name = "switch"
|
||||
version = "1.0.2"
|
||||
name = "vnt"
|
||||
version = "1.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
packet = { path = "./packet" }
|
||||
p2p_channel = { path = "./p2p_channel" }
|
||||
bytes = "1.3.0"
|
||||
log = "0.4.17"
|
||||
libc = "0.2.137"
|
||||
|
||||
dashmap = "5.4.0"
|
||||
crossbeam = "0.8.2"
|
||||
crossbeam-utils = "0.8"
|
||||
crossbeam-skiplist = "0.1"
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
rsa = "0.7.2"
|
||||
rand = "0.8.5"
|
||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||
|
||||
thiserror = "1.0.37"
|
||||
chrono = "0.4.23"
|
||||
#lazy_static = "1.4.0"
|
||||
#moka = "0.9.6"
|
||||
protobuf = "3.2.0"
|
||||
#local-ip-address = "0.4.9"
|
||||
socket2 ={ version = "0.5.2", features = ["all"] }
|
||||
tokio = { version = "1.28.1", features = ["full"] }
|
||||
[target.'cfg(any(unix))'.dependencies]
|
||||
aes-gcm = {version="0.10.2", optional = true}
|
||||
ring = {version="0.16.20", optional = true}
|
||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
tun = { path = "./rust-tun" }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
@@ -40,3 +32,9 @@ libloading = "0.7.4"
|
||||
[build-dependencies]
|
||||
protobuf-codegen = "3.2.0"
|
||||
protoc-bin-vendored = "3.0.0"
|
||||
|
||||
[features]
|
||||
default=["aes-gcm"]
|
||||
ring-cipher=["ring"]
|
||||
|
||||
|
||||
@@ -7,4 +7,3 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
thiserror = "1.0.37"
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::fmt;
|
||||
use std::{fmt, io};
|
||||
|
||||
/// 地址解析协议,由IP地址找到MAC地址
|
||||
/// https://www.ietf.org/rfc/rfc6747.txt
|
||||
@@ -9,7 +9,6 @@ use std::fmt;
|
||||
| 源MAC地址 | 源ip地址 |
|
||||
| 目的MAC地址 | 目的ip地址 |
|
||||
*/
|
||||
use crate::error::*;
|
||||
|
||||
pub struct ArpPacket<B> {
|
||||
buffer: B,
|
||||
@@ -19,9 +18,9 @@ impl<B: AsRef<[u8]>> ArpPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> Result<Self> {
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() != 28 {
|
||||
Err(Error::InvalidPacket)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::fmt;
|
||||
use crate::error::*;
|
||||
use std::{fmt, io};
|
||||
use crate::ethernet::protocol::Protocol;
|
||||
|
||||
/// 以太网帧协议
|
||||
@@ -18,11 +17,11 @@ impl<B: AsRef<[u8]>> EthernetPacket<B> {
|
||||
EthernetPacket { buffer }
|
||||
}
|
||||
|
||||
pub fn new(buffer: B) -> Result<EthernetPacket<B>> {
|
||||
pub fn new(buffer: B) -> io::Result<EthernetPacket<B>> {
|
||||
let packet = EthernetPacket::unchecked(buffer);
|
||||
//头部固定14位
|
||||
if packet.buffer.as_ref().len() < 14 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
|
||||
Ok(packet)
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::fmt;
|
||||
|
||||
use std::{fmt, io};
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
|
||||
use crate::cal_checksum;
|
||||
use crate::error::*;
|
||||
use crate::icmp::{Code, Kind};
|
||||
use crate::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
/// icmp 协议
|
||||
/* https://www.rfc-editor.org/rfc/rfc792
|
||||
0 1 2 3
|
||||
@@ -17,8 +17,6 @@ use crate::error::*;
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
*/
|
||||
use crate::icmp::{Code, Kind};
|
||||
use crate::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
pub struct IcmpPacket<B> {
|
||||
pub buffer: B,
|
||||
@@ -28,9 +26,9 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> Result<Self> {
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
@@ -56,9 +54,7 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
Code::from(self.kind(), self.buffer.as_ref()[1])
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[2..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
@@ -71,12 +67,8 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
| Kind::TimestampReply
|
||||
| Kind::InformationRequest
|
||||
| Kind::InformationReply => {
|
||||
let ide = (&self.buffer.as_ref()[4..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap();
|
||||
let seq = (&self.buffer.as_ref()[6..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap();
|
||||
let ide =u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap());
|
||||
let seq = u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap());
|
||||
HeaderOther::Identifier(ide, seq)
|
||||
}
|
||||
Kind::DestinationUnreachable | Kind::TimeExceeded | Kind::SourceQuench => {
|
||||
@@ -110,6 +102,7 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
},
|
||||
Kind::TimestampRequest | Kind::TimestampReply => {
|
||||
let mut buffer = Cursor::new(self.payload());
|
||||
|
||||
Description::Timestamp(
|
||||
buffer.read_u32::<BigEndian>().unwrap(),
|
||||
buffer.read_u32::<BigEndian>().unwrap(),
|
||||
@@ -128,11 +121,11 @@ impl<B: AsRef<[u8]>> fmt::Debug for IcmpPacket<B> {
|
||||
} else {
|
||||
"icmp::Packet!"
|
||||
})
|
||||
.field("kind", &self.kind())
|
||||
.field("code", &self.code())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
.field("kind", &self.kind())
|
||||
.field("code", &self.code())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::cal_checksum;
|
||||
|
||||
/// igmp v1
|
||||
/* https://datatracker.ietf.org/doc/html/rfc1112
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|Version| Type | Unused | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Group Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
/// v1版本的报文
|
||||
pub struct IgmpV1Packet<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV1Type {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x12
|
||||
ReportV1,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV1Type {
|
||||
fn from(value: u8) -> IgmpV1Type {
|
||||
use self::IgmpV1Type::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x12 => ReportV1,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV1Type {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpV1Type::Query => 0x11,
|
||||
IgmpV1Type::ReportV1 => 0x12,
|
||||
IgmpV1Type::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV1Packet<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() != 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV1Packet<B> {
|
||||
pub fn version(&self) -> u8 {
|
||||
self.buffer.as_ref()[0] >> 4
|
||||
}
|
||||
pub fn igmp_type(&self) -> IgmpV1Type {
|
||||
IgmpV1Type::from(self.buffer.as_ref()[0] & 0x0F)
|
||||
}
|
||||
pub fn unused(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn group_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV1Packet<B> {
|
||||
pub fn set_version(&mut self, version: u8) {
|
||||
self.buffer.as_mut()[0] = (version << 4) | 0x0F & self.buffer.as_mut()[0]
|
||||
}
|
||||
pub fn set_type(&mut self, igmp_type: IgmpV1Type) {
|
||||
let t: u8 = igmp_type.into();
|
||||
self.buffer.as_mut()[0] = self.buffer.as_mut()[0] & 0xF0 | t
|
||||
}
|
||||
pub fn set_checksum(&mut self, checksum: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
|
||||
}
|
||||
pub fn update_checksum(&mut self) {
|
||||
self.set_checksum(0);
|
||||
self.set_checksum(cal_checksum(self.buffer.as_ref()));
|
||||
}
|
||||
pub fn set_group_address(&mut self, group_address: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets());
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV1Packet<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V1")
|
||||
.field("version", &self.version())
|
||||
.field("type", &self.igmp_type())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("group_address", &self.group_address())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::cal_checksum;
|
||||
|
||||
/// igmp v2
|
||||
/* https://www.rfc-editor.org/rfc/rfc2236.html
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Max Resp Time | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Group Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
/// v2版本的报文
|
||||
pub struct IgmpV2Packet<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV2Type {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x16
|
||||
ReportV2,
|
||||
LeaveV2,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV2Type {
|
||||
fn from(value: u8) -> IgmpV2Type {
|
||||
use self::IgmpV2Type::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x16 => ReportV2,
|
||||
0x17 => LeaveV2,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV2Type {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpV2Type::Query => 0x11,
|
||||
IgmpV2Type::ReportV2 => 0x16,
|
||||
IgmpV2Type::LeaveV2 => 0x17,
|
||||
IgmpV2Type::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV2Packet<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() != 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV2Packet<B> {
|
||||
pub fn igmp_type(&self) -> IgmpV2Type {
|
||||
IgmpV2Type::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn max_resp_time(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn group_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV2Packet<B> {
|
||||
pub fn set_type(&mut self, igmp_type: IgmpV2Type) {
|
||||
self.buffer.as_mut()[0] = igmp_type.into()
|
||||
}
|
||||
pub fn set_max_resp_time(&mut self, resp: u8) {
|
||||
self.buffer.as_mut()[1] = resp
|
||||
}
|
||||
pub fn set_checksum(&mut self, checksum: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
|
||||
}
|
||||
pub fn update_checksum(&mut self) {
|
||||
self.set_checksum(0);
|
||||
self.set_checksum(cal_checksum(self.buffer.as_ref()));
|
||||
}
|
||||
pub fn set_group_address(&mut self, group_address: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets());
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV2Packet<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V2")
|
||||
.field("type", &self.igmp_type())
|
||||
.field("max_resp_time", &self.max_resp_time())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("group_address", &self.group_address())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::cal_checksum;
|
||||
|
||||
/// igmp v3
|
||||
/* https://www.rfc-editor.org/rfc/rfc3376
|
||||
Query:
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 0x11 | Max Resp Code | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Group Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Resv |S| QRV | QQIC | Number of Sources (N) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source Address [1] |
|
||||
+- -+
|
||||
| Source Address [2] |
|
||||
+- . -+
|
||||
. . .
|
||||
. . .
|
||||
+- -+
|
||||
| Source Address [N] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Report:
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 0x22 | Reserved | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Reserved | Number of Group Records (M) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Group Record [1] .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Group Record [2] .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| . |
|
||||
. . .
|
||||
| . |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Group Record [M] .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Group Record:
|
||||
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Record Type | Aux Data Len | Number of Sources (N) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Multicast Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source Address [1] |
|
||||
+- -+
|
||||
| Source Address [2] |
|
||||
+- -+
|
||||
. . .
|
||||
. . .
|
||||
. . .
|
||||
+- -+
|
||||
| Source Address [N] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Auxiliary Data .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Record Type:
|
||||
1 MODE_IS_INCLUDE 表示主机希望加入指定组播组并指定了一个或多个源地址
|
||||
2 MODE_IS_EXCLUDE 表示主机希望加入指定组播组但排除了一个或多个源地址
|
||||
3 CHANGE_TO_INCLUDE_MODE 表示主机正在将组播组的过滤模式从排除切换为包括,指定了一个或多个源地址
|
||||
4 CHANGE_TO_EXCLUDE_MODE 表示主机正在将组播组的过滤模式从包括切换为排除,指定了一个或多个源地址
|
||||
5 ALLOW_NEW_SOURCES 表示主机希望在已有的源地址列表中添加新的源地址,指定了一个或多个源地址
|
||||
6 BLOCK_OLD_SOURCES 表示主机希望在已有的源地址列表中删除旧的源地址,指定了一个或多个源地址
|
||||
*/
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV3Type {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x22
|
||||
ReportV3,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV3Type {
|
||||
fn from(value: u8) -> IgmpV3Type {
|
||||
use self::IgmpV3Type::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x22 => ReportV3,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV3Type {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpV3Type::Query => 0x11,
|
||||
IgmpV3Type::ReportV3 => 0x22,
|
||||
IgmpV3Type::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV3RecordType {
|
||||
//1 MODE_IS_INCLUDE 表示主机希望加入指定组播组并指定了一个或多个源地址
|
||||
ModeIsInclude,
|
||||
//2 MODE_IS_EXCLUDE 表示主机希望加入指定组播组但排除了一个或多个源地址
|
||||
ModeIsExclude,
|
||||
//3 CHANGE_TO_INCLUDE_MODE 表示主机正在将组播组的过滤模式从排除切换为包括,指定了一个或多个源地址
|
||||
ChangeToIncludeMode,
|
||||
//4 CHANGE_TO_EXCLUDE_MODE 表示主机正在将组播组的过滤模式从包括切换为排除,指定了一个或多个源地址
|
||||
ChangeToExcludeMode,
|
||||
//5 ALLOW_NEW_SOURCES 表示主机希望在已有的源地址列表中添加新的源地址,指定了一个或多个源地址
|
||||
AllowNewSources,
|
||||
//6 BLOCK_OLD_SOURCES 表示主机希望在已有的源地址列表中删除旧的源地址,指定了一个或多个源地址
|
||||
BlockOldSources,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV3RecordType {
|
||||
fn from(value: u8) -> IgmpV3RecordType {
|
||||
use self::IgmpV3RecordType::*;
|
||||
|
||||
match value {
|
||||
1 => ModeIsInclude,
|
||||
2 => ModeIsExclude,
|
||||
3 => ChangeToIncludeMode,
|
||||
4 => ChangeToExcludeMode,
|
||||
5 => AllowNewSources,
|
||||
6 => BlockOldSources,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV3RecordType {
|
||||
fn into(self) -> u8 {
|
||||
use self::IgmpV3RecordType::*;
|
||||
|
||||
match self {
|
||||
ModeIsInclude => 1,
|
||||
ModeIsExclude => 2,
|
||||
ChangeToIncludeMode => 3,
|
||||
ChangeToExcludeMode => 4,
|
||||
AllowNewSources => 5,
|
||||
BlockOldSources => 6,
|
||||
Unknown(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// v3版本的query报文
|
||||
pub struct IgmpV3QueryPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3QueryPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 12 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV3QueryPacket<B> {
|
||||
pub fn set_igmp_type(&mut self) {
|
||||
self.buffer.as_mut()[0] = IgmpV3Type::Query.into();
|
||||
}
|
||||
pub fn set_max_resp_code(&mut self, code: u8) {
|
||||
self.buffer.as_mut()[1] = code;
|
||||
}
|
||||
pub fn set_group_address(&mut self, addr: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&addr.octets())
|
||||
}
|
||||
pub fn set_checksum(&mut self, checksum: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes())
|
||||
}
|
||||
pub fn set_qrv(&mut self, qrv: u8) {
|
||||
self.buffer.as_mut()[8] = (self.buffer.as_ref()[8]&(!0x07)) | (qrv & 0x07)
|
||||
}
|
||||
pub fn set_qqic(&mut self, qqic: u8) {
|
||||
self.buffer.as_mut()[9] = qqic
|
||||
}
|
||||
|
||||
pub fn update_checksum(&mut self) {
|
||||
self.set_checksum(0);
|
||||
let checksum = cal_checksum(self.buffer.as_ref());
|
||||
self.set_checksum(checksum);
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3QueryPacket<B> {
|
||||
pub fn igmp_type(&self) -> IgmpV3Type {
|
||||
IgmpV3Type::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn max_resp_code(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn group_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
/// 保留字段,设置为0
|
||||
pub fn resv(&self) -> u8 {
|
||||
self.buffer.as_ref()[8] >> 4
|
||||
}
|
||||
/// 标志位
|
||||
/// 该比特位为1时,所有收到此查询报文的其他路由器不启动定时器刷新过程,但是此查询报文并不抑制查询者选举过程和路由器的主机侧处理过程;默认未置位。
|
||||
pub fn s(&self) -> u8 {
|
||||
(self.buffer.as_ref()[8] & 0x0F) >> 3
|
||||
}
|
||||
/// 查询者向网络通告的健壮系数
|
||||
/// 此参数可使查询者使用自己的健壮系统同步其他组播路由器的健壮系数;
|
||||
/// 其他路由器接收到查询报文时,如果发现该字段非0,则将自己的健壮系数调整为该字段的值;如果发现该字段为0,则不做处理。默认健壮系数值为2。
|
||||
pub fn qrv(&self) -> u8 {
|
||||
self.buffer.as_ref()[8] & 0x07
|
||||
}
|
||||
/// IGMP查询者的查询间隔
|
||||
/// 非查询者收到查询报文时,如果发现该字段非0,则将自己的查询间隔参数调整为该字段的值:如果发现该字段为0,则不做处理。默认值为60。
|
||||
pub fn qqic(&self) -> u8 {
|
||||
self.buffer.as_ref()[9]
|
||||
}
|
||||
/// 报文中包含的组播源的数量
|
||||
/// 对于普遍组查询报文和特定组查询报文,该字段为0;对于特定源组查询报文,该字段非0
|
||||
pub fn source_number(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[10..12].try_into().unwrap())
|
||||
}
|
||||
pub fn source_addresses(&self) -> Option<Vec<Ipv4Addr>> {
|
||||
let num = self.source_number();
|
||||
if num == 0 {
|
||||
None
|
||||
} else {
|
||||
let num = num as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
for index in 0..num {
|
||||
let start = (12 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
|
||||
list.push(Ipv4Addr::from(tmp));
|
||||
}
|
||||
Some(list)
|
||||
}
|
||||
}
|
||||
pub fn source_address(&self, index: u16) -> Option<Ipv4Addr> {
|
||||
if self.source_number() >= index {
|
||||
None
|
||||
} else {
|
||||
let start = (12 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
|
||||
Some(Ipv4Addr::from(tmp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// v3版本的query报文
|
||||
pub struct IgmpV3ReportPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3ReportPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3ReportPacket<B> {
|
||||
pub fn igmp_type(&self) -> IgmpV3Type {
|
||||
IgmpV3Type::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn reserved1(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn reserved2(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||
}
|
||||
pub fn record_number(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
|
||||
}
|
||||
pub fn group_records(&self) -> Option<Vec<IgmpV3RecordPacket<&[u8]>>> {
|
||||
let num = self.record_number();
|
||||
if num == 0 {
|
||||
None
|
||||
} else {
|
||||
let num = num as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let mut start = 8 as usize;
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
for _ in 0..num {
|
||||
if start >= len {
|
||||
return None;
|
||||
}
|
||||
if let Ok(record) = IgmpV3RecordPacket::new(&buf[start..]) {
|
||||
let end = start + 8 + record.aux_data_len() as usize * 4 + record.source_number() as usize * 4;
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
list.push(IgmpV3RecordPacket::new(&buf[start..end]).unwrap());
|
||||
start = end;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// group record
|
||||
pub struct IgmpV3RecordPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3RecordPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3RecordPacket<B> {
|
||||
pub fn record_type(&self) -> IgmpV3RecordType {
|
||||
IgmpV3RecordType::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
/// 辅助数据长度 以4字节为单位
|
||||
pub fn aux_data_len(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
/// 源地址数
|
||||
pub fn source_number(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
///多播地址
|
||||
pub fn multicast_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn source_addresses(&self) -> Option<Vec<Ipv4Addr>> {
|
||||
let num = self.source_number();
|
||||
if num == 0 {
|
||||
None
|
||||
} else {
|
||||
let num = num as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
for index in 0..num {
|
||||
let start = (8 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
|
||||
list.push(Ipv4Addr::from(tmp));
|
||||
}
|
||||
Some(list)
|
||||
}
|
||||
}
|
||||
pub fn source_address(&self, index: u16) -> Option<Ipv4Addr> {
|
||||
if self.source_number() >= index {
|
||||
None
|
||||
} else {
|
||||
let start = (8 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
if end > self.buffer.as_ref().len() {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[start..end].try_into().unwrap();
|
||||
Some(Ipv4Addr::from(tmp))
|
||||
}
|
||||
}
|
||||
/// 在文档中没有定义辅助数据的作用,通常应该是空的
|
||||
pub fn auxiliary_data(&self) -> &[u8] {
|
||||
let start = 8 + self.source_number() as usize * 4;
|
||||
let end = start + self.aux_data_len() as usize * 4;
|
||||
if end > self.buffer.as_ref().len() {
|
||||
return &[];
|
||||
}
|
||||
&self.buffer.as_ref()[start..end]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3QueryPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V3Query")
|
||||
.field("type", &self.igmp_type())
|
||||
.field("max_resp_code", &self.max_resp_code())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("group_address", &self.group_address())
|
||||
.field("s", &self.s())
|
||||
.field("qrv", &self.qrv())
|
||||
.field("qqic", &self.qqic())
|
||||
.field("number of sources", &self.source_number())
|
||||
.field("source_addresses", &self.source_addresses())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3ReportPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V3Report")
|
||||
.field("type", &self.igmp_type())
|
||||
.field("reserved1", &self.reserved1())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("reserved2", &self.reserved2())
|
||||
.field("record_number", &self.record_number())
|
||||
.field("group_records", &self.group_records())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3RecordPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V3Record")
|
||||
.field("record_type", &self.record_type())
|
||||
.field("aux_data_len", &self.aux_data_len())
|
||||
.field("source_number", &self.source_number())
|
||||
.field("multicast_address", &self.multicast_address())
|
||||
.field("source_addresses", &self.source_addresses())
|
||||
.field("auxiliary_data", &self.auxiliary_data())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
pub mod igmp_v1;
|
||||
pub mod igmp_v2;
|
||||
pub mod igmp_v3;
|
||||
|
||||
#[derive(Debug,Copy, Clone,Eq, PartialEq)]
|
||||
pub enum IgmpType {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x12
|
||||
ReportV1,
|
||||
/// 0x16
|
||||
ReportV2,
|
||||
/// 0x22
|
||||
ReportV3,
|
||||
/// 0x17 目标组固定是 224.0.0.2
|
||||
LeaveV2,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpType {
|
||||
fn from(value: u8) -> IgmpType {
|
||||
use self::IgmpType::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x12 => ReportV1,
|
||||
0x16 => ReportV2,
|
||||
0x22 => ReportV3,
|
||||
0x17 => LeaveV2,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpType {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpType::Query => 0x11,
|
||||
IgmpType::ReportV1 => 0x12,
|
||||
IgmpType::ReportV2 => 0x16,
|
||||
IgmpType::ReportV3 => 0x22,
|
||||
IgmpType::LeaveV2 => 0x17,
|
||||
IgmpType::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
use std::fmt;
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
|
||||
use crate::cal_checksum;
|
||||
use crate::error::*;
|
||||
use crate::ip::ipv4::protocol::Protocol;
|
||||
|
||||
/// ip协议
|
||||
@@ -38,16 +37,16 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> Result<Self> {
|
||||
if buffer.as_ref()[0] >> 4 != 4 {
|
||||
Err(Error::Unimplemented)?
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 20 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "len < 20"))?;
|
||||
}
|
||||
if buffer.as_ref()[0] >> 4 != 4 {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "not ipv4"))?;
|
||||
}
|
||||
let packet = Self::unchecked(buffer);
|
||||
if packet.buffer.as_ref().len() < packet.header_len() as usize * 4 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "head_len err"))?;
|
||||
}
|
||||
Ok(packet)
|
||||
}
|
||||
@@ -59,17 +58,6 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[(self.header_len() as usize * 4)..]
|
||||
// match self.protocol() {
|
||||
// Protocol::Udp => {
|
||||
// let udp = UdpPacket::new(IpAddr::V4(self.source_ip()),
|
||||
// IpAddr::V4(self.destination_ip()),
|
||||
// &self.buffer.as_ref()[(self.header_len() as usize * 4)..])?;
|
||||
// Ok(crate::IpUpperLayer::UDP(udp))
|
||||
// }
|
||||
// _ => {
|
||||
// Ok(crate::IpUpperLayer::Unknown(self.buffer.as_ref()));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,13 +70,18 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> IpV4Packet<B> {
|
||||
let len = self.header_len() as usize * 4;
|
||||
&mut self.buffer.as_mut()[len..]
|
||||
}
|
||||
|
||||
pub fn set_protocol(&mut self, value: Protocol) {
|
||||
self.header_mut()[9] = value.into();
|
||||
}
|
||||
pub fn set_source_ip(&mut self, value: Ipv4Addr) {
|
||||
self.header_mut()[12..16].copy_from_slice(&value.octets());
|
||||
}
|
||||
pub fn set_destination_ip(&mut self, value: Ipv4Addr) {
|
||||
self.header_mut()[16..20].copy_from_slice(&value.octets());
|
||||
}
|
||||
pub fn set_flags(&mut self, flags: u8) {
|
||||
self.buffer.as_mut()[6] = (self.buffer.as_ref()[6] & 0b11100000) | (flags << 5)
|
||||
}
|
||||
fn set_checksum(&mut self, value: u16) {
|
||||
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::io;
|
||||
use ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
pub mod ipv4;
|
||||
|
||||
pub enum IpPacket<B> {
|
||||
@@ -9,10 +8,10 @@ pub enum IpPacket<B> {
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IpPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<Self> {
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
match buffer.as_ref()[0] >> 4 {
|
||||
4 => Ok(IpPacket::V4(IpV4Packet::new(buffer)?)),
|
||||
_ => Err(Error::InvalidPacket),
|
||||
_ => Err(io::Error::from(io::ErrorKind::InvalidData)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ use std::net::Ipv4Addr;
|
||||
use byteorder::BigEndian;
|
||||
use byteorder::ReadBytesExt;
|
||||
|
||||
pub mod error;
|
||||
pub mod icmp;
|
||||
pub mod igmp;
|
||||
pub mod ip;
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
@@ -103,9 +103,9 @@ pub fn ipv4_cal_checksum(
|
||||
src_ip: &Ipv4Addr,
|
||||
dest_ip: &Ipv4Addr,
|
||||
protocol: u8,
|
||||
length: u16,
|
||||
) -> u16 {
|
||||
use std::io::Cursor;
|
||||
let length = buffer.len();
|
||||
let mut sum = 0;
|
||||
let src_ip = src_ip.octets();
|
||||
sum += u32c(src_ip[0], src_ip[1]);
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::tcp::Flags;
|
||||
|
||||
/// tcp
|
||||
@@ -59,15 +58,15 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||
buffer,
|
||||
}
|
||||
}
|
||||
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> Result<TcpPacket<B>> {
|
||||
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> io::Result<TcpPacket<B>> {
|
||||
let packet = TcpPacket::unchecked(source_ip, destination_ip, buffer);
|
||||
|
||||
if packet.buffer.as_ref().len() < 20 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
|
||||
if packet.buffer.as_ref().len() < packet.data_offset() as usize * 4 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
|
||||
Ok(packet)
|
||||
@@ -135,7 +134,6 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||
&self.source_ip,
|
||||
&self.destination_ip,
|
||||
6,
|
||||
self.buffer.as_ref().len() as u16,
|
||||
)
|
||||
}
|
||||
pub fn urgent_pointer(&self) -> u16 {
|
||||
@@ -1,8 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
/// udp协议
|
||||
///
|
||||
/*
|
||||
@@ -62,9 +60,9 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||
buffer,
|
||||
}
|
||||
}
|
||||
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> Result<UdpPacket<B>> {
|
||||
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> io::Result<UdpPacket<B>> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
let packet = Self::unchecked(source_ip, destination_ip, buffer);
|
||||
Ok(packet)
|
||||
@@ -104,16 +102,15 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||
&self.source_ip,
|
||||
&self.destination_ip,
|
||||
17,
|
||||
self.length(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||
fn header_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[..8]
|
||||
}
|
||||
}
|
||||
// impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||
// fn header_mut(&mut self) -> &mut [u8] {
|
||||
// &mut self.buffer.as_mut()[..8]
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||
/// 设置源端口
|
||||
@@ -4,6 +4,9 @@ message RegistrationRequest{
|
||||
string device_id = 2;
|
||||
string name = 3;
|
||||
bool is_fast = 4;
|
||||
string version = 5;
|
||||
fixed32 virtual_ip = 6;
|
||||
bool allow_ip_change = 7;
|
||||
}
|
||||
|
||||
message RegistrationResponse{
|
||||
@@ -14,6 +17,7 @@ message RegistrationResponse{
|
||||
repeated DeviceInfo device_info_list = 5;
|
||||
fixed32 public_ip = 6;
|
||||
uint32 public_port = 7;
|
||||
bytes public_ipv6 = 8;
|
||||
}
|
||||
message DeviceInfo{
|
||||
string name = 1;
|
||||
@@ -34,6 +38,7 @@ message PunchInfo{
|
||||
bool reply = 6;
|
||||
fixed32 local_ip = 7;
|
||||
uint32 local_port = 8;
|
||||
repeated bytes public_ipv6_list = 9;
|
||||
}
|
||||
enum PunchNatType{
|
||||
Symmetric = 0;
|
||||
@@ -27,15 +27,6 @@ pub mod macos;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use self::macos::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
pub mod ios;
|
||||
#[cfg(target_os = "ios")]
|
||||
pub use self::ios::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod android;
|
||||
#[cfg(target_os = "android")]
|
||||
pub use self::android::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
@@ -0,0 +1,542 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
use tokio::net::tcp::OwnedReadHalf;
|
||||
use tokio::sync::watch::{channel, Receiver, Sender};
|
||||
use crate::channel::{Route, RouteKey, Status};
|
||||
use crate::channel::punch::NatType;
|
||||
use crate::core::status::VntWorker;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::handle::recv_handler::ChannelDataHandler;
|
||||
|
||||
pub struct ContextInner {
|
||||
pub(crate) lock: Mutex<()>,
|
||||
//udp用于打洞、服务端通信(可选)
|
||||
pub(crate) main_channel: Arc<UdpSocket>,
|
||||
//在udp的基础上,可以选择使用tcp和服务端通信
|
||||
pub(crate) main_tcp_channel: Option<tokio::sync::mpsc::Sender<Vec<u8>>>,
|
||||
pub(crate) route_table: SkipMap<Ipv4Addr, Vec<Route>>,
|
||||
pub(crate) route_table_time: SkipMap<(RouteKey, Ipv4Addr), AtomicCell<Instant>>,
|
||||
pub(crate) status_receiver: Receiver<Status>,
|
||||
pub(crate) status_sender: Sender<Status>,
|
||||
pub(crate) udp_map: SkipMap<usize, Arc<UdpSocket>>,
|
||||
pub(crate) channel_num: usize,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
pub(crate) inner: Arc<ContextInner>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(main_channel: Arc<UdpSocket>, main_tcp_channel: Option<tokio::sync::mpsc::Sender<Vec<u8>>>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>, _channel_num: usize) -> Self {
|
||||
//当前版本只支持一个通道
|
||||
let channel_num = 1;
|
||||
let (status_sender, status_receiver) = channel(Status::Cone);
|
||||
let inner = Arc::new(ContextInner {
|
||||
lock: Mutex::new(()),
|
||||
main_channel,
|
||||
main_tcp_channel,
|
||||
route_table: SkipMap::new(),
|
||||
route_table_time: SkipMap::new(),
|
||||
status_receiver,
|
||||
status_sender,
|
||||
udp_map: SkipMap::new(),
|
||||
channel_num,
|
||||
current_device,
|
||||
});
|
||||
Self {
|
||||
inner
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn is_close(&self) -> bool {
|
||||
*self.inner.status_receiver.borrow() == Status::Close
|
||||
}
|
||||
pub fn is_cone(&self) -> bool {
|
||||
*self.inner.status_receiver.borrow() == Status::Cone
|
||||
}
|
||||
pub fn close(&self) {
|
||||
let _ = self.inner.status_sender.send(Status::Close);
|
||||
}
|
||||
pub fn switch(&self, nat_type: NatType) {
|
||||
match nat_type {
|
||||
NatType::Symmetric => {
|
||||
self.switch_to_symmetric();
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.switch_to_cone();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn switch_to_cone(&self) {
|
||||
let _ = self.inner.status_sender.send(Status::Cone);
|
||||
}
|
||||
pub fn switch_to_symmetric(&self) {
|
||||
let _ = self.inner.status_sender.send(Status::Symmetric);
|
||||
}
|
||||
pub fn main_local_port(&self) -> io::Result<u16> {
|
||||
self.inner.main_channel.local_addr().map(|k| k.port())
|
||||
}
|
||||
pub async fn send_main_udp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
|
||||
self.inner.main_channel.send_to(buf, addr).await
|
||||
}
|
||||
pub async fn send_main(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
vec[4..].copy_from_slice(buf);
|
||||
if sender.send(vec).await.is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "send_main err"))
|
||||
}
|
||||
} else {
|
||||
self.inner.main_channel.send_to(buf, addr).await
|
||||
}
|
||||
}
|
||||
pub fn try_send_main(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
vec[4..].copy_from_slice(buf);
|
||||
if sender.try_send(vec).is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "try_send_main err"))
|
||||
}
|
||||
} else {
|
||||
self.inner.main_channel.try_send_to(buf, addr)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn send_all(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
|
||||
for udp in self.inner.udp_map.iter() {
|
||||
udp.value().send_to(buf, addr).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<usize> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
if v.value().is_empty() {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "route not found"));
|
||||
}
|
||||
let route = v.value()[0];
|
||||
drop(v);
|
||||
if !route.is_p2p() {
|
||||
if let Some(time) = self.inner.route_table_time.get(&(route.route_key(), *id)) {
|
||||
//借道传输时,长时间不通信的通道不使用
|
||||
if time.value().load().elapsed() > Duration::from_secs(3) {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "route time out"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(udp) = self.inner.udp_map.get(&route.index) {
|
||||
return udp.value().send_to(buf, route.addr).await;
|
||||
}
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
|
||||
pub fn try_send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<usize> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
if v.value().is_empty() {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "route not found"));
|
||||
}
|
||||
let route = v.value()[0];
|
||||
drop(v);
|
||||
if let Some(udp) = self.inner.udp_map.get(&route.index) {
|
||||
return udp.value().try_send_to(buf, route.addr);
|
||||
}
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
pub async fn send_by_key(&self, buf: &[u8], route_key: &RouteKey) -> io::Result<usize> {
|
||||
if route_key.index == 0 {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
vec[4..].copy_from_slice(buf);
|
||||
return if sender.send(vec).await.is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "send_by_key err"))
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Some(udp) = self.inner.udp_map.get(&route_key.index) {
|
||||
return udp.value().send_to(buf, route_key.addr).await;
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
pub fn try_send_by_key(&self, buf: &[u8], route_key: &RouteKey) -> io::Result<usize> {
|
||||
if route_key.index == 0 {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
vec[4..].copy_from_slice(buf);
|
||||
return if sender.try_send(vec).is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "try_send_by_key err"))
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Some(udp) = self.inner.udp_map.get(&route_key.index) {
|
||||
return udp.value().try_send_to(buf, route_key.addr);
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) {
|
||||
self.add_route_(id, route, true)
|
||||
}
|
||||
pub fn add_route(&self, id: Ipv4Addr, route: Route) {
|
||||
self.add_route_(id, route, false)
|
||||
}
|
||||
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) {
|
||||
let key = route.route_key();
|
||||
let guard = self.inner.lock.lock();
|
||||
let mut list = if let Some(entry) = self.inner.route_table.get(&id) {
|
||||
entry.value().clone()
|
||||
} else {
|
||||
Vec::with_capacity(4)
|
||||
};
|
||||
let mut exist = false;
|
||||
for x in list.iter_mut() {
|
||||
if x.metric < route.metric {
|
||||
//不能比当前的路径更长
|
||||
return;
|
||||
}
|
||||
if x.route_key() == key {
|
||||
if only_if_absent {
|
||||
return;
|
||||
}
|
||||
x.metric = route.metric;
|
||||
x.rt = route.rt;
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if exist {
|
||||
list.sort_by_key(|k| k.sort_key());
|
||||
} else {
|
||||
if route.metric == 1 {
|
||||
//添加了直连的则排除非直连的
|
||||
list.retain(|k| k.metric == 1);
|
||||
}
|
||||
list.push(route);
|
||||
list.sort_by_key(|k| k.sort_key());
|
||||
let max_len = self.inner.channel_num + 1;
|
||||
if list.len() > max_len {
|
||||
list.truncate(max_len);
|
||||
}
|
||||
}
|
||||
self.inner.route_table.insert(id, list);
|
||||
self.inner.route_table_time.insert((key, id), AtomicCell::new(Instant::now()));
|
||||
drop(guard);
|
||||
}
|
||||
pub fn route(&self, id: &Ipv4Addr) -> Option<Vec<Route>> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
Some(v.value().clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn route_one(&self, id: &Ipv4Addr) -> Option<Route> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
v.value().iter().max_by_key(|k| k.sort_key()).map(|k| *k)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn route_to_id(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
|
||||
for x in self.inner.route_table.iter() {
|
||||
for route in x.value() {
|
||||
if &route.route_key() == route_key && route.is_p2p() {
|
||||
return Some(*x.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn need_punch(&self, id: &Ipv4Addr) -> bool {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
if v.value().iter().filter(|k| k.is_p2p()).count() >= self.inner.channel_num {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
pub fn route_table(&self) -> Vec<(Ipv4Addr, Vec<Route>)> {
|
||||
self.inner.route_table.iter().map(|k| (k.key().clone(), k.value().clone())).collect()
|
||||
}
|
||||
pub fn route_table_one(&self) -> Vec<(Ipv4Addr, Route)> {
|
||||
let mut v = Vec::with_capacity(8);
|
||||
for x in self.inner.route_table.iter() {
|
||||
if let Some(route) = x.value().first() {
|
||||
v.push((*x.key(), *route));
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
pub fn direct_route_table_one(&self) -> Vec<(Ipv4Addr, Route)> {
|
||||
let mut v = Vec::with_capacity(8);
|
||||
for x in self.inner.route_table.iter() {
|
||||
if let Some(route) = x.value().first() {
|
||||
if route.metric == 1 {
|
||||
v.push((*x.key(), *route));
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
pub fn remove_route_all(&self, id: &Ipv4Addr) {
|
||||
let guard = self.inner.lock.lock();
|
||||
if let Some(v) = self.inner.route_table.remove(id) {
|
||||
for x in v.value() {
|
||||
self.inner.route_table_time.remove(&(x.route_key(), *id));
|
||||
}
|
||||
}
|
||||
drop(guard);
|
||||
}
|
||||
pub fn remove_route(&self, id: &Ipv4Addr, route_key: RouteKey) {
|
||||
let guard = self.inner.lock.lock();
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
let mut routes = v.value().clone();
|
||||
drop(v);
|
||||
routes.retain(|x| x.route_key() != route_key);
|
||||
self.inner.route_table.insert(*id, routes);
|
||||
}
|
||||
self.inner.route_table_time.remove(&(route_key, *id));
|
||||
drop(guard);
|
||||
}
|
||||
pub fn update_read_time(&self, id: &Ipv4Addr, route_key: &RouteKey) {
|
||||
if let Some(time) = self.inner.route_table_time.get(&(*route_key, *id)) {
|
||||
time.value().store(Instant::now());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Channel {
|
||||
context: Context,
|
||||
handler: ChannelDataHandler,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn new(context: Context,
|
||||
handler: ChannelDataHandler, ) -> Self {
|
||||
Self {
|
||||
context,
|
||||
handler,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
async fn handle(handler: &mut ChannelDataHandler,
|
||||
context: &Context,
|
||||
id: usize,
|
||||
result: io::Result<(usize, SocketAddr)>,
|
||||
buf: &mut [u8], start: usize) {
|
||||
match result {
|
||||
Ok((len, addr)) => {
|
||||
handler.handle(buf, start, start + len, RouteKey::new(id, addr), context).await;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e)
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn tcp_handle(mut tcp_r: OwnedReadHalf, context: Context,
|
||||
mut handler: ChannelDataHandler, head_reserve: usize, ) -> io::Result<()> {
|
||||
let mut buf = [0; 4096];
|
||||
let addr = tcp_r.peer_addr()?;
|
||||
let key = RouteKey::new(0, addr);
|
||||
loop {
|
||||
tcp_r.read_exact(&mut buf[head_reserve..head_reserve + 4]).await?;
|
||||
let len = 4 + (((buf[head_reserve + 2] as u16) << 8) | buf[head_reserve + 3] as u16) as usize;
|
||||
tcp_r.read_exact(&mut buf[head_reserve + 4..head_reserve + len]).await?;
|
||||
handler.handle(&mut buf[4..], head_reserve, head_reserve + len - 4, key, &context).await;
|
||||
}
|
||||
}
|
||||
async fn start_tcp(mut worker: VntWorker, tcp_stream: TcpStream, mut receiver: tokio::sync::mpsc::Receiver<Vec<u8>>, context: Context, handler: ChannelDataHandler, head_reserve: usize) {
|
||||
let (tcp_r, mut tcp_w) = tcp_stream.into_split();
|
||||
{
|
||||
let context = context.clone();
|
||||
let handler = handler.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = Self::tcp_handle(tcp_r, context, handler, head_reserve).await {
|
||||
log::info!("tcp链接断开:{:?}",e);
|
||||
}
|
||||
});
|
||||
}
|
||||
loop {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
rs=receiver.recv()=>{
|
||||
if let Some(mut data) = rs{
|
||||
if data.len()<4{
|
||||
continue
|
||||
}
|
||||
let len = data.len() - 4;
|
||||
data[2] = (len >> 8) as u8;
|
||||
data[3] = (len & 0xFF) as u8;
|
||||
if let Err(e) = tcp_w.write_all(&data).await {
|
||||
if context.is_close() {
|
||||
break;
|
||||
}
|
||||
log::info!("发送失败,需要重连:{:?}",e);
|
||||
let _ = tcp_w.shutdown().await;
|
||||
match TcpStream::connect(context.inner.current_device.load().connect_server).await {
|
||||
Ok(tcp_stream) => {
|
||||
let (r, w) = tcp_stream.into_split();
|
||||
tcp_w = w;
|
||||
let context = context.clone();
|
||||
let handler = handler.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = Self::tcp_handle(r, context, handler, head_reserve).await {
|
||||
log::info!("tcp 链接断开:{:?}",e);
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
log::info!("重连失败:{:?}",e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
}
|
||||
pub async fn start(self,
|
||||
mut worker: VntWorker,
|
||||
tcp: Option<(TcpStream, tokio::sync::mpsc::Receiver<Vec<u8>>)>,
|
||||
head_reserve: usize,//头部预留字节
|
||||
symmetric_channel_num: usize,//对称网络,则再加一组监听,提升打洞成功率
|
||||
relay: bool,
|
||||
) {
|
||||
let context = self.context;
|
||||
let main_channel = context.inner.main_channel.clone();
|
||||
let handler = self.handler.clone();
|
||||
if let Some((tcp_stream, receiver)) = tcp {
|
||||
tokio::spawn(Self::start_tcp(worker.worker("main_channel_tcp"), tcp_stream, receiver, context.clone(), handler.clone(), head_reserve));
|
||||
}
|
||||
tokio::spawn(Self::start_(worker.worker("main_channel_1"), context.clone(), handler.clone(), main_channel.clone(), head_reserve, true));
|
||||
// tokio::spawn(Self::start_(worker.worker("main_channel_2"), context.clone(), handler, main_channel, head_reserve, true));
|
||||
if relay {
|
||||
worker.stop_wait().await;
|
||||
return;
|
||||
}
|
||||
let mut cur_status = Status::Cone;
|
||||
let mut status_receiver = context.inner.status_receiver.clone();
|
||||
loop {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
rs=status_receiver.changed()=>{
|
||||
match rs {
|
||||
Ok(_) => {
|
||||
let s = status_receiver.borrow().clone();
|
||||
match s {
|
||||
Status::Cone => {
|
||||
cur_status = Status::Cone;
|
||||
}
|
||||
Status::Symmetric => {
|
||||
if cur_status == Status::Symmetric {
|
||||
continue;
|
||||
}
|
||||
cur_status = Status::Symmetric;
|
||||
for _ in 0..symmetric_channel_num {
|
||||
match UdpSocket::bind("0.0.0.0:0").await {
|
||||
Ok(udp) => {
|
||||
let udp = Arc::new(udp);
|
||||
let context = context.clone();
|
||||
let handler = self.handler.clone();
|
||||
tokio::spawn(Self::start_(worker.worker("symmetric_channel"),context, handler, udp, head_reserve, false));
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Status::Close => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
}
|
||||
async fn start_(mut worker: VntWorker, context: Context,
|
||||
mut handler: ChannelDataHandler,
|
||||
udp: Arc<UdpSocket>,
|
||||
head_reserve: usize,
|
||||
is_core: bool) {
|
||||
let mut status_receiver = context.inner.status_receiver.clone();
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::io::AsRawSocket;
|
||||
#[cfg(target_os = "windows")]
|
||||
let id = 1 + udp.as_raw_socket() as usize;
|
||||
#[cfg(any(unix))]
|
||||
use std::os::fd::AsRawFd;
|
||||
#[cfg(any(unix))]
|
||||
let id = 1 + udp.as_raw_fd() as usize;
|
||||
context.inner.udp_map.insert(id, udp.clone());
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
tokio::select! {
|
||||
rs=udp.recv_from(&mut buf[head_reserve..])=>{
|
||||
Self::handle(&mut handler,&context,id,rs,&mut buf,head_reserve).await;
|
||||
}
|
||||
changed=status_receiver.changed()=>{
|
||||
match changed {
|
||||
Ok(_) => {
|
||||
match *status_receiver.borrow() {
|
||||
Status::Cone => {
|
||||
if !is_core{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Status::Close=>{
|
||||
break;
|
||||
}
|
||||
Status::Symmetric => {}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
context.inner.udp_map.remove(&id);
|
||||
if is_core {
|
||||
worker.stop_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
use std::io;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::time::Duration;
|
||||
use crate::channel::channel::Context;
|
||||
use crate::channel::RouteKey;
|
||||
|
||||
|
||||
pub struct Idle {
|
||||
read_idle: Duration,
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl Idle {
|
||||
pub fn new(read_idle: Duration,
|
||||
context: Context, ) -> Self {
|
||||
Self {
|
||||
read_idle,
|
||||
context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Idle {
|
||||
/// 获取空闲路由
|
||||
pub async fn next_idle(&self) -> io::Result<(Ipv4Addr, RouteKey)> {
|
||||
loop {
|
||||
let mut max = Duration::from_secs(0);
|
||||
for entry in self.context.inner.route_table_time.iter() {
|
||||
let last_read = entry.value().load().elapsed();
|
||||
if last_read >= self.read_idle {
|
||||
entry.remove();
|
||||
return Ok((entry.key().1.clone(), entry.key().0.clone()));
|
||||
} else {
|
||||
if max < last_read {
|
||||
max = last_read;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.read_idle > max {
|
||||
let sleep_time = self.read_idle - max;
|
||||
tokio::time::sleep(sleep_time).await;
|
||||
}
|
||||
if self.context.is_close() {
|
||||
return Err(Error::new(ErrorKind::Other, "closed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub mod channel;
|
||||
pub mod punch;
|
||||
pub mod idle;
|
||||
pub mod sender;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Status {
|
||||
Cone,
|
||||
Symmetric,
|
||||
Close,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Route {
|
||||
index: usize,
|
||||
pub addr: SocketAddr,
|
||||
pub metric: u8,
|
||||
pub rt: i64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct RouteSortKey {
|
||||
pub metric: u8,
|
||||
pub rt: i64,
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub fn new(index: usize,
|
||||
addr: SocketAddr, metric: u8, rt: i64, ) -> Self {
|
||||
Self {
|
||||
index,
|
||||
addr,
|
||||
metric,
|
||||
rt,
|
||||
}
|
||||
}
|
||||
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
|
||||
Self {
|
||||
index: route_key.index,
|
||||
addr: route_key.addr,
|
||||
metric,
|
||||
rt,
|
||||
}
|
||||
}
|
||||
pub fn route_key(&self) -> RouteKey {
|
||||
RouteKey {
|
||||
index: self.index,
|
||||
addr: self.addr,
|
||||
}
|
||||
}
|
||||
pub fn sort_key(&self) -> RouteSortKey {
|
||||
RouteSortKey {
|
||||
metric: self.metric,
|
||||
rt: self.rt,
|
||||
}
|
||||
}
|
||||
pub fn is_p2p(&self) -> bool {
|
||||
self.metric == 1
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct RouteKey {
|
||||
index: usize,
|
||||
pub addr: SocketAddr,
|
||||
}
|
||||
|
||||
impl RouteKey {
|
||||
pub(crate) fn new(index: usize,
|
||||
addr: SocketAddr, ) -> Self {
|
||||
Self {
|
||||
index,
|
||||
addr,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::time::Duration;
|
||||
|
||||
use rand::prelude::SliceRandom;
|
||||
|
||||
use crate::channel::channel::Context;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NatInfo {
|
||||
pub public_ips: Vec<Ipv4Addr>,
|
||||
pub public_port: u16,
|
||||
pub public_port_range: u16,
|
||||
pub local_ip: Ipv4Addr,
|
||||
pub local_port: u16,
|
||||
pub nat_type: NatType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum NatType {
|
||||
Symmetric,
|
||||
Cone,
|
||||
}
|
||||
|
||||
impl NatInfo {
|
||||
pub fn new(mut public_ips: Vec<Ipv4Addr>,
|
||||
public_port: u16,
|
||||
public_port_range: u16,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
nat_type: NatType, ) -> Self {
|
||||
public_ips.retain(|ip| {
|
||||
!ip.is_loopback() && !ip.is_private()
|
||||
});
|
||||
Self {
|
||||
public_ips,
|
||||
public_port,
|
||||
public_port_range,
|
||||
local_ip,
|
||||
local_port,
|
||||
nat_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Punch {
|
||||
context: Context,
|
||||
port_vec: Vec<u16>,
|
||||
port_index: HashMap<Ipv4Addr, usize>,
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
pub fn new(context: Context) -> Self {
|
||||
let mut port_vec: Vec<u16> = (1..65535).collect();
|
||||
port_vec.push(65535);
|
||||
let mut rng = rand::thread_rng();
|
||||
port_vec.shuffle(&mut rng);
|
||||
Punch {
|
||||
context,
|
||||
port_vec,
|
||||
port_index: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
pub async fn punch(&mut self, buf: &[u8], id: Ipv4Addr, nat_info: NatInfo) -> io::Result<()> {
|
||||
if !self.context.need_punch(&id) {
|
||||
return Ok(());
|
||||
}
|
||||
if !nat_info.local_ip.is_unspecified() || nat_info.local_port != 0 {
|
||||
let _ = self.context.send_main_udp(buf, SocketAddr::V4(SocketAddrV4::new(nat_info.local_ip, nat_info.local_port))).await;
|
||||
}
|
||||
match nat_info.nat_type {
|
||||
NatType::Symmetric => {
|
||||
// 假设对方绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,自己随机尝试k次的情况下
|
||||
// 猜中的概率 p = 1-((65535-n)/65535)*((65535-n-1)/(65535-1))*...*((65535-n-k+1)/(65535-k+1))
|
||||
// n取76,k取600,猜中的概率就超过50%了
|
||||
// 前提 自己是锥形网络,否则猜中了也通信不了
|
||||
|
||||
//预测范围内最多发送max_k1个包
|
||||
let max_k1 = 60;
|
||||
//全局最多发送max_k2个包
|
||||
let max_k2 = 800;
|
||||
if nat_info.public_port_range < max_k1 * 3 {
|
||||
//端口变化不大时,在预测的范围内随机发送
|
||||
let min_port = if nat_info.public_port > nat_info.public_port_range {
|
||||
nat_info.public_port - nat_info.public_port_range
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let (max_port, overflow) = nat_info.public_port.overflowing_add(nat_info.public_port_range);
|
||||
let max_port = if overflow {
|
||||
65535
|
||||
} else {
|
||||
max_port
|
||||
};
|
||||
let k = if max_port - min_port + 1 > max_k1 {
|
||||
max_k1 as usize
|
||||
} else {
|
||||
(max_port - min_port + 1) as usize
|
||||
};
|
||||
let mut nums: Vec<u16> = (min_port..max_port).collect();
|
||||
nums.push(max_port);
|
||||
{
|
||||
let mut rng = rand::thread_rng();
|
||||
nums.shuffle(&mut rng);
|
||||
}
|
||||
self.punch_symmetric(&nums[..k], buf, &nat_info.public_ips, max_k1 as usize).await?;
|
||||
}
|
||||
let start = *self.port_index.entry(id.clone()).or_insert(0);
|
||||
let mut end = start + max_k2;
|
||||
let mut index = end;
|
||||
if end >= self.port_vec.len() {
|
||||
end = self.port_vec.len();
|
||||
index = 0
|
||||
}
|
||||
self.punch_symmetric(&self.port_vec[start..end], buf, &nat_info.public_ips, max_k2).await?;
|
||||
self.port_index.insert(id, index);
|
||||
}
|
||||
NatType::Cone => {
|
||||
let is_cone = self.context.is_cone();
|
||||
for ip in nat_info.public_ips {
|
||||
let addr = SocketAddr::V4(SocketAddrV4::new(ip, nat_info.public_port));
|
||||
if is_cone {
|
||||
self.context.send_main_udp(buf, addr).await?;
|
||||
} else {
|
||||
//只有一方是对称,则对称方要使用全部端口发送数据,符合上述计算的概率
|
||||
self.context.send_all(buf, addr).await?;
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn punch_symmetric(&self, ports: &[u16], buf: &[u8], ips: &Vec<Ipv4Addr>, max: usize) -> io::Result<()> {
|
||||
let mut count = 0;
|
||||
for port in ports {
|
||||
for pub_ip in ips {
|
||||
count += 1;
|
||||
if count == max {
|
||||
return Ok(());
|
||||
}
|
||||
let addr = SocketAddr::V4(SocketAddrV4::new(*pub_ip, *port));
|
||||
self.context.send_main_udp(buf, addr).await?;
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use std::ops::Deref;
|
||||
use crate::channel::channel::Context;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChannelSender {
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl ChannelSender {
|
||||
pub fn new(context: Context) -> Self {
|
||||
Self {
|
||||
context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ChannelSender {
|
||||
type Target = Context;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.context
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
use std::io;
|
||||
|
||||
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, Nonce, Tag,KeyInit};
|
||||
use aes_gcm::aead::consts::{U12, U16};
|
||||
use aes_gcm::aead::generic_array::GenericArray;
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::protocol;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Cipher {
|
||||
AesGCM128(Aes128Gcm),
|
||||
AesGCM256(Aes256Gcm),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
pub fn new(password: Option<String>) -> Self {
|
||||
if let Some(password) = password {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(password.as_bytes());
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
if password.len() < 8 {
|
||||
let key: &Key<Aes128Gcm> = key[..16].into();
|
||||
Cipher::AesGCM128(Aes128Gcm::new(&key))
|
||||
} else {
|
||||
let key: &Key<Aes256Gcm> = &key.into();
|
||||
Cipher::AesGCM256(Aes256Gcm::new(&key))
|
||||
}
|
||||
} else {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
pub fn decrypt_ipv4(&self, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < 16 {
|
||||
log::error!("数据异常,长度小于16");
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce);
|
||||
let payload_len = net_packet.payload().len() - 16;
|
||||
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(&net_packet.payload()[payload_len..]);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher) => {
|
||||
cipher.decrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len], &tag)
|
||||
}
|
||||
Cipher::AesGCM256(cipher) => {
|
||||
cipher.decrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len], &tag)
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
if let Err(e) = rs {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)));
|
||||
}
|
||||
return Ok(Some(payload_len));
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
/// 返回加密后载荷的长度
|
||||
pub fn encrypt_ipv4(&self, payload_len: usize, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher) => {
|
||||
cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::AesGCM256(cipher) => {
|
||||
cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
return match rs {
|
||||
Ok(tag) => {
|
||||
if tag.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("加密tag长度错误:{}", tag.len())));
|
||||
}
|
||||
net_packet.set_encrypt_flag(true);
|
||||
net_packet.payload_mut()[payload_len..payload_len + 16].copy_from_slice(tag.as_slice());
|
||||
Ok(Some(payload_len + 16))
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#[cfg(feature = "ring-cipher")]
|
||||
mod ring_cipher;
|
||||
#[cfg(feature = "ring-cipher")]
|
||||
pub use ring_cipher::Cipher;
|
||||
#[cfg(not(feature = "ring-cipher"))]
|
||||
mod aes_gcm_cipher;
|
||||
#[cfg(not(feature = "ring-cipher"))]
|
||||
pub use aes_gcm_cipher::Cipher;
|
||||
@@ -0,0 +1,132 @@
|
||||
|
||||
|
||||
use std::io;
|
||||
use ring::aead;
|
||||
use ring::aead::{LessSafeKey, UnboundKey};
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::protocol;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket};
|
||||
|
||||
pub enum Cipher {
|
||||
AesGCM128(LessSafeKey, [u8; 16]),
|
||||
AesGCM256(LessSafeKey, [u8; 32]),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Clone for Cipher {
|
||||
fn clone(&self) -> Self {
|
||||
match &self {
|
||||
Cipher::AesGCM128(_, key) => {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, key.as_slice()).unwrap());
|
||||
Cipher::AesGCM128(c, *key)
|
||||
}
|
||||
Cipher::AesGCM256(_, key) => {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, key.as_slice()).unwrap());
|
||||
Cipher::AesGCM256(c, *key)
|
||||
}
|
||||
Cipher::None => {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
pub fn new(password: Option<String>) -> Self {
|
||||
if let Some(password) = password {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(password.as_bytes());
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
if password.len() < 8 {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, &key[..16]).unwrap());
|
||||
Cipher::AesGCM128(c, key[..16].try_into().unwrap())
|
||||
} else {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, &key).unwrap());
|
||||
Cipher::AesGCM256(c, key)
|
||||
}
|
||||
} else {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
pub fn decrypt_ipv4(&self, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < 16 {
|
||||
log::error!("数据异常,长度小于16");
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce = aead::Nonce::assume_unique_for_key(nonce);
|
||||
let payload_len = net_packet.payload().len() - 16;
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher, _) => {
|
||||
cipher.open_in_place(nonce, aead::Aad::empty(), net_packet.payload_mut())
|
||||
}
|
||||
Cipher::AesGCM256(cipher, _) => {
|
||||
cipher.open_in_place(nonce, aead::Aad::empty(), net_packet.payload_mut())
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
if let Err(e) = rs {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)));
|
||||
}
|
||||
return Ok(Some(payload_len));
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
/// 返回加密后载荷的长度
|
||||
pub fn encrypt_ipv4(&self, payload_len: usize, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce = aead::Nonce::assume_unique_for_key(nonce);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher, _) => {
|
||||
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::AesGCM256(cipher, _) => {
|
||||
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
return match rs {
|
||||
Ok(tag) => {
|
||||
let tag = tag.as_ref();
|
||||
if tag.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("加密tag长度错误:{}", tag.len())));
|
||||
}
|
||||
net_packet.set_encrypt_flag(true);
|
||||
net_packet.payload_mut()[payload_len..payload_len + 16].copy_from_slice(tag);
|
||||
Ok(Some(payload_len + 16))
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
use tokio::sync::mpsc::channel;
|
||||
|
||||
use crate::channel::{Route, RouteKey};
|
||||
use crate::channel::channel::{Channel, Context};
|
||||
use crate::channel::idle::Idle;
|
||||
use crate::channel::punch::{NatInfo, Punch};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntStatusManger;
|
||||
use crate::error::Error;
|
||||
use crate::external_route::{AllowExternalRoute, ExternalRoute};
|
||||
use crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, registration_handler};
|
||||
use crate::handle::recv_handler::ChannelDataHandler;
|
||||
use crate::handle::registration_handler::{RegResponse, ReqEnum};
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
use crate::handle::tun_tap::tap_handler;
|
||||
use crate::handle::tun_tap::tun_handler;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::nat::NatTest;
|
||||
use crate::tun_tap_device;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceWriter};
|
||||
|
||||
pub mod status;
|
||||
pub mod sync;
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vnt {
|
||||
name: String,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
context: Context,
|
||||
vnt_status_manager: VntStatusManger,
|
||||
device_writer: DeviceWriter,
|
||||
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
|
||||
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
||||
/// 1. 网络中的虚拟ip列表
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
nat_test: NatTest,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
}
|
||||
|
||||
pub struct VntUtil {
|
||||
config: Config,
|
||||
main_channel: UdpSocket,
|
||||
main_tcp_channel: Option<TcpStream>,
|
||||
response: Option<RegResponse>,
|
||||
iface: Option<(DeviceWriter, DeviceReader)>,
|
||||
}
|
||||
|
||||
impl VntUtil {
|
||||
pub async fn new(config: Config) -> io::Result<VntUtil> {
|
||||
let main_channel = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
Ok(VntUtil {
|
||||
config,
|
||||
main_channel,
|
||||
main_tcp_channel: None,
|
||||
response: None,
|
||||
iface: None,
|
||||
})
|
||||
}
|
||||
pub async fn connect(&mut self) -> Result<RegResponse, ReqEnum> {
|
||||
if self.config.tcp {
|
||||
match TcpStream::connect(self.config.server_address).await {
|
||||
Ok(tcp) => {
|
||||
let _ = self.main_tcp_channel.insert(tcp);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ReqEnum::Other(format!("connect error:{}", e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
match registration_handler::registration(&self.main_channel, self.main_tcp_channel.as_mut(), self.config.server_address,
|
||||
self.config.token.clone(), self.config.device_id.clone(),
|
||||
self.config.name.clone(), self.config.ip.unwrap_or(Ipv4Addr::UNSPECIFIED)).await {
|
||||
Ok(res) => {
|
||||
let _ = self.response.insert(res.clone());
|
||||
Ok(res)
|
||||
}
|
||||
Err(e) => {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "android"))]
|
||||
pub fn create_iface(&mut self, vpn_fd: i32) {
|
||||
let (device_writer, device_reader) = tun_tap_device::create(vpn_fd);
|
||||
let _ = self.iface.insert((device_writer, device_reader));
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
pub fn create_iface(&mut self) -> io::Result<tun_tap_device::DriverInfo> {
|
||||
if self.iface.is_some() {
|
||||
return Err(io::Error::from(io::ErrorKind::AlreadyExists));
|
||||
}
|
||||
let response = match &self.response {
|
||||
None => {
|
||||
return Err(io::Error::from(io::ErrorKind::AlreadyExists));
|
||||
}
|
||||
Some(res) => {
|
||||
res
|
||||
}
|
||||
};
|
||||
let device_type = if self.config.tap {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
//删除tun网卡避免ip冲突,因为非正常退出会保留网卡
|
||||
tun_tap_device::delete_device(tun_tap_device::DeviceType::Tun);
|
||||
}
|
||||
tun_tap_device::DeviceType::Tap
|
||||
} else {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
//删除tap网卡避免ip冲突,非正常退出会保留网卡
|
||||
tun_tap_device::delete_device(tun_tap_device::DeviceType::Tap);
|
||||
}
|
||||
tun_tap_device::DeviceType::Tun
|
||||
};
|
||||
let mtu = self.config.mtu.unwrap_or(1430);
|
||||
let in_ips = self.config.in_ips.iter().map(|(dest, mask, _)| { (Ipv4Addr::from(*dest & *mask), Ipv4Addr::from(*mask)) }).collect::<Vec<(Ipv4Addr, Ipv4Addr)>>();
|
||||
|
||||
let (device_writer, device_reader, driver_info) = tun_tap_device::create_device(device_type, response.virtual_ip,
|
||||
response.virtual_netmask, response.virtual_gateway, in_ips, mtu)?;
|
||||
let _ = self.iface.insert((device_writer, device_reader));
|
||||
Ok(driver_info)
|
||||
}
|
||||
pub async fn build(self) -> crate::Result<Vnt> {
|
||||
let response = match self.response {
|
||||
None => {
|
||||
return Err(Error::Stop("response None".to_string()));
|
||||
}
|
||||
Some(res) => {
|
||||
res
|
||||
}
|
||||
};
|
||||
let (device_writer, device_reader) = match self.iface {
|
||||
None => {
|
||||
return Err(Error::Stop("iface None".to_string()));
|
||||
}
|
||||
Some(res) => {
|
||||
res
|
||||
}
|
||||
};
|
||||
let config = self.config;
|
||||
let vnt_status_manager = VntStatusManger::new();
|
||||
let cipher = Cipher::new(config.password.clone());
|
||||
let virtual_ip = response.virtual_ip;
|
||||
let virtual_gateway = response.virtual_gateway;
|
||||
let virtual_netmask = response.virtual_netmask;
|
||||
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address)));
|
||||
|
||||
let (cone_sender, cone_receiver) = channel(3);
|
||||
let (symmetric_sender, symmetric_receiver) = channel(2);
|
||||
let (tcp_sender, tcp) = if let Some(main_tcp_channel) = self.main_tcp_channel {
|
||||
let (tcp_sender, tcp_receiver) = channel::<Vec<u8>>(100);
|
||||
(Some(tcp_sender), Some((main_tcp_channel, tcp_receiver)))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let context = Context::new(Arc::new(self.main_channel), tcp_sender, current_device.clone(), 1);
|
||||
let punch = Punch::new(context.clone());
|
||||
let idle = Idle::new(Duration::from_secs(16), context.clone());
|
||||
let channel_sender = ChannelSender::new(context.clone());
|
||||
|
||||
let register = Arc::new(registration_handler::Register::new(channel_sender.clone(),
|
||||
config.server_address, config.token.clone(),
|
||||
config.device_id.clone(), config.name.clone()));
|
||||
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> = Arc::new(Mutex::new((response.epoch, response.device_info_list)));
|
||||
let peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>> = Arc::new(SkipMap::new());
|
||||
let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected));
|
||||
|
||||
|
||||
let local_ip = crate::nat::local_ip()?;
|
||||
let local_port = context.main_local_port()?;
|
||||
// NAT检测
|
||||
let nat_test = NatTest::new(config.nat_test_server.clone(), response.public_ip, response.public_port, local_ip, local_port);
|
||||
let in_external_route = if config.in_ips.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ExternalRoute::new(config.in_ips))
|
||||
};
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = if config.out_ips.is_empty() {
|
||||
(None, None, None)
|
||||
} else {
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = crate::ip_proxy::init_proxy(channel_sender.clone(), current_device.clone()).await?;
|
||||
(Some(tcp_proxy), Some(udp_proxy), Some(ip_proxy_map))
|
||||
};
|
||||
let out_external_route = AllowExternalRoute::new(config.out_ips);
|
||||
|
||||
let igmp_server = if config.simulate_multicast {
|
||||
Some(IgmpServer::new(device_writer.clone()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
if config.tap {
|
||||
tap_handler::start(vnt_status_manager.worker("tap_handler"), channel_sender.clone(), device_reader, device_writer.clone(),
|
||||
igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone());
|
||||
} else {
|
||||
tun_handler::start(vnt_status_manager.worker("tun_handler"), channel_sender.clone(), device_reader, device_writer.clone(),
|
||||
igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone());
|
||||
}
|
||||
#[cfg(any(target_os = "android"))]
|
||||
tun_handler::start(vnt_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());
|
||||
|
||||
//外部数据接收处理
|
||||
let channel_recv_handler = ChannelDataHandler::new(current_device.clone(), device_list.clone(),
|
||||
register.clone(), nat_test.clone(), igmp_server,
|
||||
device_writer.clone(), connect_status.clone(),
|
||||
peer_nat_info_map.clone(), ip_proxy_map, out_external_route,
|
||||
cone_sender, symmetric_sender, cipher, config.relay);
|
||||
{
|
||||
let channel = Channel::new(context.clone(), channel_recv_handler);
|
||||
let channel_worker = vnt_status_manager.worker("channel_worker");
|
||||
let relay = config.relay;
|
||||
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, tcp, 14, 65, relay).await
|
||||
});
|
||||
}
|
||||
{
|
||||
let other_worker = vnt_status_manager.worker("punch_handler");
|
||||
let nat_test = nat_test.clone();
|
||||
let device_list = device_list.clone();
|
||||
let current_device = current_device.clone();
|
||||
// 定时心跳
|
||||
heartbeat_handler::start_heartbeat(other_worker.worker("heartbeat"), channel_sender.clone(), device_list.clone(), current_device.clone(), config.server_address_str);
|
||||
// 空闲检查
|
||||
heartbeat_handler::start_idle(other_worker.worker("idle"), idle, channel_sender.clone());
|
||||
if !config.relay {
|
||||
// 打洞处理
|
||||
punch_handler::start(other_worker.worker("cone_receiver"), cone_receiver, punch.clone(), current_device.clone());
|
||||
punch_handler::start(other_worker.worker("symmetric_receiver"), symmetric_receiver, punch, current_device.clone());
|
||||
tokio::spawn(punch_handler::start_punch(other_worker, nat_test,
|
||||
device_list, channel_sender, current_device));
|
||||
}
|
||||
}
|
||||
context.switch(nat_test.nat_info().nat_type);
|
||||
Ok(Vnt {
|
||||
name: config.name,
|
||||
current_device,
|
||||
context,
|
||||
vnt_status_manager,
|
||||
device_writer,
|
||||
nat_test,
|
||||
device_list,
|
||||
connect_status,
|
||||
peer_nat_info_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Vnt {
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
pub fn current_device(&self) -> CurrentDeviceInfo {
|
||||
self.current_device.load()
|
||||
}
|
||||
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
|
||||
self.peer_nat_info_map.get(ip).map(|e| e.value().clone())
|
||||
}
|
||||
pub fn connection_status(&self) -> ConnectStatus {
|
||||
self.connect_status.load()
|
||||
}
|
||||
pub fn nat_info(&self) -> NatInfo {
|
||||
self.nat_test.nat_info()
|
||||
}
|
||||
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
|
||||
let device_list_lock = self.device_list.lock();
|
||||
let (_epoch, device_list) = device_list_lock.clone();
|
||||
drop(device_list_lock);
|
||||
device_list
|
||||
}
|
||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
|
||||
self.context.route_one(ip)
|
||||
}
|
||||
pub fn route_key(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
|
||||
self.context.route_to_id(route_key)
|
||||
}
|
||||
pub fn route_table(&self) -> Vec<(Ipv4Addr, Route)> {
|
||||
self.context.route_table_one()
|
||||
}
|
||||
pub fn stop(&self) -> io::Result<()> {
|
||||
self.context.close();
|
||||
self.vnt_status_manager.stop_all();
|
||||
self.device_writer.close()?;
|
||||
let virtual_gateway = self.current_device.load().virtual_gateway;
|
||||
let _ = std::net::UdpSocket::bind("0.0.0.0:0")?.send_to(&[0],
|
||||
SocketAddr::V4(SocketAddrV4::new(virtual_gateway, 10000)));
|
||||
Ok(())
|
||||
}
|
||||
pub async fn wait_stop(&mut self) {
|
||||
self.vnt_status_manager.wait().await;
|
||||
let _ = self.stop();
|
||||
}
|
||||
pub async fn wait_stop_ms(&mut self, ms: Duration) -> bool {
|
||||
tokio::select! {
|
||||
_=self.vnt_status_manager.wait()=>{
|
||||
let _ = self.stop();
|
||||
return true;
|
||||
}
|
||||
_=tokio::time::sleep(ms)=>{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Vnt {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.stop();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
pub tap: bool,
|
||||
pub token: String,
|
||||
pub device_id: String,
|
||||
pub name: String,
|
||||
pub server_address: SocketAddr,
|
||||
pub server_address_str: String,
|
||||
pub nat_test_server: Vec<SocketAddr>,
|
||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32)>,
|
||||
pub password: Option<String>,
|
||||
pub simulate_multicast: bool,
|
||||
pub mtu: Option<u16>,
|
||||
pub tcp: bool,
|
||||
pub ip: Option<Ipv4Addr>,
|
||||
pub relay: bool,
|
||||
}
|
||||
|
||||
|
||||
impl Config {
|
||||
pub fn new(tap: bool, token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
server_address: SocketAddr,
|
||||
server_address_str: String,
|
||||
nat_test_server: Vec<SocketAddr>,
|
||||
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32)>,
|
||||
password: Option<String>, simulate_multicast: bool, mtu: Option<u16>, tcp: bool,
|
||||
ip: Option<Ipv4Addr>,
|
||||
relay: bool, ) -> Self {
|
||||
Self {
|
||||
tap,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address,
|
||||
server_address_str,
|
||||
nat_test_server,
|
||||
in_ips,
|
||||
out_ips,
|
||||
password,
|
||||
simulate_multicast,
|
||||
mtu,
|
||||
tcp,
|
||||
ip,
|
||||
relay,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::watch;
|
||||
use tokio::sync::watch::{Receiver, Sender};
|
||||
use crate::util::wait::WaitGroup;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum VntStatus {
|
||||
Starting,
|
||||
Stopping,
|
||||
}
|
||||
|
||||
pub struct VntWorker {
|
||||
_name: String,
|
||||
wg: WaitGroup,
|
||||
status_s: Arc<Sender<VntStatus>>,
|
||||
status_r: Receiver<VntStatus>,
|
||||
}
|
||||
|
||||
impl VntWorker {
|
||||
pub fn worker(&self, name: &str) -> Self {
|
||||
self.wg.add();
|
||||
VntWorker {
|
||||
_name: name.to_string(),
|
||||
wg: self.wg.clone(),
|
||||
status_s: self.status_s.clone(),
|
||||
status_r: self.status_r.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VntWorker {
|
||||
fn drop(&mut self) {
|
||||
self.wg.done();
|
||||
}
|
||||
}
|
||||
|
||||
impl VntWorker {
|
||||
pub fn stop_all(&self) {
|
||||
let _ = self.status_s.send(VntStatus::Stopping);
|
||||
}
|
||||
pub async fn stop_wait(&mut self) {
|
||||
loop {
|
||||
if *self.status_r.borrow() == VntStatus::Stopping {
|
||||
return;
|
||||
}
|
||||
match self.status_r.changed().await {
|
||||
Ok(_) => {
|
||||
if *self.status_r.borrow() == VntStatus::Stopping {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(_) => { return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VntStatusManger {
|
||||
wg: WaitGroup,
|
||||
status_s: Arc<Sender<VntStatus>>,
|
||||
status_r: Receiver<VntStatus>,
|
||||
}
|
||||
|
||||
impl VntStatusManger {
|
||||
pub fn new() -> Self {
|
||||
let (status_s, status_r) = watch::channel(VntStatus::Starting);
|
||||
Self {
|
||||
wg: WaitGroup::new(),
|
||||
status_s: Arc::new(status_s),
|
||||
status_r,
|
||||
}
|
||||
}
|
||||
pub fn stop_all(&self) {
|
||||
let _ = self.status_s.send(VntStatus::Stopping);
|
||||
}
|
||||
pub async fn wait(&mut self) {
|
||||
self.wg.wait().await
|
||||
}
|
||||
pub fn worker(&self, name: &str) -> VntWorker {
|
||||
self.wg.add();
|
||||
VntWorker {
|
||||
_name: name.to_string(),
|
||||
wg: self.wg.clone(),
|
||||
status_s: self.status_s.clone(),
|
||||
status_r: self.status_r.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
use std::io;
|
||||
use std::ops::Deref;
|
||||
use std::time::Duration;
|
||||
use tokio::runtime::Runtime;
|
||||
use crate::core::{Config, Vnt, VntUtil};
|
||||
use crate::handle::registration_handler::{RegResponse, ReqEnum};
|
||||
|
||||
pub struct VntUtilSync {
|
||||
vnt_util: VntUtil,
|
||||
runtime: Runtime,
|
||||
}
|
||||
|
||||
pub struct VntSync {
|
||||
vnt: Vnt,
|
||||
runtime: Runtime,
|
||||
}
|
||||
|
||||
impl VntUtilSync {
|
||||
pub fn new(config: Config) -> io::Result<VntUtilSync> {
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
|
||||
let vnt_util = runtime.block_on(VntUtil::new(config))?;
|
||||
Ok(VntUtilSync {
|
||||
vnt_util,
|
||||
runtime,
|
||||
})
|
||||
}
|
||||
pub fn connect(&mut self) -> Result<RegResponse, ReqEnum> {
|
||||
self.runtime.block_on(self.vnt_util.connect())
|
||||
}
|
||||
#[cfg(any(target_os = "android"))]
|
||||
pub fn create_iface(&mut self, vpn_fd: i32) {
|
||||
self.vnt_util.create_iface(vpn_fd)
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
pub fn create_iface(&mut self) -> io::Result<crate::tun_tap_device::DriverInfo> {
|
||||
self.vnt_util.create_iface()
|
||||
}
|
||||
pub fn build(self) -> crate::Result<VntSync> {
|
||||
let runtime = self.runtime;
|
||||
let vnt = runtime.block_on(self.vnt_util.build())?;
|
||||
{
|
||||
let mut vnt = vnt.clone();
|
||||
std::thread::spawn(move || {
|
||||
runtime.block_on(vnt.wait_stop())
|
||||
});
|
||||
}
|
||||
Ok(VntSync {
|
||||
vnt,
|
||||
runtime: tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl VntSync {
|
||||
pub fn wait_stop(&mut self) {
|
||||
self.runtime.block_on(self.vnt.wait_stop())
|
||||
}
|
||||
pub fn wait_stop_ms(&mut self, ms: u64) -> bool {
|
||||
self.runtime.block_on(self.vnt.wait_stop_ms(Duration::from_millis(ms)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for VntSync {
|
||||
type Target = Vnt;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.vnt
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
use std::io;
|
||||
|
||||
use crossbeam::channel::RecvError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("packet error")]
|
||||
PacketError(#[from] packet::error::Error),
|
||||
#[error("Io error")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Channel error")]
|
||||
Channel(#[from] RecvError),
|
||||
#[error("Protobuf error")]
|
||||
Protobuf(#[from] protobuf::Error),
|
||||
#[error("Invalid packet")]
|
||||
@@ -0,0 +1,48 @@
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
|
||||
// 目标ip,子网掩码,网关
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExternalRoute {
|
||||
route_table: Arc<Vec<(u32, u32, Ipv4Addr)>>,
|
||||
}
|
||||
|
||||
impl ExternalRoute {
|
||||
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
|
||||
Self {
|
||||
route_table: Arc::new(route_table)
|
||||
}
|
||||
}
|
||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
for (dest, mask, gateway) in self.route_table.iter() {
|
||||
if *mask & ip == *mask & *dest {
|
||||
return Some(*gateway);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AllowExternalRoute {
|
||||
route_table: Arc<Vec<(u32, u32)>>,
|
||||
}
|
||||
|
||||
impl AllowExternalRoute {
|
||||
pub fn new(route_table: Vec<(u32, u32)>) -> Self {
|
||||
Self {
|
||||
route_table: Arc::new(route_table)
|
||||
}
|
||||
}
|
||||
pub fn allow(&self, ip: &Ipv4Addr) -> bool {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
for (dest, mask) in self.route_table.iter() {
|
||||
if *mask & ip == *mask & *dest {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::io;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use rand::prelude::SliceRandom;
|
||||
use crate::channel::idle::Idle;
|
||||
use crate::channel::Route;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::core::status::VntWorker;
|
||||
|
||||
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::protocol::control_packet::PingPacket;
|
||||
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, Version};
|
||||
|
||||
pub fn start_idle(mut worker: VntWorker, idle: Idle, sender: ChannelSender) {
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
return;
|
||||
}
|
||||
rs=start_idle_(idle, sender)=>{
|
||||
if let Err(e) = rs {
|
||||
log::warn!("空闲检测任务停止:{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}
|
||||
|
||||
async fn start_idle_(idle: Idle, sender: ChannelSender) -> io::Result<()> {
|
||||
loop {
|
||||
let (peer_ip, route) = idle.next_idle().await?;
|
||||
log::info!(
|
||||
"peer_ip:{:?},route:{:?}",
|
||||
peer_ip,
|
||||
route
|
||||
);
|
||||
sender.remove_route(&peer_ip, route);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_heartbeat(
|
||||
mut worker: VntWorker,
|
||||
sender: ChannelSender,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
server_address_str: String,
|
||||
) {
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
return;
|
||||
}
|
||||
rs=start_heartbeat_(sender, device_list, current_device,server_address_str)=>{
|
||||
if let Err(e) = rs {
|
||||
log::warn!("心跳任务停止:{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}
|
||||
|
||||
fn set_now_time(packet: &mut NetPacket<[u8; 16]>) -> io::Result<()> {
|
||||
let current_time = crate::handle::now_time() as u16;
|
||||
let mut ping = PingPacket::new(packet.payload_mut())?;
|
||||
ping.set_time(current_time);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn start_heartbeat_(
|
||||
sender: ChannelSender,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
server_address_str: String,
|
||||
) -> io::Result<()> {
|
||||
let mut net_packet = NetPacket::new([0u8; 16])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Control);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
|
||||
//只寻找两跳以内能到的目标
|
||||
net_packet.first_set_ttl(2);
|
||||
let mut count = 0;
|
||||
loop {
|
||||
if sender.is_close() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut current_dev = current_device.load();
|
||||
if count % 10 == 0 {
|
||||
let mut packet = NetPacket::new([0; 12])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(
|
||||
control_packet::Protocol::AddrRequest.into(),
|
||||
);
|
||||
packet.first_set_ttl(MAX_TTL);
|
||||
packet.set_source(current_dev.virtual_ip());
|
||||
packet.set_destination(current_dev.virtual_gateway);
|
||||
let _ = sender.send_main_udp(packet.buffer(), current_dev.connect_server).await;
|
||||
}
|
||||
if count % 20 == 19 {
|
||||
if let Ok(mut addr) = server_address_str.to_socket_addrs() {
|
||||
if let Some(addr) = addr.next() {
|
||||
if addr != current_dev.connect_server {
|
||||
let mut tmp = current_dev.clone();
|
||||
tmp.connect_server = addr;
|
||||
if current_device.compare_exchange(current_dev, tmp).is_ok() {
|
||||
current_dev.connect_server = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
net_packet.set_source(current_dev.virtual_ip());
|
||||
{
|
||||
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||
let epoch = { device_list.lock().0 };
|
||||
ping.set_epoch(epoch);
|
||||
}
|
||||
set_now_time(&mut net_packet)?;
|
||||
net_packet.set_destination(current_dev.virtual_gateway());
|
||||
if let Err(e) = sender.send_main(net_packet.buffer(), current_dev.connect_server).await
|
||||
{
|
||||
log::warn!(
|
||||
"connect_server:{:?},e:{:?}",
|
||||
current_dev.connect_server,
|
||||
e
|
||||
);
|
||||
}
|
||||
if count < 7 || count % 7 == 0 {
|
||||
let mut route_list: Option<Vec<(Ipv4Addr, Vec<Route>)>> = None;
|
||||
let peer_list = { device_list.lock().1.clone() };
|
||||
for peer in peer_list {
|
||||
if peer.virtual_ip == current_dev.virtual_ip {
|
||||
continue;
|
||||
}
|
||||
set_now_time(&mut net_packet)?;
|
||||
net_packet.set_destination(peer.virtual_ip);
|
||||
if let Some(route) = sender.route_one(&peer.virtual_ip) {
|
||||
let _ = sender.send_by_key(net_packet.buffer(), &route.route_key()).await;
|
||||
if route.is_p2p() {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
//没有直连路由则发送到网关
|
||||
let _ = sender.send_main(net_packet.buffer(), current_dev.connect_server).await;
|
||||
}
|
||||
|
||||
//再随机发送到其他地址,看有没有客户端符合转发条件
|
||||
let route_list = route_list.get_or_insert_with(|| {
|
||||
let mut l = sender.route_table();
|
||||
l.shuffle(&mut rand::thread_rng());
|
||||
l
|
||||
});
|
||||
let mut num = 0;
|
||||
'a: for (peer_ip, route_list) in route_list.iter() {
|
||||
for route in route_list {
|
||||
if peer_ip != &peer.virtual_ip && route.is_p2p() {
|
||||
set_now_time(&mut net_packet)?;
|
||||
let _ = sender.try_send_by_key(net_packet.buffer(), &route.route_key());
|
||||
num += 1;
|
||||
break;
|
||||
}
|
||||
if num >= 2 {
|
||||
break 'a;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||
}
|
||||
} else {
|
||||
for (peer_ip, route_list) in sender.route_table().iter() {
|
||||
net_packet.set_destination(*peer_ip);
|
||||
for route in route_list {
|
||||
set_now_time(&mut net_packet)?;
|
||||
if let Err(e) = sender.send_by_key(net_packet.buffer(), &route.route_key()).await {
|
||||
log::warn!("peer_ip:{:?},route:{:?},e:{:?}", peer_ip, route, e);
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count += 1;
|
||||
tokio::time::sleep(Duration::from_millis(5000)).await;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,19 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
|
||||
pub mod heartbeat_handler;
|
||||
pub mod tun_handler;
|
||||
pub mod tap_handler;
|
||||
pub mod punch_handler;
|
||||
pub mod recv_handler;
|
||||
pub mod registration_handler;
|
||||
pub mod tun_tap;
|
||||
|
||||
pub fn now_time() -> u64 {
|
||||
let now = std::time::SystemTime::now();
|
||||
if let Ok(timestamp) = now.duration_since(std::time::UNIX_EPOCH) {
|
||||
timestamp.as_secs() * 1000 + u64::from(timestamp.subsec_millis())
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否在一个网段
|
||||
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
|
||||
@@ -30,7 +38,7 @@ impl PeerDeviceInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq,Ord, PartialOrd)]
|
||||
pub enum PeerDeviceStatus {
|
||||
Online,
|
||||
Offline,
|
||||
@@ -60,19 +68,6 @@ pub enum ConnectStatus {
|
||||
Connected,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct CurrentDeviceInfoExt {
|
||||
pub mac: [u8; 6],
|
||||
}
|
||||
|
||||
impl CurrentDeviceInfoExt {
|
||||
pub fn new(mac: [u8; 6]) -> Self {
|
||||
Self {
|
||||
mac,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct CurrentDeviceInfo {
|
||||
virtual_ip: Ipv4Addr,
|
||||
@@ -0,0 +1,140 @@
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::nat::NatTest;
|
||||
use crate::proto::message::{PunchInfo, PunchNatType};
|
||||
use crate::protocol::{control_packet, other_turn_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use protobuf::Message;
|
||||
use rand::prelude::SliceRandom;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::io;
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
use crate::channel::punch::{NatInfo, Punch};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::core::status::VntWorker;
|
||||
|
||||
pub fn start(mut worker: VntWorker, receiver: Receiver<(Ipv4Addr, NatInfo)>, punch: Punch, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_=start0(receiver, punch, current_device)=>{}
|
||||
_=worker.stop_wait()=>{
|
||||
return;
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn start0(mut receiver: Receiver<(Ipv4Addr, NatInfo)>, mut punch: Punch, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
||||
while let Some((peer_ip, nat_info)) = receiver.recv().await {
|
||||
if let Err(e) = start_(&mut punch, ¤t_device, peer_ip, nat_info).await {
|
||||
log::warn!("网络打洞异常 {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_(
|
||||
punch: &mut Punch,
|
||||
current_device: &Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
peer_ip: Ipv4Addr,
|
||||
nat_info: NatInfo,
|
||||
) -> io::Result<()> {
|
||||
let mut packet = NetPacket::new([0u8; 12])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.first_set_ttl(1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
packet.set_source(current_device.load().virtual_ip());
|
||||
packet.set_destination(peer_ip);
|
||||
log::info!("发起打洞,目标:{:?},{:?}", peer_ip, nat_info);
|
||||
|
||||
punch.punch(packet.buffer(), peer_ip, nat_info).await
|
||||
}
|
||||
|
||||
pub async fn start_punch(
|
||||
mut worker: VntWorker,
|
||||
nat_test: NatTest,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
sender: ChannelSender,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) {
|
||||
let mut num = 0;
|
||||
let sleep_time = [3, 5, 7, 11, 13, 17, 19, 23, 29];
|
||||
loop {
|
||||
if sender.is_close() {
|
||||
break;
|
||||
}
|
||||
tokio::select! {
|
||||
rs= start_punch_(Duration::from_secs(sleep_time[num % sleep_time.len()]),&nat_test, &device_list, &sender, ¤t_device)=>{
|
||||
if let Err(e) = rs {
|
||||
log::warn!("打洞处理任务异常 {:?}", e);
|
||||
}
|
||||
}
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
}
|
||||
num += 1;
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_punch_(
|
||||
sleep_time: Duration,
|
||||
nat_test: &NatTest,
|
||||
device_list: &Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
sender: &ChannelSender,
|
||||
current_device: &Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) -> crate::Result<()> {
|
||||
let current_device = current_device.load();
|
||||
let nat_info = nat_test.nat_info();
|
||||
let mut list = device_list.lock().clone().1;
|
||||
list.shuffle(&mut rand::thread_rng());
|
||||
let mut count = 0;
|
||||
for info in list {
|
||||
if info.virtual_ip <= current_device.virtual_ip {
|
||||
continue;
|
||||
}
|
||||
if !sender.need_punch(&info.virtual_ip) {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
if count > 2 {
|
||||
break;
|
||||
}
|
||||
let buf = punch_packet(current_device.virtual_ip(), &nat_info, info.virtual_ip)?;
|
||||
let _ = sender.send_main(&buf, current_device.connect_server).await;
|
||||
}
|
||||
tokio::time::sleep(sleep_time).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn punch_packet(
|
||||
virtual_ip: Ipv4Addr,
|
||||
nat_info: &NatInfo,
|
||||
dest: Ipv4Addr,
|
||||
) -> crate::Result<Vec<u8>> {
|
||||
let mut punch_reply = PunchInfo::new();
|
||||
punch_reply.reply = false;
|
||||
punch_reply.public_ip_list = nat_info
|
||||
.public_ips
|
||||
.iter()
|
||||
.map(|ip| u32::from_be_bytes(ip.octets()))
|
||||
.collect();
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ip.octets());
|
||||
punch_reply.local_port = nat_info.local_port as u32;
|
||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 12 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(other_turn_packet::Protocol::Punch.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_source(virtual_ip);
|
||||
net_packet.set_destination(dest);
|
||||
net_packet.set_payload(&bytes);
|
||||
Ok(net_packet.into_buffer())
|
||||
}
|
||||
@@ -0,0 +1,522 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use parking_lot::Mutex;
|
||||
use protobuf::Message;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
|
||||
use packet::icmp::{icmp, Kind};
|
||||
use packet::icmp::icmp::HeaderOther;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use crate::channel::channel::Context;
|
||||
use crate::channel::punch::{NatInfo, NatType};
|
||||
use crate::channel::{Route, RouteKey};
|
||||
use crate::cipher::Cipher;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::external_route::AllowExternalRoute;
|
||||
use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, PeerDeviceStatus};
|
||||
use crate::handle::registration_handler::Register;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::nat;
|
||||
use crate::nat::NatTest;
|
||||
use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationResponse};
|
||||
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, service_packet, other_turn_packet, Version, ip_turn_packet};
|
||||
use crate::protocol::control_packet::ControlPacket;
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::tun_tap_device::DeviceWriter;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChannelDataHandler {
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
register: Arc<Register>,
|
||||
nat_test: NatTest,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
device_writer: DeviceWriter,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
out_external_route: AllowExternalRoute,
|
||||
cone_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
symmetric_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
cipher: Cipher,
|
||||
relay: bool,
|
||||
}
|
||||
|
||||
impl ChannelDataHandler {
|
||||
pub fn new(current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
register: Arc<Register>,
|
||||
nat_test: NatTest,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
device_writer: DeviceWriter,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
out_external_route: AllowExternalRoute,
|
||||
cone_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
symmetric_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
cipher: Cipher,
|
||||
relay: bool, ) -> Self {
|
||||
Self {
|
||||
current_device,
|
||||
device_list,
|
||||
register,
|
||||
nat_test,
|
||||
igmp_server,
|
||||
device_writer,
|
||||
connect_status,
|
||||
peer_nat_info_map,
|
||||
ip_proxy_map,
|
||||
out_external_route,
|
||||
cone_sender,
|
||||
symmetric_sender,
|
||||
cipher,
|
||||
relay,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl ChannelDataHandler {
|
||||
pub async fn handle(&mut self, buf: &mut [u8], start: usize, end: usize, route_key: RouteKey, context: &Context) {
|
||||
assert_eq!(start, 14);
|
||||
match self.handle0(&mut buf[..end], &route_key, context).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn handle0(&self, buf: &mut [u8], route_key: &RouteKey, context: &Context) -> crate::Result<()> {
|
||||
let mut net_packet = NetPacket::new(&mut buf[14..])?;
|
||||
if net_packet.ttl() == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let source = net_packet.source();
|
||||
let current_device = self.current_device.load();
|
||||
let destination = net_packet.destination();
|
||||
let not_broadcast = !destination.is_broadcast() && !destination.is_multicast() && destination != current_device.broadcast_address;
|
||||
if current_device.virtual_ip() != destination
|
||||
&& not_broadcast && !destination.is_unspecified()
|
||||
&& self.connect_status.load() == ConnectStatus::Connected {
|
||||
if !check_dest(source, current_device.virtual_netmask, current_device.virtual_network) {
|
||||
log::warn!("转发数据,源地址错误:{:?},当前网络:{:?},route_key:{:?}",source,current_device.virtual_network,route_key);
|
||||
return Ok(());
|
||||
}
|
||||
if !check_dest(destination, current_device.virtual_netmask, current_device.virtual_network) {
|
||||
log::warn!("转发数据,目的地址错误:{:?},当前网络:{:?},route_key:{:?}",destination,current_device.virtual_network,route_key);
|
||||
return Ok(());
|
||||
}
|
||||
net_packet.set_ttl(net_packet.ttl() - 1);
|
||||
let ttl = net_packet.ttl();
|
||||
if ttl > 0 {
|
||||
// 转发
|
||||
if let Some(route) = context.route_one(&destination) {
|
||||
if route.metric <= net_packet.ttl() {
|
||||
context.send_by_key(net_packet.buffer(), &route.route_key()).await?;
|
||||
}
|
||||
} else if (ttl > 1 || destination == current_device.virtual_gateway())
|
||||
&& source != current_device.virtual_gateway() {
|
||||
//网关默认要转发一次,生存时间不够的发到网关也会被丢弃
|
||||
context.send_main(net_packet.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
match net_packet.protocol() {
|
||||
Protocol::IpTurn => {
|
||||
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
ip_turn_packet::Protocol::Icmp => {
|
||||
let ipv4 = IpV4Packet::new(net_packet.payload())?;
|
||||
if ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
self.device_writer.write_ipv4(&mut buf[12..])?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
ip_turn_packet::Protocol::Igmp => {
|
||||
if let Some(igmp_server) = &self.igmp_server {
|
||||
let ipv4 = IpV4Packet::new(net_packet.payload())?;
|
||||
if ipv4.protocol() == ipv4::protocol::Protocol::Igmp {
|
||||
igmp_server.handle(ipv4.payload(), source)?;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
ip_turn_packet::Protocol::Ipv4 => {
|
||||
let data = if let Some(payload_len) = self.cipher.decrypt_ipv4(&mut net_packet)? {
|
||||
&mut net_packet.payload_mut()[..payload_len]
|
||||
} else {
|
||||
net_packet.payload_mut()
|
||||
};
|
||||
let mut ipv4 = IpV4Packet::new(data)?;
|
||||
match ipv4.protocol() {
|
||||
ipv4::protocol::Protocol::Igmp => {
|
||||
if let Some(igmp_server) = &self.igmp_server {
|
||||
igmp_server.handle(ipv4.payload(), source)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
ipv4::protocol::Protocol::Icmp => {
|
||||
if ipv4.destination_ip() == destination {
|
||||
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
|
||||
if icmp_packet.kind() == Kind::EchoRequest {
|
||||
//开启ping
|
||||
icmp_packet.set_kind(Kind::EchoReply);
|
||||
icmp_packet.update_checksum();
|
||||
ipv4.set_source_ip(destination);
|
||||
ipv4.set_destination_ip(source);
|
||||
ipv4.update_checksum();
|
||||
net_packet.set_source(destination);
|
||||
net_packet.set_destination(source);
|
||||
//不管加不加密,和接收到的数据长度都一致
|
||||
let _ = self.cipher.encrypt_ipv4(net_packet.payload().len() - 16, &mut net_packet)?;
|
||||
context.send_by_key(net_packet.buffer(), route_key).await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if not_broadcast && ipv4.destination_ip() != destination {
|
||||
if let Some(ip_proxy_map) = &self.ip_proxy_map {
|
||||
if self.out_external_route.allow(&ipv4.destination_ip()) {
|
||||
match ipv4.protocol() {
|
||||
ipv4::protocol::Protocol::Tcp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||
let source_port = tcp_packet.source_port();
|
||||
let dest_port = tcp_packet.destination_port();
|
||||
tcp_packet.set_destination_port(ip_proxy_map.tcp_proxy_port);
|
||||
tcp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
ip_proxy_map.tcp_proxy_map.insert(SocketAddrV4::new(source, source_port), SocketAddrV4::new(dest_ip, dest_port));
|
||||
}
|
||||
ipv4::protocol::Protocol::Udp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let mut udp_packet = packet::udp::udp::UdpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||
let source_port = udp_packet.source_port();
|
||||
let dest_port = udp_packet.destination_port();
|
||||
udp_packet.set_destination_port(ip_proxy_map.udp_proxy_port);
|
||||
udp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
ip_proxy_map.udp_proxy_map.insert(SocketAddrV4::new(source, source_port), SocketAddrV4::new(dest_ip, dest_port));
|
||||
}
|
||||
ipv4::protocol::Protocol::Icmp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?;
|
||||
match icmp_packet.header_other() {
|
||||
HeaderOther::Identifier(id, seq) => {
|
||||
ip_proxy_map.icmp_proxy_map.insert((dest_ip, id, seq), source);
|
||||
ip_proxy_map.send_icmp(ipv4.payload(), &dest_ip)?;
|
||||
}
|
||||
_ => {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//传输协议12字节
|
||||
self.device_writer.write_ipv4(&mut buf[12..])?;
|
||||
return Ok(());
|
||||
}
|
||||
ip_turn_packet::Protocol::Ipv4Broadcast => {
|
||||
//客户端不帮忙转发广播包,所以不会出现这种类型的数据
|
||||
}
|
||||
ip_turn_packet::Protocol::Unknown(_) => {}
|
||||
}
|
||||
}
|
||||
Protocol::Service => {
|
||||
self.service(context, current_device, source, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::Error => {
|
||||
self.error(context, current_device, source, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::Control => {
|
||||
self.control(context, current_device, source, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::OtherTurn => {
|
||||
self.other_turn(context, current_device, source, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::UnKnow(e) => {
|
||||
log::info!("不支持的协议:{}",e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn service(&self, context: &Context, current_device: CurrentDeviceInfo, _source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationRequest => {}
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
let local_port = context.main_local_port()?;
|
||||
let local_ip = nat::local_ip()?;
|
||||
let nat_info = self.nat_test.re_test(Ipv4Addr::from(response.public_ip),
|
||||
response.public_port as u16, local_ip, local_port);
|
||||
context.switch(nat_info.nat_type);
|
||||
let new_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let current_ip = current_device.virtual_ip();
|
||||
if current_ip != new_ip {
|
||||
// ip发生变化
|
||||
log::info!("ip发生变化,old_ip:{:?},new_ip:{:?}",current_ip,new_ip);
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
let old_netmask = current_device.virtual_netmask;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
let old_gateway = current_device.virtual_gateway();
|
||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
self.device_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
|
||||
let new_current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway,
|
||||
virtual_netmask, current_device.connect_server);
|
||||
if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) {
|
||||
log::warn!("替换失败:{:?}",e);
|
||||
}
|
||||
}
|
||||
self.connect_status.store(ConnectStatus::Connected);
|
||||
}
|
||||
service_packet::Protocol::PollDeviceList => {}
|
||||
service_packet::Protocol::PushDeviceList => {
|
||||
let device_list_t = DeviceList::parse_from_bytes(net_packet.payload())?;
|
||||
let ip_list: Vec<PeerDeviceInfo> = device_list_t
|
||||
.device_info_list
|
||||
.into_iter()
|
||||
.map(|info| {
|
||||
PeerDeviceInfo::new(
|
||||
Ipv4Addr::from(info.virtual_ip),
|
||||
info.name,
|
||||
info.device_status as u8,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let route = Route::from(*route_key, 2, 99);
|
||||
for x in &ip_list {
|
||||
if x.status == PeerDeviceStatus::Online {
|
||||
context.add_route_if_absent(x.virtual_ip, route);
|
||||
}
|
||||
}
|
||||
let mut dev = self.device_list.lock();
|
||||
if dev.0 != device_list_t.epoch as u16 {
|
||||
dev.0 = device_list_t.epoch as u16;
|
||||
dev.1 = ip_list;
|
||||
}
|
||||
}
|
||||
service_packet::Protocol::Unknown(u) => {
|
||||
log::warn!("未知服务协议:{}",u);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn error(&self, _context: &Context, current_device: CurrentDeviceInfo, _source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, _route_key: &RouteKey) -> crate::Result<()> {
|
||||
log::info!("current_device:{:?}",current_device);
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
InErrorPacket::TokenError => {
|
||||
return Err(Error::Stop("Token error".to_string()));
|
||||
}
|
||||
InErrorPacket::Disconnect => {
|
||||
{
|
||||
//掉线epoch要归零
|
||||
let mut dev = self.device_list.lock();
|
||||
dev.0 = 0;
|
||||
}
|
||||
|
||||
self.connect_status.store(ConnectStatus::Connecting);
|
||||
self.register.fast_register(current_device.virtual_ip).await?;
|
||||
}
|
||||
InErrorPacket::AddressExhausted => {
|
||||
//地址用尽
|
||||
return Err(Error::Stop("IP address has been exhausted".to_string()));
|
||||
}
|
||||
InErrorPacket::OtherError(e) => {
|
||||
log::error!("OtherError {:?}", e.message());
|
||||
}
|
||||
InErrorPacket::IpAlreadyExists => {
|
||||
log::error!("IpAlreadyExists");
|
||||
}
|
||||
InErrorPacket::InvalidIp => {
|
||||
log::error!("InvalidIp");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn control(&self, context: &Context, current_device: CurrentDeviceInfo, source: Ipv4Addr, mut net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
ControlPacket::PingPacket(_) => {
|
||||
context.update_read_time(&source, route_key);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
net_packet.set_destination(source);
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
context.send_by_key(net_packet.buffer(), route_key).await?;
|
||||
let route = Route::from(*route_key, metric, 99);
|
||||
context.add_route_if_absent(source, route);
|
||||
}
|
||||
ControlPacket::PongPacket(pong_packet) => {
|
||||
context.update_read_time(&source, route_key);
|
||||
let current_time = crate::handle::now_time() as u16;
|
||||
if current_time < pong_packet.time() {
|
||||
return Ok(());
|
||||
}
|
||||
let rt = (current_time - pong_packet.time()) as i64;
|
||||
let route = Route::from(*route_key, metric, rt);
|
||||
context.add_route(source, route);
|
||||
if source == current_device.virtual_gateway() {
|
||||
let epoch = self.device_list.lock().0;
|
||||
if pong_packet.epoch() != epoch {
|
||||
let mut poll_device = NetPacket::new([0; 12])?;
|
||||
poll_device.set_source(current_device.virtual_ip());
|
||||
poll_device.set_destination(source);
|
||||
poll_device.set_version(Version::V1);
|
||||
poll_device.first_set_ttl(MAX_TTL);
|
||||
poll_device.set_protocol(Protocol::Service);
|
||||
poll_device.set_transport_protocol(service_packet::Protocol::PollDeviceList.into());
|
||||
context.send_main(poll_device.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlPacket::PunchRequest => {
|
||||
if self.relay {
|
||||
return Ok(());
|
||||
}
|
||||
//回应
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into());
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
net_packet.set_destination(source);
|
||||
net_packet.first_set_ttl(1);
|
||||
context.send_by_key(net_packet.buffer(), route_key).await?;
|
||||
let route = Route::from(*route_key, metric, 99);
|
||||
context.add_route_if_absent(source, route);
|
||||
}
|
||||
ControlPacket::PunchResponse => {
|
||||
if self.relay {
|
||||
return Ok(());
|
||||
}
|
||||
// log::info!("PunchResponse route_key:{:?}",route_key);
|
||||
let route = Route::from(*route_key, metric, 99);
|
||||
context.add_route_if_absent(source, route);
|
||||
}
|
||||
ControlPacket::AddrRequest => {
|
||||
match route_key.addr.ip() {
|
||||
std::net::IpAddr::V4(ipv4) => {
|
||||
let mut packet = NetPacket::new([0; 12 + 6])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(
|
||||
control_packet::Protocol::AddrResponse.into(),
|
||||
);
|
||||
packet.first_set_ttl(MAX_TTL);
|
||||
packet.set_source(current_device.virtual_ip());
|
||||
packet.set_destination(source);
|
||||
let mut addr_packet = control_packet::AddrPacket::new(packet.payload_mut())?;
|
||||
addr_packet.set_ipv4(ipv4);
|
||||
addr_packet.set_port(route_key.addr.port());
|
||||
context.send_by_key(packet.buffer(), route_key).await?;
|
||||
}
|
||||
std::net::IpAddr::V6(_) => {}
|
||||
}
|
||||
}
|
||||
ControlPacket::AddrResponse(addr_packet) => {
|
||||
if addr_packet.port() != 0
|
||||
&& !addr_packet.ipv4().is_multicast()
|
||||
&& !addr_packet.ipv4().is_broadcast()
|
||||
&& !addr_packet.ipv4().is_unspecified()
|
||||
&& !addr_packet.ipv4().is_loopback()
|
||||
&& !addr_packet.ipv4().is_private() {
|
||||
self.nat_test.update_addr(addr_packet.ipv4(), addr_packet.port())
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn other_turn(&self, context: &Context, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
if self.relay {
|
||||
return Ok(());
|
||||
}
|
||||
match other_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
other_turn_packet::Protocol::Punch => {
|
||||
let punch_info = PunchInfo::parse_from_bytes(net_packet.payload())?;
|
||||
let public_ips = punch_info.public_ip_list.
|
||||
iter().map(|v| { Ipv4Addr::from(v.to_be_bytes()) }).collect();
|
||||
let peer_nat_info = NatInfo::new(public_ips,
|
||||
punch_info.public_port as u16,
|
||||
punch_info.public_port_range as u16,
|
||||
Ipv4Addr::from(punch_info.local_ip.to_be_bytes()),
|
||||
punch_info.local_port as u16,
|
||||
punch_info.nat_type.enum_value_or_default().into());
|
||||
self.peer_nat_info_map.insert(source, peer_nat_info.clone());
|
||||
if !punch_info.reply {
|
||||
let mut punch_reply = PunchInfo::new();
|
||||
punch_reply.reply = true;
|
||||
let nat_info = self.nat_test.nat_info();
|
||||
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|ip| u32::from_be_bytes(ip.octets())).collect();
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.nat_type =
|
||||
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ip.octets());
|
||||
punch_reply.local_port = nat_info.local_port as u32;
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet =
|
||||
NetPacket::new(vec![0u8; 12 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(
|
||||
other_turn_packet::Protocol::Punch.into(),
|
||||
);
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
net_packet.set_destination(source);
|
||||
net_packet.set_payload(&bytes);
|
||||
if !peer_nat_info.local_ip.is_unspecified() && peer_nat_info.local_port != 0 {
|
||||
let mut packet = NetPacket::new([0u8; 12])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.first_set_ttl(1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
packet.set_source(current_device.virtual_ip());
|
||||
packet.set_destination(source);
|
||||
let _ = context.send_main(packet.buffer(), SocketAddr::V4(SocketAddrV4::new(peer_nat_info.local_ip, peer_nat_info.local_port))).await;
|
||||
}
|
||||
if self.punch(source, peer_nat_info).await {
|
||||
context.send_by_key(net_packet.buffer(), route_key).await?;
|
||||
}
|
||||
} else {
|
||||
self.punch(source, peer_nat_info).await;
|
||||
}
|
||||
}
|
||||
other_turn_packet::Protocol::Unknown(e) => {
|
||||
log::warn!("不支持的转发协议 {:?},source:{:?}",e,source);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn punch(&self, peer_ip: Ipv4Addr, peer_nat_info: NatInfo) -> bool {
|
||||
match peer_nat_info.nat_type {
|
||||
NatType::Symmetric => {
|
||||
self.symmetric_sender.try_send((peer_ip, peer_nat_info)).is_ok()
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.cone_sender.try_send((peer_ip, peer_nat_info)).is_ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::time::{Duration, Instant};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use protobuf::Message;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::handle::PeerDeviceInfo;
|
||||
|
||||
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::protocol::{service_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||
|
||||
pub enum ReqEnum {
|
||||
TokenError,
|
||||
AddressExhausted,
|
||||
IpAlreadyExists,
|
||||
InvalidIp,
|
||||
Timeout,
|
||||
ServerError(String),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RegResponse {
|
||||
pub virtual_ip: Ipv4Addr,
|
||||
pub virtual_gateway: Ipv4Addr,
|
||||
pub virtual_netmask: Ipv4Addr,
|
||||
pub epoch: u16,
|
||||
pub device_info_list: Vec<PeerDeviceInfo>,
|
||||
pub public_ip: Ipv4Addr,
|
||||
pub public_port: u16,
|
||||
}
|
||||
|
||||
///向中继服务器注册,token标识一个虚拟网关,device_id防止多次注册时得到的ip不一致
|
||||
pub async fn registration(
|
||||
main_channel: &UdpSocket,
|
||||
main_tcp_channel: Option<&mut TcpStream>,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
ip: Ipv4Addr,
|
||||
) -> Result<RegResponse, ReqEnum> {
|
||||
let request_packet =
|
||||
registration_request_packet(token.clone(), device_id.clone(), name.clone(), ip, false, false).unwrap();
|
||||
let buf = request_packet.buffer();
|
||||
let mut recv_buf = [0u8; 10240];
|
||||
let recv_buf = if let Some(main_tcp_channel) = main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
let len = buf.len();
|
||||
vec[2] = (len >> 8) as u8;
|
||||
vec[3] = (len & 0xFF) as u8;
|
||||
vec[4..].copy_from_slice(buf);
|
||||
if let Err(e) = main_tcp_channel.write_all(&vec).await {
|
||||
return Err(ReqEnum::Other(format!("send error:{}", e)));
|
||||
}
|
||||
if let Err(e) = main_tcp_channel.read_exact(&mut recv_buf[..4]).await {
|
||||
return Err(ReqEnum::Other(format!("read error:{}", e)));
|
||||
}
|
||||
let len = 4 + (((recv_buf[2] as u16) << 8) | recv_buf[3] as u16) as usize;
|
||||
if let Err(e) = main_tcp_channel.read_exact(&mut recv_buf[4..len]).await {
|
||||
return Err(ReqEnum::Other(format!("read error:{}", e)));
|
||||
}
|
||||
&recv_buf[4..len]
|
||||
} else {
|
||||
if let Err(e) = main_channel.send_to(buf, server_address).await {
|
||||
return Err(ReqEnum::Other(format!("send error:{}", e)));
|
||||
}
|
||||
match tokio::time::timeout(Duration::from_millis(300), main_channel.recv_from(&mut recv_buf)).await {
|
||||
Ok(rs) => {
|
||||
match rs {
|
||||
Ok((len, addr)) => {
|
||||
if server_address != addr {
|
||||
return Err(ReqEnum::Other(format!("invalid data,from {}", addr)));
|
||||
}
|
||||
&recv_buf[..len]
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ReqEnum::Other(format!("receiver error:{}", e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(ReqEnum::Timeout);
|
||||
}
|
||||
}
|
||||
};
|
||||
let net_packet = match NetPacket::new(recv_buf) {
|
||||
Ok(net_packet) => {
|
||||
net_packet
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ReqEnum::ServerError(format!("{}", e)));
|
||||
}
|
||||
};
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
match RegistrationResponse::parse_from_bytes(net_packet.payload()) {
|
||||
Ok(response) => {
|
||||
let device_info_list: Vec<PeerDeviceInfo> = response
|
||||
.device_info_list
|
||||
.into_iter()
|
||||
.map(|info| {
|
||||
PeerDeviceInfo::new(
|
||||
Ipv4Addr::from(info.virtual_ip),
|
||||
info.name,
|
||||
info.device_status as u8,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
Ok(RegResponse {
|
||||
virtual_ip: Ipv4Addr::from(response.virtual_ip),
|
||||
virtual_gateway: Ipv4Addr::from(response.virtual_gateway),
|
||||
virtual_netmask: Ipv4Addr::from(response.virtual_netmask),
|
||||
epoch: response.epoch as u16,
|
||||
device_info_list,
|
||||
public_ip: Ipv4Addr::from(response.public_ip),
|
||||
public_port: response.public_port as u16,
|
||||
})
|
||||
}
|
||||
Err(_) => {
|
||||
Err(ReqEnum::ServerError("invalid data".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Err(ReqEnum::ServerError("invalid data".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::Error => {
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload()) {
|
||||
Ok(e) => match e {
|
||||
InErrorPacket::TokenError => Err(ReqEnum::TokenError),
|
||||
InErrorPacket::Disconnect => {
|
||||
Err(ReqEnum::ServerError("disconnect".to_string()))
|
||||
}
|
||||
InErrorPacket::AddressExhausted => {
|
||||
Err(ReqEnum::AddressExhausted)
|
||||
}
|
||||
InErrorPacket::OtherError(e) => match e.message() {
|
||||
Ok(str) => {
|
||||
Err(ReqEnum::ServerError(str))
|
||||
}
|
||||
Err(e) => Err(ReqEnum::Other(format!("{}", e))),
|
||||
},
|
||||
InErrorPacket::IpAlreadyExists => {
|
||||
Err(ReqEnum::IpAlreadyExists)
|
||||
}
|
||||
InErrorPacket::InvalidIp => {
|
||||
Err(ReqEnum::InvalidIp)
|
||||
}
|
||||
},
|
||||
Err(e) => Err(ReqEnum::Other(format!("{}", e))),
|
||||
}
|
||||
}
|
||||
_ => Err(ReqEnum::ServerError("invalid data".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn registration_request_packet(
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
ip: Ipv4Addr,
|
||||
is_fast: bool,
|
||||
allow_ip_change: bool,
|
||||
) -> crate::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = RegistrationRequest::new();
|
||||
request.token = token;
|
||||
request.device_id = device_id;
|
||||
request.name = name;
|
||||
request.virtual_ip = ip.into();
|
||||
request.allow_ip_change = allow_ip_change;
|
||||
request.is_fast = is_fast;
|
||||
request.version = "1.1.2".to_string();
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let buf = vec![0u8; 12 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_payload(&bytes);
|
||||
Ok(net_packet)
|
||||
}
|
||||
|
||||
pub struct Register {
|
||||
sender: ChannelSender,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
time: AtomicCell<Instant>,
|
||||
}
|
||||
|
||||
impl Register {
|
||||
pub fn new(
|
||||
sender: ChannelSender,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
sender,
|
||||
server_address,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
time: AtomicCell::new(Instant::now()),
|
||||
}
|
||||
}
|
||||
pub async fn fast_register(&self, ip: Ipv4Addr) -> io::Result<()> {
|
||||
let last = self.time.load();
|
||||
if last.elapsed() < Duration::from_secs(2)
|
||||
|| self
|
||||
.time
|
||||
.compare_exchange(last, Instant::now())
|
||||
.is_err()
|
||||
{
|
||||
//短时间不重复注册
|
||||
return Ok(());
|
||||
}
|
||||
log::info!("重新连接");
|
||||
let request_packet = registration_request_packet(
|
||||
self.token.clone(),
|
||||
self.device_id.clone(),
|
||||
self.name.clone(),
|
||||
ip,
|
||||
false,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
let buf = request_packet.buffer();
|
||||
self.sender.send_main(buf, self.server_address).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use packet::ip::ipv4::protocol::Protocol;
|
||||
use packet::tcp::tcp::TcpPacket;
|
||||
use packet::udp::udp::UdpPacket;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::{check_dest, CurrentDeviceInfo};
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket, Version};
|
||||
use crate::error::*;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::protocol;
|
||||
use crate::protocol::ip_turn_packet::BroadcastPacketEnd;
|
||||
|
||||
pub mod tun_handler;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
pub mod tap_handler;
|
||||
|
||||
async fn broadcast(sender: &ChannelSender, net_packet: &mut NetPacket<&mut [u8]>, data_len: usize, current_device: &CurrentDeviceInfo) -> Result<()> {
|
||||
let mut peer_ips = Vec::with_capacity(8);
|
||||
let vec = sender.route_table_one();
|
||||
let mut relay_count = 0;
|
||||
const MAX_COUNT: usize = u8::MAX as usize;
|
||||
for (peer_ip, route) in vec {
|
||||
if peer_ip == current_device.virtual_gateway {
|
||||
continue;
|
||||
}
|
||||
if peer_ips.len() == MAX_COUNT {
|
||||
break;
|
||||
}
|
||||
if route.is_p2p()
|
||||
&& sender.send_by_key(&net_packet.buffer()[..data_len], &route.route_key()).await.is_ok() {
|
||||
peer_ips.push(peer_ip);
|
||||
} else {
|
||||
relay_count += 1;
|
||||
}
|
||||
}
|
||||
if relay_count == 0 && !peer_ips.is_empty() && peer_ips.len() != MAX_COUNT {
|
||||
//不需要转发
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if peer_ips.is_empty() {
|
||||
sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?;
|
||||
} else {
|
||||
let end_len = 1 + peer_ips.len() * 4;
|
||||
//剩余的发送到服务端,需要告知哪些已发送过
|
||||
//放在末尾可以减少复制次数
|
||||
let mut broadcast = BroadcastPacketEnd::unchecked(&mut net_packet.buffer_mut()[data_len..data_len + end_len]);
|
||||
broadcast.set_address(&peer_ips)?;
|
||||
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into());
|
||||
sender.send_main(&net_packet.buffer()[..(data_len + end_len)], current_device.connect_server).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn multicast(igmp_server: &IgmpServer, multicast_addr: Ipv4Addr, sender: &ChannelSender, net_packet: &mut NetPacket<&mut [u8]>, data_len: usize, current_device: &CurrentDeviceInfo) -> Result<()> {
|
||||
let mut peer_ips = Vec::with_capacity(8);
|
||||
let vec = sender.route_table_one();
|
||||
let mut relay_count = 0;
|
||||
const MAX_COUNT: usize = u8::MAX as usize;
|
||||
if let Some(members) = igmp_server.load(&multicast_addr) {
|
||||
for (peer_ip, route) in vec {
|
||||
if peer_ip == current_device.virtual_gateway {
|
||||
continue;
|
||||
}
|
||||
let is_send = { members.read().is_send(&peer_ip) };
|
||||
if is_send {
|
||||
if peer_ips.len() == MAX_COUNT {
|
||||
break;
|
||||
}
|
||||
if route.is_p2p()
|
||||
&& sender.send_by_key(&net_packet.buffer()[..data_len], &route.route_key()).await.is_ok() {
|
||||
peer_ips.push(peer_ip);
|
||||
} else {
|
||||
relay_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if relay_count == 0 && !peer_ips.is_empty() && peer_ips.len() != MAX_COUNT {
|
||||
//不需要转发
|
||||
return Ok(());
|
||||
}
|
||||
if peer_ips.is_empty() {
|
||||
sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?;
|
||||
} else {
|
||||
let end_len = 1 + peer_ips.len() * 4;
|
||||
//剩余的发送到服务端,需要告知哪些已发送过
|
||||
//放在末尾可以减少复制次数
|
||||
let mut broadcast = BroadcastPacketEnd::unchecked(&mut net_packet.buffer_mut()[data_len..data_len + end_len]);
|
||||
broadcast.set_address(&peer_ips)?;
|
||||
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into());
|
||||
sender.send_main(&net_packet.buffer()[..(data_len + end_len)], current_device.connect_server).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 实现一个原地发送,必须保证是如下结构
|
||||
/// |12字节开头|ip报文|至少1024字节+12字节结尾|
|
||||
///
|
||||
#[inline]
|
||||
pub async fn base_handle(sender: &ChannelSender, buf: &mut [u8],
|
||||
mut data_len: usize,//数据总长度=ip长度+12
|
||||
igmp_server: &Option<IgmpServer>,
|
||||
current_device: CurrentDeviceInfo,
|
||||
ip_route: &Option<ExternalRoute>, proxy_map: &Option<IpProxyMap>, cipher: &Cipher) -> Result<()> {
|
||||
let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?;
|
||||
let protocol = ipv4_packet.protocol();
|
||||
let ip_head_len = ipv4_packet.header_len() as usize * 4;
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
let mut dest_ip = ipv4_packet.destination_ip();
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(protocol::Protocol::IpTurn);
|
||||
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
|
||||
net_packet.first_set_ttl(3);
|
||||
net_packet.set_source(src_ip);
|
||||
net_packet.set_destination(dest_ip);
|
||||
if dest_ip == current_device.virtual_gateway {
|
||||
if protocol == Protocol::Icmp {
|
||||
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Icmp.into());
|
||||
//发送到服务端的不加密
|
||||
sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if dest_ip.is_multicast() {
|
||||
match protocol {
|
||||
Protocol::Igmp => {
|
||||
if igmp_server.is_some() {
|
||||
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Igmp.into());
|
||||
//发送到服务端
|
||||
net_packet.set_destination(current_device.virtual_gateway);
|
||||
sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
Protocol::Udp => {
|
||||
if let Some(igmp_server) = igmp_server {
|
||||
if let Some(len) = cipher.encrypt_ipv4(data_len - 12, &mut net_packet)? {
|
||||
data_len = 12 + len;
|
||||
}
|
||||
multicast(igmp_server, dest_ip, sender, &mut net_packet, data_len, ¤t_device).await?;
|
||||
return Ok(());
|
||||
} else {
|
||||
//当广播
|
||||
dest_ip = Ipv4Addr::BROADCAST;
|
||||
net_packet.set_destination(dest_ip);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
if dest_ip.is_broadcast() || current_device.broadcast_address == dest_ip {
|
||||
// 广播 发送到直连目标
|
||||
if Protocol::Udp == protocol {
|
||||
if let Some(len) = cipher.encrypt_ipv4(data_len - 12, &mut net_packet)? {
|
||||
data_len = 12 + len;
|
||||
}
|
||||
broadcast(sender, &mut net_packet, data_len, ¤t_device).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) {
|
||||
if let Some(ip_route) = ip_route {
|
||||
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
||||
//路由的目标不能是自己
|
||||
if r_dest_ip == src_ip {
|
||||
return Ok(());
|
||||
}
|
||||
//需要修改目的地址
|
||||
dest_ip = r_dest_ip;
|
||||
net_packet.set_destination(r_dest_ip);
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
} else if let Some(proxy_map) = proxy_map {
|
||||
match protocol {
|
||||
Protocol::Tcp => {
|
||||
let dest_addr = {
|
||||
let tcp_packet = TcpPacket::new(src_ip, dest_ip, &mut net_packet.buffer_mut()[12 + ip_head_len..data_len])?;
|
||||
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.tcp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value();
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut tcp_packet = TcpPacket::new(source_ip, dest_ip, &mut net_packet.buffer_mut()[12 + ip_head_len..data_len])?;
|
||||
tcp_packet.set_source_port(source_addr.port());
|
||||
tcp_packet.update_checksum();
|
||||
let mut ipv4_packet = IpV4Packet::new(&mut net_packet.buffer_mut()[12..data_len])?;
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}
|
||||
}
|
||||
Protocol::Udp => {
|
||||
let dest_addr = {
|
||||
let udp_packet = UdpPacket::new(src_ip, dest_ip, &mut net_packet.buffer_mut()[12 + ip_head_len..data_len])?;
|
||||
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.udp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value();
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut udp_packet = UdpPacket::new(source_ip, dest_ip, &mut net_packet.buffer_mut()[12 + ip_head_len..data_len])?;
|
||||
udp_packet.set_source_port(source_addr.port());
|
||||
udp_packet.update_checksum();
|
||||
let mut ipv4_packet = IpV4Packet::new(&mut net_packet.buffer_mut()[12..data_len])?;
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if let Some(len) = cipher.encrypt_ipv4(data_len - 12, &mut net_packet)? {
|
||||
data_len = 12 + len;
|
||||
}
|
||||
|
||||
//优先发到直连到地址
|
||||
if sender.send_by_id(&net_packet.buffer()[..data_len], &dest_ip).await.is_err() {
|
||||
sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
use std::{io, thread};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use packet::arp::arp::ArpPacket;
|
||||
use packet::ethernet;
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
use packet::icmp::icmp::IcmpPacket;
|
||||
use packet::icmp::Kind;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntWorker;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceWriter};
|
||||
|
||||
pub fn start(worker: VntWorker, sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
cipher: Cipher) {
|
||||
thread::Builder::new().name("tap_handler".into()).spawn(move || {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all().build().unwrap()
|
||||
.block_on(async move {
|
||||
if let Err(e) = start_(sender, device_reader,
|
||||
device_writer, igmp_server,
|
||||
current_device, ip_route, ip_proxy_map, cipher).await {
|
||||
log::warn!("tap:{:?}",e);
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
async fn start_(sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
cipher: Cipher) -> io::Result<()> {
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
//ip拆包了会直接丢弃?
|
||||
let len = device_reader.read(&mut buf)?;
|
||||
if let Err(e) = handle(&mut buf, len, &igmp_server, ¤t_device, &device_writer, &sender, &ip_route, &ip_proxy_map, &cipher).await {
|
||||
log::warn!("tap handle{:?}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle(buf: &mut [u8], len: usize, igmp_server: &Option<IgmpServer>, current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||
device_writer: &DeviceWriter, sender: &ChannelSender, ip_route: &Option<ExternalRoute>, proxy_map: &Option<IpProxyMap>, cipher: &Cipher) -> crate::Result<()> {
|
||||
let mut ethernet_packet = EthernetPacket::new(&mut buf[..len])?;
|
||||
let current_device = current_device.load();
|
||||
match ethernet_packet.protocol() {
|
||||
ethernet::protocol::Protocol::Arp => {
|
||||
let mut out_ethernet_packet = EthernetPacket::unchecked(ethernet_packet.buffer.to_vec());
|
||||
let arp_packet = ArpPacket::unchecked(ethernet_packet.payload());
|
||||
let mut out_arp_packet = ArpPacket::unchecked(out_ethernet_packet.payload_mut());
|
||||
let sender_h = arp_packet.sender_hardware_addr();
|
||||
let sender_p = arp_packet.sender_protocol_addr();
|
||||
let target_p = arp_packet.target_protocol_addr();
|
||||
if target_p == &[0, 0, 0, 0] || sender_p == &[0, 0, 0, 0] || target_p == sender_p {
|
||||
return Ok(());
|
||||
}
|
||||
//回复一个虚假的MAC地址
|
||||
out_arp_packet.set_sender_hardware_addr(&[target_p[0], target_p[1], target_p[2], target_p[3], !sender_h[5], 234]);
|
||||
out_arp_packet.set_sender_protocol_addr(target_p);
|
||||
out_arp_packet.set_target_hardware_addr(sender_h);
|
||||
out_arp_packet.set_target_protocol_addr(sender_p);
|
||||
out_arp_packet.set_op_code(2);
|
||||
out_ethernet_packet.set_source(&[target_p[0], target_p[1], target_p[2], target_p[3], !sender_h[5], 234]);
|
||||
out_ethernet_packet.set_destination(sender_h);
|
||||
device_writer.write_ethernet_tap(&out_ethernet_packet.buffer)?;
|
||||
}
|
||||
ethernet::protocol::Protocol::Ipv4 => {
|
||||
let mut ipv4_packet = IpV4Packet::unchecked(ethernet_packet.payload_mut());
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
if src_ip != current_device.virtual_ip() {
|
||||
return Ok(());
|
||||
}
|
||||
let dest_ip = ipv4_packet.destination_ip();
|
||||
let protocol = ipv4_packet.protocol();
|
||||
if src_ip == dest_ip {
|
||||
if protocol == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
ipv4_packet.set_source_ip(dest_ip);
|
||||
ipv4_packet.set_destination_ip(src_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
let source = ethernet_packet.source().to_vec();
|
||||
let dest = ethernet_packet.destination().to_vec();
|
||||
ethernet_packet.set_source(&dest);
|
||||
ethernet_packet.set_destination(&source);
|
||||
device_writer.write_ethernet_tap(ðernet_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// 以太网帧头部14字节,预留12字节
|
||||
return crate::handle::tun_tap::base_handle(sender, &mut buf[2..], len - 2, igmp_server, current_device,
|
||||
ip_route, proxy_map, cipher).await;
|
||||
}
|
||||
_ => {
|
||||
// log::warn!("不支持的二层协议:{:?}",p)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
use std::{io, thread};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use packet::icmp::Kind;
|
||||
use packet::icmp::icmp::IcmpPacket;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntWorker;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceWriter};
|
||||
|
||||
fn icmp(device_writer: &DeviceWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
|
||||
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
let src = ipv4_packet.source_ip();
|
||||
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||
ipv4_packet.set_destination_ip(src);
|
||||
ipv4_packet.update_checksum();
|
||||
device_writer.write_ipv4_tun(ipv4_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 接收tun数据,并且转发到udp上
|
||||
#[inline]
|
||||
async fn handle(sender: &ChannelSender, data: &mut [u8], len: usize, device_writer: &DeviceWriter, igmp_server: &Option<IgmpServer>, current_device: CurrentDeviceInfo,
|
||||
ip_route: &Option<ExternalRoute>, proxy_map: &Option<IpProxyMap>, cipher: &Cipher) -> Result<()> {
|
||||
let ipv4_packet = if let Ok(ipv4_packet) = IpV4Packet::new(&mut data[12..len]) {
|
||||
ipv4_packet
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
let dest_ip = ipv4_packet.destination_ip();
|
||||
if src_ip != current_device.virtual_ip() {
|
||||
return Ok(());
|
||||
}
|
||||
if src_ip == dest_ip {
|
||||
return icmp(&device_writer, ipv4_packet);
|
||||
}
|
||||
return crate::handle::tun_tap::base_handle(sender, data, len, igmp_server, current_device, ip_route, proxy_map, cipher).await;
|
||||
}
|
||||
|
||||
pub fn start(worker: VntWorker, sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
cipher: Cipher) {
|
||||
thread::Builder::new().name("tun_handler".into()).spawn(move || {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all().build().unwrap()
|
||||
.block_on(async move {
|
||||
if let Err(e) = start_(sender, device_reader, &device_writer, igmp_server, current_device, ip_route, ip_proxy_map, cipher).await {
|
||||
log::warn!("stop:{}",e);
|
||||
}
|
||||
let _ = device_writer.close();
|
||||
worker.stop_all();
|
||||
})
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
async fn start_(sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: &DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
cipher: Cipher) -> io::Result<()> {
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
if sender.is_close() {
|
||||
return Ok(());
|
||||
}
|
||||
let len = device_reader.read(&mut buf[12..])? + 12;
|
||||
#[cfg(any(target_os = "macos"))]
|
||||
let mut buf = &mut buf[4..];
|
||||
match handle(&sender, &mut buf, len, device_writer, &igmp_server, current_device.load(), &ip_route, &ip_proxy_map, &cipher).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use parking_lot::RwLock;
|
||||
use packet::igmp::igmp_v2::IgmpV2Packet;
|
||||
use packet::igmp::igmp_v3::{IgmpV3QueryPacket, IgmpV3RecordType, IgmpV3ReportPacket};
|
||||
use packet::igmp::IgmpType;
|
||||
use packet::ip::ipv4::protocol::Protocol;
|
||||
use crate::tun_tap_device::DeviceWriter;
|
||||
|
||||
//1. 定时发送query,启动时20秒一次,连发3次,之后8分钟一次
|
||||
//2. 接收网关的igmp report 维护组播源信息
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Multicast {
|
||||
//成员虚拟ip
|
||||
members: HashMap<Ipv4Addr, Instant>,
|
||||
//是否是过滤模式
|
||||
//成员过滤或包含的源ip
|
||||
map: HashMap<Ipv4Addr, (bool, HashSet<Ipv4Addr>)>,
|
||||
}
|
||||
|
||||
impl Multicast {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
members: Default::default(),
|
||||
map: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn is_send(&self, ip: &Ipv4Addr) -> bool {
|
||||
if self.members.contains_key(ip) {
|
||||
if let Some((is_include, set)) = self.map.get(ip) {
|
||||
if *is_include {
|
||||
set.contains(ip)
|
||||
} else {
|
||||
!set.contains(ip)
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IgmpServer {
|
||||
multicast: Arc<SkipMap<Ipv4Addr, Arc<RwLock<Multicast>>>>,
|
||||
}
|
||||
|
||||
impl IgmpServer {
|
||||
pub fn new(device_writer: DeviceWriter) -> Self {
|
||||
let multicast: Arc<SkipMap<Ipv4Addr, Arc<RwLock<Multicast>>>> = Arc::new(SkipMap::new());
|
||||
std::thread::spawn(move || {
|
||||
//预留以太网帧头和ip头
|
||||
let mut buf = [0; 14 + 24 + 12];
|
||||
let dest = Ipv4Addr::new(224, 0, 0, 1);
|
||||
let src = Ipv4Addr::new(10, 26, 0, 1);
|
||||
{
|
||||
let buf = &mut buf[14..];
|
||||
let len = buf.len();
|
||||
// ipv4 头部20字节
|
||||
buf[0] = 0b0100_0110;
|
||||
//写入总长度
|
||||
buf[2..4].copy_from_slice(&(len as u16).to_be_bytes());
|
||||
//ttl
|
||||
buf[8] = 1;
|
||||
buf[20] = 0x94;
|
||||
buf[21] = 0x04;
|
||||
let mut ipv4 = packet::ip::ipv4::packet::IpV4Packet::unchecked(buf);
|
||||
ipv4.set_flags(2);
|
||||
ipv4.set_protocol(Protocol::Igmp);
|
||||
ipv4.set_source_ip(src);
|
||||
ipv4.set_destination_ip(dest);
|
||||
ipv4.update_checksum();
|
||||
}
|
||||
{
|
||||
let mut igmp_query = IgmpV3QueryPacket::unchecked(&mut buf[14 + 24..]);
|
||||
igmp_query.set_igmp_type();
|
||||
igmp_query.set_max_resp_code(50);
|
||||
igmp_query.set_group_address(Ipv4Addr::UNSPECIFIED);
|
||||
igmp_query.set_qrv(2);
|
||||
igmp_query.set_qqic(10);
|
||||
igmp_query.update_checksum();
|
||||
}
|
||||
loop {
|
||||
let _ = device_writer.write_ipv4(&mut buf);
|
||||
std::thread::sleep(Duration::from_secs(20))
|
||||
}
|
||||
});
|
||||
Self {
|
||||
multicast,
|
||||
}
|
||||
}
|
||||
pub fn load(&self, multicast_addr: &Ipv4Addr) -> Option<Arc<RwLock<Multicast>>> {
|
||||
if let Some(entry) = self.multicast.get(multicast_addr) {
|
||||
Some(entry.value().clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn handle(&self, buf: &[u8], source: Ipv4Addr) -> crate::Result<()> {
|
||||
for x in self.multicast.iter() {
|
||||
let mut list = Vec::new();
|
||||
let mut write_guard = x.value().write();
|
||||
for (ip, time) in &write_guard.members {
|
||||
if time.elapsed() > Duration::from_secs(30) {
|
||||
list.push(*ip);
|
||||
}
|
||||
}
|
||||
for ip in list {
|
||||
write_guard.members.remove(&ip);
|
||||
write_guard.map.remove(&ip);
|
||||
}
|
||||
}
|
||||
match IgmpType::from(buf[0]) {
|
||||
IgmpType::Query => {}
|
||||
IgmpType::ReportV1 | IgmpType::ReportV2 => {
|
||||
//加入组播,v1和v2差不多
|
||||
let report = IgmpV2Packet::new(buf)?;
|
||||
let multicast_addr = report.group_address();
|
||||
if !multicast_addr.is_multicast() {
|
||||
return Ok(());
|
||||
}
|
||||
let multi = self.multicast.get_or_insert_with(multicast_addr, || {
|
||||
Arc::new(RwLock::new(Multicast::new()))
|
||||
});
|
||||
let mut guard = multi.value().write();
|
||||
guard.members.insert(source, Instant::now());
|
||||
}
|
||||
IgmpType::LeaveV2 => {
|
||||
//退出组播
|
||||
let leave = IgmpV2Packet::new(buf)?;
|
||||
let multicast_addr = leave.group_address();
|
||||
if !multicast_addr.is_multicast() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(entry) = self.multicast.get(&multicast_addr) {
|
||||
let mut guard = entry.value().write();
|
||||
guard.map.remove(&source);
|
||||
guard.members.remove(&source);
|
||||
}
|
||||
}
|
||||
IgmpType::ReportV3 => {
|
||||
let report = IgmpV3ReportPacket::new(buf)?;
|
||||
if let Some(group_records) = report.group_records() {
|
||||
for group_record in group_records {
|
||||
let multicast_addr = group_record.multicast_address();
|
||||
if !multicast_addr.is_multicast() {
|
||||
return Ok(());
|
||||
}
|
||||
let multi = self.multicast.get_or_insert_with(multicast_addr, || {
|
||||
Arc::new(RwLock::new(Multicast::new()))
|
||||
});
|
||||
let mut guard = multi.value().write();
|
||||
|
||||
match group_record.record_type() {
|
||||
IgmpV3RecordType::ModeIsInclude | IgmpV3RecordType::ChangeToIncludeMode => {
|
||||
match group_record.source_addresses() {
|
||||
None => {
|
||||
//不接收所有
|
||||
guard.members.remove(&source);
|
||||
guard.map.remove(&source);
|
||||
}
|
||||
Some(src) => {
|
||||
guard.members.insert(source, Instant::now());
|
||||
guard.map.insert(source, (true, HashSet::from_iter(src)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IgmpV3RecordType::ModeIsExclude | IgmpV3RecordType::ChangeToExcludeMode => {
|
||||
match group_record.source_addresses() {
|
||||
None => {
|
||||
//接收所有
|
||||
guard.members.insert(source, Instant::now());
|
||||
guard.map.remove(&source);
|
||||
}
|
||||
Some(src) => {
|
||||
guard.members.insert(source, Instant::now());
|
||||
guard.map.insert(source, (false, HashSet::from_iter(src)));
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpV3RecordType::AllowNewSources => {
|
||||
//在已有源的基础上,接收目标源,如果是排除模式,则删除;是包含模式则添加
|
||||
match group_record.source_addresses() {
|
||||
None => {}
|
||||
Some(src) => {
|
||||
match guard.map.get_mut(&source) {
|
||||
None => {}
|
||||
Some((is_include, set)) => {
|
||||
for ip in src {
|
||||
if *is_include {
|
||||
set.insert(ip);
|
||||
} else {
|
||||
set.remove(&ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpV3RecordType::BlockOldSources => {
|
||||
//在已有源的基础上,不接收目标源
|
||||
match group_record.source_addresses() {
|
||||
None => {}
|
||||
Some(src) => {
|
||||
match guard.map.get_mut(&source) {
|
||||
None => {}
|
||||
Some((is_include, set)) => {
|
||||
for ip in src {
|
||||
if *is_include {
|
||||
set.remove(&ip);
|
||||
} else {
|
||||
set.insert(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpV3RecordType::Unknown(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpType::Unknown(_) => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,15 @@ use std::io;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use socket2::{Domain, SockAddr, Socket, Type};
|
||||
use p2p_channel::channel::sender::Sender;
|
||||
|
||||
use packet::icmp::icmp;
|
||||
use packet::icmp::icmp::HeaderOther;
|
||||
use packet::ip::ipv4;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
||||
|
||||
@@ -18,12 +18,12 @@ pub struct IcmpProxy {
|
||||
icmp_socket: Arc<Socket>,
|
||||
// 对端-> 真实来源
|
||||
icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||
sender: Sender<Ipv4Addr>,
|
||||
sender: ChannelSender,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
}
|
||||
|
||||
impl IcmpProxy {
|
||||
pub fn new(addr: SocketAddrV4, icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>, sender: Sender<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<IcmpProxy> {
|
||||
pub fn new(addr: SocketAddrV4, icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>, sender: ChannelSender, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<IcmpProxy> {
|
||||
let icmp_socket = Arc::new(Socket::new(Domain::IPV4, Type::RAW, Some(socket2::Protocol::ICMPV4))?);
|
||||
icmp_socket.bind(&SockAddr::from(addr))?;
|
||||
// // 设置 SIO_RCVALL 参数
|
||||
@@ -57,7 +57,7 @@ impl IcmpProxy {
|
||||
current_device,
|
||||
})
|
||||
}
|
||||
pub fn icmp_socket(&self) ->Arc<Socket>{
|
||||
pub fn icmp_socket(&self) -> Arc<Socket> {
|
||||
self.icmp_socket.clone()
|
||||
}
|
||||
pub fn start(self) {
|
||||
@@ -66,9 +66,9 @@ impl IcmpProxy {
|
||||
unsafe { std::mem::transmute(&mut buf[..]) };
|
||||
let mut net_packet = NetPacket::new([0u8; 4 + 8 + 1500]).unwrap();
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||
net_packet.set_ttl(MAX_TTL);
|
||||
net_packet.set_protocol(Protocol::IpTurn);
|
||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Icmp.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
loop {
|
||||
match self.recv(data) {
|
||||
Ok((len, peer_ip)) => {
|
||||
@@ -85,12 +85,16 @@ impl IcmpProxy {
|
||||
let dest_ip = *entry.value();
|
||||
ipv4_packet.set_destination_ip(dest_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
let virtual_ip = self.current_device.load().virtual_ip();
|
||||
let current_device = self.current_device.load();
|
||||
let virtual_ip = current_device.virtual_ip();
|
||||
let connect_server = current_device.connect_server;
|
||||
net_packet.set_source(virtual_ip);
|
||||
net_packet.set_destination(dest_ip);
|
||||
let data_len = ipv4_packet.buffer.len();
|
||||
net_packet.set_payload(ipv4_packet.buffer);
|
||||
let _ = self.sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip);
|
||||
if self.sender.try_send_by_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip).is_err() {
|
||||
let _ = self.sender.try_send_main(&net_packet.buffer()[..(12 + data_len)], connect_server);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -0,0 +1,68 @@
|
||||
use std::{io, thread};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use crossbeam_skiplist::SkipMap;
|
||||
use socket2::{SockAddr, Socket};
|
||||
use tokio::net::{TcpListener, UdpSocket};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::ip_proxy::icmp_proxy::IcmpProxy;
|
||||
use crate::ip_proxy::tcp_proxy::TcpProxy;
|
||||
use crate::ip_proxy::udp_proxy::UdpProxy;
|
||||
|
||||
pub mod icmp_proxy;
|
||||
pub mod tcp_proxy;
|
||||
pub mod udp_proxy;
|
||||
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
Icmp,
|
||||
Tcp,
|
||||
Udp,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IpProxyMap {
|
||||
pub(crate) tcp_proxy_port: u16,
|
||||
pub(crate) udp_proxy_port: u16,
|
||||
//真实源地址 -> 目的地址
|
||||
pub(crate) tcp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
pub(crate) udp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
// icmp用Identifier来区分,没有Identifier的一律不转发
|
||||
pub(crate) icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||
icmp_socket: Arc<Socket>,
|
||||
}
|
||||
|
||||
impl IpProxyMap {
|
||||
pub fn send_icmp(&self, buf: &[u8], dest: &Ipv4Addr) -> io::Result<usize> {
|
||||
self.icmp_socket.send_to(buf, &SockAddr::from(SocketAddrV4::new(*dest, 0)))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init_proxy(sender: ChannelSender, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<(TcpProxy, UdpProxy, IpProxyMap)> {
|
||||
let tcp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>> = Arc::new(SkipMap::new());
|
||||
let udp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>> = Arc::new(SkipMap::new());
|
||||
let icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>> = Arc::new(SkipMap::new());
|
||||
let tcp_listener = TcpListener::bind("0.0.0.0:0").await?;
|
||||
let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
let tcp_proxy_port = tcp_listener.local_addr()?.port();
|
||||
let udp_proxy_port = udp_socket.local_addr()?.port();
|
||||
let tcp_proxy = TcpProxy::new(tcp_listener, tcp_proxy_map.clone());
|
||||
let udp_proxy = UdpProxy::new(udp_socket, udp_proxy_map.clone());
|
||||
let addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0);
|
||||
let icmp_proxy = IcmpProxy::new(addr, icmp_proxy_map.clone(), sender.clone(), current_device.clone())?;
|
||||
let icmp_socket = icmp_proxy.icmp_socket();
|
||||
thread::spawn(move || {
|
||||
icmp_proxy.start();
|
||||
});
|
||||
|
||||
Ok((tcp_proxy, udp_proxy, IpProxyMap {
|
||||
tcp_proxy_port,
|
||||
udp_proxy_port,
|
||||
tcp_proxy_map,
|
||||
udp_proxy_map,
|
||||
icmp_proxy_map,
|
||||
icmp_socket,
|
||||
}))
|
||||
}
|
||||
@@ -6,12 +6,11 @@ use tokio::net::{TcpListener, TcpStream};
|
||||
|
||||
pub struct TcpProxy {
|
||||
tcp_listener: TcpListener,
|
||||
// todo 怎么过期
|
||||
map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
}
|
||||
|
||||
impl TcpProxy {
|
||||
pub fn new(tcp_listener: TcpListener, map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>) -> Self {
|
||||
pub fn new(tcp_listener: TcpListener, map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>) -> Self {
|
||||
Self {
|
||||
tcp_listener,
|
||||
map,
|
||||
@@ -26,21 +25,23 @@ impl TcpProxy {
|
||||
match sender_addr {
|
||||
SocketAddr::V4(sender_addr) => {
|
||||
if let Some(entry) = map.get(&sender_addr) {
|
||||
let (src_addr, dest_addr) = *entry.value();
|
||||
let dest_addr = *entry.value();
|
||||
let peer_tcp_stream = match TcpStream::connect(dest_addr).await {
|
||||
Ok(peer_tcp_stream) => {peer_tcp_stream}
|
||||
Err(e) => {
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let map = map.clone();
|
||||
tokio::spawn(async move {
|
||||
match proxy(tcp_stream, peer_tcp_stream).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
}
|
||||
}
|
||||
map.remove(&sender_addr);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,11 @@ use tokio::net::UdpSocket;
|
||||
/// 一个udp代理,作用是利用系统协议栈,将udp数据报解析出来再转发到目的地址
|
||||
pub struct UdpProxy {
|
||||
udp_socket: Arc<UdpSocket>,
|
||||
// todo 过期处理
|
||||
map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
}
|
||||
|
||||
impl UdpProxy {
|
||||
pub fn new(udp_socket: UdpSocket, map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>) -> Self {
|
||||
pub fn new(udp_socket: UdpSocket, map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>) -> Self {
|
||||
let udp_socket = Arc::new(udp_socket);
|
||||
Self {
|
||||
udp_socket,
|
||||
@@ -49,11 +48,11 @@ impl UdpProxy {
|
||||
}
|
||||
}
|
||||
|
||||
async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<SocketAddrV4, Arc<UdpSocket>>>, map: &Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>, udp_socket: &Arc<UdpSocket>) -> io::Result<()> {
|
||||
async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<SocketAddrV4, Arc<UdpSocket>>>, map: &Arc<SkipMap<SocketAddrV4, SocketAddrV4>>, udp_socket: &Arc<UdpSocket>) -> io::Result<()> {
|
||||
if let Some(entry) = inner_map.get(&sender_addr) {
|
||||
entry.value().send(buf).await?;
|
||||
} else if let Some(entry) = map.get(&sender_addr) {
|
||||
let (src_addr, dest_addr) = *entry.value();
|
||||
let dest_addr = *entry.value();
|
||||
let peer_udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
peer_udp_socket.connect(dest_addr).await?;
|
||||
peer_udp_socket.send(buf).await?;
|
||||
@@ -61,6 +60,7 @@ async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<S
|
||||
let inner_map = inner_map.clone();
|
||||
inner_map.insert(sender_addr, peer_udp_socket.clone());
|
||||
let udp_socket = udp_socket.clone();
|
||||
let map = map.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut buf = [0u8; 65536];
|
||||
loop {
|
||||
@@ -71,25 +71,26 @@ async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<S
|
||||
match udp_socket.send_to(&buf[..len], sender_addr).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
//超时关闭
|
||||
log::warn!("udp代理超时关闭,来源:{},目标:{}",src_addr,dest_addr);
|
||||
log::warn!("udp代理超时关闭,来源:{},目标:{}",sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
inner_map.remove(&sender_addr);
|
||||
map.remove(&sender_addr);
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
@@ -1,7 +1,5 @@
|
||||
use crate::error::Error;
|
||||
|
||||
pub use p2p_channel::channel::{Route, RouteKey};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub mod error;
|
||||
@@ -9,8 +7,11 @@ pub mod handle;
|
||||
pub mod nat;
|
||||
pub mod proto;
|
||||
pub mod protocol;
|
||||
pub mod tun_device;
|
||||
pub mod tap_device;
|
||||
pub mod ip_proxy;
|
||||
pub mod external_route;
|
||||
pub mod igmp_server;
|
||||
pub mod tun_tap_device;
|
||||
pub mod core;
|
||||
pub mod channel;
|
||||
pub mod util;
|
||||
pub mod cipher;
|
||||
@@ -1,23 +1,9 @@
|
||||
use p2p_channel::punch::NatType;
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
use crate::channel::punch::NatType;
|
||||
|
||||
// #[derive(Debug, Copy, Clone, PartialEq)]
|
||||
// pub enum NatType {
|
||||
// Symmetric,
|
||||
// Cone,
|
||||
// }
|
||||
//
|
||||
// impl Into<u8> for NatType {
|
||||
// fn into(self) -> u8 {
|
||||
// match self {
|
||||
// NatType::Symmetric => 0,
|
||||
// NatType::Cone => 1,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// 返回所有公网ip和端口变化范围
|
||||
pub fn public_ip_list(addrs: &Vec<SocketAddr>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
@@ -72,7 +58,6 @@ pub fn public_ip_list_(
|
||||
udp: &UdpSocket,
|
||||
addrs: &Vec<SocketAddr>,
|
||||
) -> io::Result<(HashSet<Ipv4Addr>, u16, u16)> {
|
||||
// println!("local port {:?}", udp.local_addr().unwrap().port());
|
||||
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
|
||||
let mut buf = [0u8; 128];
|
||||
for addr in addrs {
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::proto::message::PunchNatType;
|
||||
use p2p_channel::punch::{NatInfo, NatType};
|
||||
use parking_lot::Mutex;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
@@ -8,12 +7,20 @@ use std::sync::Arc;
|
||||
pub mod check;
|
||||
|
||||
use std::net::UdpSocket;
|
||||
use crate::channel::punch::{NatInfo, NatType};
|
||||
|
||||
pub fn local_ip() -> io::Result<IpAddr> {
|
||||
pub fn local_ip() -> io::Result<Ipv4Addr> {
|
||||
let socket = UdpSocket::bind("0.0.0.0:0")?;
|
||||
socket.connect("8.8.8.8:80")?;
|
||||
let addr = socket.local_addr()?;
|
||||
Ok(addr.ip())
|
||||
match addr.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
Ok(ip)
|
||||
}
|
||||
IpAddr::V6(_) => {
|
||||
Ok(Ipv4Addr::UNSPECIFIED)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -45,7 +52,7 @@ impl NatTest {
|
||||
nat_test_server: Vec<SocketAddr>,
|
||||
public_ip: Ipv4Addr,
|
||||
public_port: u16,
|
||||
local_ip: IpAddr,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
) -> NatTest {
|
||||
let info = NatTest::re_test_(
|
||||
@@ -63,11 +70,18 @@ impl NatTest {
|
||||
pub fn nat_info(&self) -> NatInfo {
|
||||
self.info.lock().clone()
|
||||
}
|
||||
pub fn update_addr(&self, ip: Ipv4Addr, port: u16) {
|
||||
let mut guard = self.info.lock();
|
||||
guard.public_port = port;
|
||||
if !guard.public_ips.contains(&ip) {
|
||||
guard.public_ips.push(ip);
|
||||
}
|
||||
}
|
||||
pub fn re_test(
|
||||
&self,
|
||||
public_ip: Ipv4Addr,
|
||||
public_port: u16,
|
||||
local_ip: IpAddr,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
) -> NatInfo {
|
||||
let info = NatTest::re_test_(
|
||||
@@ -84,16 +98,16 @@ impl NatTest {
|
||||
nat_test_server: &Vec<SocketAddr>,
|
||||
public_ip: Ipv4Addr,
|
||||
public_port: u16,
|
||||
local_ip: IpAddr,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
) -> NatInfo {
|
||||
return match check::public_ip_list(nat_test_server) {
|
||||
Ok((nat_type, ips, port_range)) => {
|
||||
let mut public_ips = Vec::new();
|
||||
public_ips.push(IpAddr::from(public_ip));
|
||||
public_ips.push(Ipv4Addr::from(public_ip));
|
||||
for ip in ips {
|
||||
if ip != public_ip {
|
||||
public_ips.push(IpAddr::from(ip));
|
||||
public_ips.push(ip);
|
||||
}
|
||||
}
|
||||
NatInfo::new(
|
||||
@@ -108,7 +122,7 @@ impl NatTest {
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
NatInfo::new(
|
||||
vec![IpAddr::from(public_ip)],
|
||||
vec![public_ip],
|
||||
public_port,
|
||||
0,
|
||||
local_ip,
|
||||
@@ -37,6 +37,12 @@ pub struct RegistrationRequest {
|
||||
pub name: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.is_fast)
|
||||
pub is_fast: bool,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.version)
|
||||
pub version: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.allow_ip_change)
|
||||
pub allow_ip_change: bool,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationRequest.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
@@ -54,7 +60,7 @@ impl RegistrationRequest {
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(4);
|
||||
let mut fields = ::std::vec::Vec::with_capacity(7);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"token",
|
||||
@@ -76,6 +82,21 @@ impl RegistrationRequest {
|
||||
|m: &RegistrationRequest| { &m.is_fast },
|
||||
|m: &mut RegistrationRequest| { &mut m.is_fast },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"version",
|
||||
|m: &RegistrationRequest| { &m.version },
|
||||
|m: &mut RegistrationRequest| { &mut m.version },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &RegistrationRequest| { &m.virtual_ip },
|
||||
|m: &mut RegistrationRequest| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"allow_ip_change",
|
||||
|m: &RegistrationRequest| { &m.allow_ip_change },
|
||||
|m: &mut RegistrationRequest| { &mut m.allow_ip_change },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationRequest>(
|
||||
"RegistrationRequest",
|
||||
fields,
|
||||
@@ -106,6 +127,15 @@ impl ::protobuf::Message for RegistrationRequest {
|
||||
32 => {
|
||||
self.is_fast = is.read_bool()?;
|
||||
},
|
||||
42 => {
|
||||
self.version = is.read_string()?;
|
||||
},
|
||||
53 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
56 => {
|
||||
self.allow_ip_change = is.read_bool()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
@@ -130,6 +160,15 @@ impl ::protobuf::Message for RegistrationRequest {
|
||||
if self.is_fast != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if !self.version.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(5, &self.version);
|
||||
}
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.allow_ip_change != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
@@ -148,6 +187,15 @@ impl ::protobuf::Message for RegistrationRequest {
|
||||
if self.is_fast != false {
|
||||
os.write_bool(4, self.is_fast)?;
|
||||
}
|
||||
if !self.version.is_empty() {
|
||||
os.write_string(5, &self.version)?;
|
||||
}
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(6, self.virtual_ip)?;
|
||||
}
|
||||
if self.allow_ip_change != false {
|
||||
os.write_bool(7, self.allow_ip_change)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
@@ -169,6 +217,9 @@ impl ::protobuf::Message for RegistrationRequest {
|
||||
self.device_id.clear();
|
||||
self.name.clear();
|
||||
self.is_fast = false;
|
||||
self.version.clear();
|
||||
self.virtual_ip = 0;
|
||||
self.allow_ip_change = false;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
@@ -178,6 +229,9 @@ impl ::protobuf::Message for RegistrationRequest {
|
||||
device_id: ::std::string::String::new(),
|
||||
name: ::std::string::String::new(),
|
||||
is_fast: false,
|
||||
version: ::std::string::String::new(),
|
||||
virtual_ip: 0,
|
||||
allow_ip_change: false,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
@@ -219,6 +273,8 @@ pub struct RegistrationResponse {
|
||||
pub public_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_port)
|
||||
pub public_port: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_ipv6)
|
||||
pub public_ipv6: ::std::vec::Vec<u8>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationResponse.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
@@ -236,7 +292,7 @@ impl RegistrationResponse {
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(7);
|
||||
let mut fields = ::std::vec::Vec::with_capacity(8);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
@@ -273,6 +329,11 @@ impl RegistrationResponse {
|
||||
|m: &RegistrationResponse| { &m.public_port },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_port },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_ipv6",
|
||||
|m: &RegistrationResponse| { &m.public_ipv6 },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_ipv6 },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationResponse>(
|
||||
"RegistrationResponse",
|
||||
fields,
|
||||
@@ -312,6 +373,9 @@ impl ::protobuf::Message for RegistrationResponse {
|
||||
56 => {
|
||||
self.public_port = is.read_uint32()?;
|
||||
},
|
||||
66 => {
|
||||
self.public_ipv6 = is.read_bytes()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
@@ -346,6 +410,9 @@ impl ::protobuf::Message for RegistrationResponse {
|
||||
if self.public_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(7, self.public_port);
|
||||
}
|
||||
if !self.public_ipv6.is_empty() {
|
||||
my_size += ::protobuf::rt::bytes_size(8, &self.public_ipv6);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
@@ -373,6 +440,9 @@ impl ::protobuf::Message for RegistrationResponse {
|
||||
if self.public_port != 0 {
|
||||
os.write_uint32(7, self.public_port)?;
|
||||
}
|
||||
if !self.public_ipv6.is_empty() {
|
||||
os.write_bytes(8, &self.public_ipv6)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
@@ -397,6 +467,7 @@ impl ::protobuf::Message for RegistrationResponse {
|
||||
self.device_info_list.clear();
|
||||
self.public_ip = 0;
|
||||
self.public_port = 0;
|
||||
self.public_ipv6.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
@@ -409,6 +480,7 @@ impl ::protobuf::Message for RegistrationResponse {
|
||||
device_info_list: ::std::vec::Vec::new(),
|
||||
public_ip: 0,
|
||||
public_port: 0,
|
||||
public_ipv6: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
@@ -749,6 +821,8 @@ pub struct PunchInfo {
|
||||
pub local_ip: u32,
|
||||
// @@protoc_insertion_point(field:PunchInfo.local_port)
|
||||
pub local_port: u32,
|
||||
// @@protoc_insertion_point(field:PunchInfo.public_ipv6_list)
|
||||
pub public_ipv6_list: ::std::vec::Vec<::std::vec::Vec<u8>>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:PunchInfo.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
@@ -766,7 +840,7 @@ impl PunchInfo {
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(7);
|
||||
let mut fields = ::std::vec::Vec::with_capacity(8);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"public_ip_list",
|
||||
@@ -803,6 +877,11 @@ impl PunchInfo {
|
||||
|m: &PunchInfo| { &m.local_port },
|
||||
|m: &mut PunchInfo| { &mut m.local_port },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"public_ipv6_list",
|
||||
|m: &PunchInfo| { &m.public_ipv6_list },
|
||||
|m: &mut PunchInfo| { &mut m.public_ipv6_list },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<PunchInfo>(
|
||||
"PunchInfo",
|
||||
fields,
|
||||
@@ -845,6 +924,9 @@ impl ::protobuf::Message for PunchInfo {
|
||||
64 => {
|
||||
self.local_port = is.read_uint32()?;
|
||||
},
|
||||
74 => {
|
||||
self.public_ipv6_list.push(is.read_bytes()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
@@ -876,6 +958,9 @@ impl ::protobuf::Message for PunchInfo {
|
||||
if self.local_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(8, self.local_port);
|
||||
}
|
||||
for value in &self.public_ipv6_list {
|
||||
my_size += ::protobuf::rt::bytes_size(9, &value);
|
||||
};
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
@@ -903,6 +988,9 @@ impl ::protobuf::Message for PunchInfo {
|
||||
if self.local_port != 0 {
|
||||
os.write_uint32(8, self.local_port)?;
|
||||
}
|
||||
for v in &self.public_ipv6_list {
|
||||
os.write_bytes(9, &v)?;
|
||||
};
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
@@ -927,6 +1015,7 @@ impl ::protobuf::Message for PunchInfo {
|
||||
self.reply = false;
|
||||
self.local_ip = 0;
|
||||
self.local_port = 0;
|
||||
self.public_ipv6_list.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
@@ -939,6 +1028,7 @@ impl ::protobuf::Message for PunchInfo {
|
||||
reply: false,
|
||||
local_ip: 0,
|
||||
local_port: 0,
|
||||
public_ipv6_list: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
@@ -1017,28 +1107,33 @@ impl PunchNatType {
|
||||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\rmessage.proto\"u\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\
|
||||
\x20\x01(\tR\x05token\x12\x1b\n\tdevice_id\x18\x02\x20\x01(\tR\x08device\
|
||||
Id\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x17\n\x07is_fast\
|
||||
\x18\x04\x20\x01(\x08R\x06isFast\"\x92\x02\n\x14RegistrationResponse\x12\
|
||||
\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvirtualIp\x12'\n\x0fvirtual_ga\
|
||||
teway\x18\x02\x20\x01(\x07R\x0evirtualGateway\x12'\n\x0fvirtual_netmask\
|
||||
\x18\x03\x20\x01(\x07R\x0evirtualNetmask\x12\x14\n\x05epoch\x18\x04\x20\
|
||||
\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x05\x20\x03(\x0b2\x0b.D\
|
||||
eviceInfoR\x0edeviceInfoList\x12\x1b\n\tpublic_ip\x18\x06\x20\x01(\x07R\
|
||||
\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\x20\x01(\rR\npublicPort\"d\
|
||||
\n\nDeviceInfo\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\x12\x1d\n\n\
|
||||
virtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\x12#\n\rdevice_status\x18\
|
||||
\x03\x20\x01(\rR\x0cdeviceStatus\"Y\n\nDeviceList\x12\x14\n\x05epoch\x18\
|
||||
\x01\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x02\x20\x03(\
|
||||
\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xf8\x01\n\tPunchInfo\x12$\n\
|
||||
\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\x12\x1f\n\x0bpu\
|
||||
blic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11public_port_range\
|
||||
\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12(\n\x08nat_type\x18\x05\x20\
|
||||
\x01(\x0e2\r.PunchNatTypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\x01\
|
||||
(\x08R\x05reply\x12\x19\n\x08local_ip\x18\x07\x20\x01(\x07R\x07localIp\
|
||||
\x12\x1d\n\nlocal_port\x18\x08\x20\x01(\rR\tlocalPort*'\n\x0cPunchNatTyp\
|
||||
e\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01b\x06proto3\
|
||||
\n\rmessage.proto\"\xd6\x01\n\x13RegistrationRequest\x12\x14\n\x05token\
|
||||
\x18\x01\x20\x01(\tR\x05token\x12\x1b\n\tdevice_id\x18\x02\x20\x01(\tR\
|
||||
\x08deviceId\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x17\n\x07\
|
||||
is_fast\x18\x04\x20\x01(\x08R\x06isFast\x12\x18\n\x07version\x18\x05\x20\
|
||||
\x01(\tR\x07version\x12\x1d\n\nvirtual_ip\x18\x06\x20\x01(\x07R\tvirtual\
|
||||
Ip\x12&\n\x0fallow_ip_change\x18\x07\x20\x01(\x08R\rallowIpChange\"\xb3\
|
||||
\x02\n\x14RegistrationResponse\x12\x1d\n\nvirtual_ip\x18\x01\x20\x01(\
|
||||
\x07R\tvirtualIp\x12'\n\x0fvirtual_gateway\x18\x02\x20\x01(\x07R\x0evirt\
|
||||
ualGateway\x12'\n\x0fvirtual_netmask\x18\x03\x20\x01(\x07R\x0evirtualNet\
|
||||
mask\x12\x14\n\x05epoch\x18\x04\x20\x01(\rR\x05epoch\x125\n\x10device_in\
|
||||
fo_list\x18\x05\x20\x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\x12\x1b\
|
||||
\n\tpublic_ip\x18\x06\x20\x01(\x07R\x08publicIp\x12\x1f\n\x0bpublic_port\
|
||||
\x18\x07\x20\x01(\rR\npublicPort\x12\x1f\n\x0bpublic_ipv6\x18\x08\x20\
|
||||
\x01(\x0cR\npublicIpv6\"d\n\nDeviceInfo\x12\x12\n\x04name\x18\x01\x20\
|
||||
\x01(\tR\x04name\x12\x1d\n\nvirtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\
|
||||
\x12#\n\rdevice_status\x18\x03\x20\x01(\rR\x0cdeviceStatus\"Y\n\nDeviceL\
|
||||
ist\x12\x14\n\x05epoch\x18\x01\x20\x01(\rR\x05epoch\x125\n\x10device_inf\
|
||||
o_list\x18\x02\x20\x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xa2\x02\
|
||||
\n\tPunchInfo\x12$\n\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIp\
|
||||
List\x12\x1f\n\x0bpublic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11\
|
||||
public_port_range\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12(\n\x08nat_t\
|
||||
ype\x18\x05\x20\x01(\x0e2\r.PunchNatTypeR\x07natType\x12\x14\n\x05reply\
|
||||
\x18\x06\x20\x01(\x08R\x05reply\x12\x19\n\x08local_ip\x18\x07\x20\x01(\
|
||||
\x07R\x07localIp\x12\x1d\n\nlocal_port\x18\x08\x20\x01(\rR\tlocalPort\
|
||||
\x12(\n\x10public_ipv6_list\x18\t\x20\x03(\x0cR\x0epublicIpv6List*'\n\
|
||||
\x0cPunchNatType\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01b\x06\
|
||||
proto3\
|
||||
";
|
||||
|
||||
/// `FileDescriptorProto` object which was a source for this generated file
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
@@ -17,7 +18,10 @@ pub enum Protocol {
|
||||
PunchRequest,
|
||||
/// 打洞响应
|
||||
PunchResponse,
|
||||
UnKnow(u8),
|
||||
///获取对端看到的地址
|
||||
AddrRequest,
|
||||
AddrResponse,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
@@ -27,7 +31,9 @@ impl From<u8> for Protocol {
|
||||
2 => Protocol::Pong,
|
||||
3 => Protocol::PunchRequest,
|
||||
4 => Protocol::PunchResponse,
|
||||
val => Protocol::UnKnow(val),
|
||||
5 => Protocol::AddrRequest,
|
||||
6 => Protocol::AddrResponse,
|
||||
val => Protocol::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +45,9 @@ impl Into<u8> for Protocol {
|
||||
Protocol::Pong => 2,
|
||||
Protocol::PunchRequest => 3,
|
||||
Protocol::PunchResponse => 4,
|
||||
Protocol::UnKnow(val) => val,
|
||||
Protocol::AddrRequest => 5,
|
||||
Protocol::AddrResponse => 6,
|
||||
Protocol::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +57,8 @@ pub enum ControlPacket<B> {
|
||||
PongPacket(PongPacket<B>),
|
||||
PunchRequest,
|
||||
PunchResponse,
|
||||
AddrRequest,
|
||||
AddrResponse(AddrPacket<B>),
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ControlPacket<B> {
|
||||
@@ -58,18 +68,19 @@ impl<B: AsRef<[u8]>> ControlPacket<B> {
|
||||
Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)),
|
||||
Protocol::PunchRequest => Ok(ControlPacket::PunchRequest),
|
||||
Protocol::PunchResponse => Ok(ControlPacket::PunchResponse),
|
||||
Protocol::UnKnow(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "Unsupported")),
|
||||
Protocol::AddrRequest => Ok(ControlPacket::AddrRequest),
|
||||
Protocol::AddrResponse => Ok(ControlPacket::AddrResponse(AddrPacket::new(buffer)?)),
|
||||
Protocol::Unknown(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "Unsupported")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 网络探针
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PingPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
type PongPacket<B> = PingPacket<B>;
|
||||
pub type PongPacket<B> = PingPacket<B>;
|
||||
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<PingPacket<B>> {
|
||||
@@ -107,3 +118,42 @@ impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AddrPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> AddrPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<AddrPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 6 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "len != 6"));
|
||||
}
|
||||
Ok(AddrPacket { buffer })
|
||||
}
|
||||
pub fn ipv4(&self) -> Ipv4Addr {
|
||||
let buf = self.buffer.as_ref();
|
||||
Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])
|
||||
}
|
||||
pub fn port(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> AddrPacket<B> {
|
||||
pub fn set_ipv4(&mut self, ip: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&ip.octets())
|
||||
}
|
||||
pub fn set_port(&mut self, port: u16) {
|
||||
self.buffer.as_mut()[4..6].copy_from_slice(&port.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for AddrPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AddrPacket")
|
||||
.field("ipv4", &self.ipv4())
|
||||
.field("port", &self.port())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ pub enum Protocol {
|
||||
TokenError,
|
||||
Disconnect,
|
||||
AddressExhausted,
|
||||
IpAlreadyExists,
|
||||
InvalidIp,
|
||||
Other(u8),
|
||||
}
|
||||
|
||||
@@ -14,6 +16,8 @@ impl From<u8> for Protocol {
|
||||
1 => Self::TokenError,
|
||||
2 => Self::Disconnect,
|
||||
3 => Self::AddressExhausted,
|
||||
4 => Self::IpAlreadyExists,
|
||||
5 => Self::InvalidIp,
|
||||
val => Self::Other(val),
|
||||
}
|
||||
}
|
||||
@@ -25,6 +29,8 @@ impl Into<u8> for Protocol {
|
||||
Protocol::TokenError => 1,
|
||||
Protocol::Disconnect => 2,
|
||||
Protocol::AddressExhausted => 3,
|
||||
Protocol::IpAlreadyExists => 4,
|
||||
Protocol::InvalidIp => 5,
|
||||
Protocol::Other(val) => val,
|
||||
}
|
||||
}
|
||||
@@ -34,6 +40,8 @@ pub enum InErrorPacket<B> {
|
||||
TokenError,
|
||||
Disconnect,
|
||||
AddressExhausted,
|
||||
IpAlreadyExists,
|
||||
InvalidIp,
|
||||
OtherError(ErrorPacket<B>),
|
||||
}
|
||||
|
||||
@@ -43,6 +51,8 @@ impl<B: AsRef<[u8]>> InErrorPacket<B> {
|
||||
Protocol::TokenError => Ok(InErrorPacket::TokenError),
|
||||
Protocol::Disconnect => Ok(InErrorPacket::Disconnect),
|
||||
Protocol::AddressExhausted => Ok(InErrorPacket::AddressExhausted),
|
||||
Protocol::IpAlreadyExists => Ok(InErrorPacket::IpAlreadyExists),
|
||||
Protocol::InvalidIp => Ok(InErrorPacket::InvalidIp),
|
||||
Protocol::Other(_) => Ok(InErrorPacket::OtherError(ErrorPacket::new(buffer)?)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Protocol {
|
||||
Icmp,
|
||||
Igmp,
|
||||
Ipv4,
|
||||
Ipv4Broadcast,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Icmp,
|
||||
2 => Protocol::Igmp,
|
||||
4 => Protocol::Ipv4,
|
||||
201 => Protocol::Ipv4Broadcast,
|
||||
val => Protocol::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Icmp => 1,
|
||||
Protocol::Igmp => 2,
|
||||
Protocol::Ipv4 => 4,
|
||||
Protocol::Ipv4Broadcast => 201,
|
||||
Protocol::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BroadcastPacketEnd<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> BroadcastPacketEnd<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
let len = buffer.as_ref().len();
|
||||
let packet = Self::unchecked(buffer);
|
||||
if len < 1 || packet.len() != len {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"InvalidData",
|
||||
))
|
||||
} else {
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> BroadcastPacketEnd<B> {
|
||||
pub fn len(&self) -> usize {
|
||||
1 + self.num() as usize * 4
|
||||
}
|
||||
pub fn num(&self) -> u8 {
|
||||
let len = self.buffer.as_ref().len();
|
||||
self.buffer.as_ref()[len - 1]
|
||||
}
|
||||
/// 已经发送给了这些地址
|
||||
/// 从尾往头拿
|
||||
pub fn addresses(&self) -> Vec<Ipv4Addr> {
|
||||
let num = self.num() as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let buf = self.buffer.as_ref();
|
||||
let mut offset = buf.len() + 4 - 2;
|
||||
for _ in 0..num {
|
||||
offset -= 4;
|
||||
list.push(Ipv4Addr::new(buf[offset - 3], buf[offset - 2], buf[offset - 1], buf[offset]));
|
||||
}
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> BroadcastPacketEnd<B> {
|
||||
/// 从头往尾放
|
||||
pub fn set_address(&mut self, addr: &[Ipv4Addr]) -> io::Result<()> {
|
||||
let buf = self.buffer.as_mut();
|
||||
if buf.len() < 1 + addr.len() * 4 || addr.len() > u8::MAX as usize {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"InvalidData",
|
||||
))
|
||||
} else {
|
||||
let mut offset = 0;
|
||||
for ip in addr {
|
||||
buf[offset..offset + 4].copy_from_slice(&ip.octets());
|
||||
offset += 4;
|
||||
}
|
||||
self.buffer.as_mut()[offset] = addr.len() as u8;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{fmt, io};
|
||||
0 15 31
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 版本(8) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
|
||||
| p|unused| 版本(4) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 源ip地址(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@@ -18,7 +18,8 @@ use std::{fmt, io};
|
||||
pub mod control_packet;
|
||||
pub mod error_packet;
|
||||
pub mod service_packet;
|
||||
pub mod turn_packet;
|
||||
pub mod ip_turn_packet;
|
||||
pub mod other_turn_packet;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Version {
|
||||
@@ -52,8 +53,8 @@ pub enum Protocol {
|
||||
Error,
|
||||
/// 控制协议
|
||||
Control,
|
||||
/// 转发ipv4数据
|
||||
Ipv4Turn,
|
||||
/// 转发ip数据
|
||||
IpTurn,
|
||||
/// 转发其他数据
|
||||
OtherTurn,
|
||||
UnKnow(u8),
|
||||
@@ -65,7 +66,7 @@ impl From<u8> for Protocol {
|
||||
1 => Protocol::Service,
|
||||
2 => Protocol::Error,
|
||||
3 => Protocol::Control,
|
||||
4 => Protocol::Ipv4Turn,
|
||||
4 => Protocol::IpTurn,
|
||||
5 => Protocol::OtherTurn,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
@@ -78,7 +79,7 @@ impl Into<u8> for Protocol {
|
||||
Protocol::Service => 1,
|
||||
Protocol::Error => 2,
|
||||
Protocol::Control => 3,
|
||||
Protocol::Ipv4Turn => 4,
|
||||
Protocol::IpTurn => 4,
|
||||
Protocol::OtherTurn => 5,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
@@ -114,8 +115,11 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
pub fn is_encrypt(&self) -> bool {
|
||||
self.buffer.as_ref()[0] & 0x80 == 0x80
|
||||
}
|
||||
pub fn version(&self) -> Version {
|
||||
Version::from(self.buffer.as_ref()[0])
|
||||
Version::from(self.buffer.as_ref()[0] & 0x0F)
|
||||
}
|
||||
pub fn protocol(&self) -> Protocol {
|
||||
Protocol::from(self.buffer.as_ref()[1])
|
||||
@@ -143,8 +147,19 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
||||
pub fn buffer_mut(&mut self) -> &mut [u8] {
|
||||
self.buffer.as_mut()
|
||||
}
|
||||
pub fn set_encrypt_flag(&mut self, is_encrypt: bool) {
|
||||
if is_encrypt {
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x80
|
||||
} else {
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0x7F
|
||||
};
|
||||
}
|
||||
pub fn set_version(&mut self, version: Version) {
|
||||
self.buffer.as_mut()[0] = version.into();
|
||||
let v: u8 = version.into();
|
||||
self.buffer.as_mut()[0] = (self.buffer.as_ref()[0] & 0xF0) | (0x0F & v);
|
||||
}
|
||||
pub fn set_protocol(&mut self, protocol: Protocol) {
|
||||
self.buffer.as_mut()[1] = protocol.into();
|
||||
@@ -1,14 +1,14 @@
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Protocol {
|
||||
Punch,
|
||||
UnKnow(u8),
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Punch,
|
||||
val => Protocol::UnKnow(val),
|
||||
val => Protocol::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Punch => 1,
|
||||
Protocol::UnKnow(val) => val,
|
||||
Protocol::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ pub enum Protocol {
|
||||
PollDeviceList,
|
||||
/// 推送设备列表
|
||||
PushDeviceList,
|
||||
UnKnow(u8),
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
@@ -18,7 +18,7 @@ impl From<u8> for Protocol {
|
||||
2 => Self::RegistrationResponse,
|
||||
3 => Self::PollDeviceList,
|
||||
4 => Self::PushDeviceList,
|
||||
val => Self::UnKnow(val),
|
||||
val => Self::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ impl Into<u8> for Protocol {
|
||||
Self::RegistrationResponse => 2,
|
||||
Self::PollDeviceList => 3,
|
||||
Self::PushDeviceList => 4,
|
||||
Self::UnKnow(val) => val,
|
||||
Self::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use std::io;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter(RawFd);
|
||||
|
||||
pub struct DeviceReader(RawFd);
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
unsafe {
|
||||
let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len());
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,为了兼容其他代码,头部空了14个字节
|
||||
pub fn write_ipv4(&self, buf: &[u8]) -> io::Result<()> {
|
||||
let buf = &buf[14..];
|
||||
self.write_ipv4_tun(buf)
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
// unsafe {
|
||||
// libc::close(self.0);
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len());
|
||||
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(amount as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(fd: i32) -> (DeviceWriter, DeviceReader) {
|
||||
(DeviceWriter(fd as _), DeviceReader(fd as _))
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter, DriverInfo};
|
||||
use tun::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use crate::tun_tap_device::linux_mac::DeviceW;
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let mut config = tun::Configuration::default();
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
// .queues(2)
|
||||
.up();
|
||||
let mut dev = self.lock.lock();
|
||||
if let Err(e) = dev.configure(&config) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &self.in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
// add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!(
|
||||
"ip route add {:?}/{:?} dev {}",
|
||||
address, netmask, name
|
||||
);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: cmd:{},out:{:?}", route_add_str, route_add_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_device(device_type: DeviceType,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader,DriverInfo)> {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(mtu.into())
|
||||
// .queues(2) 用多个队列有兼容性问题
|
||||
.up();
|
||||
match device_type {
|
||||
DeviceType::Tun => {}
|
||||
DeviceType::Tap => {
|
||||
config.layer(tun::Layer::L2);
|
||||
}
|
||||
}
|
||||
let dev = tun::create(&config).unwrap();
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
// add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
let device_w = match device_type {
|
||||
DeviceType::Tun => {
|
||||
DeviceW::Tun(writer)
|
||||
}
|
||||
DeviceType::Tap => {
|
||||
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
|
||||
let mac_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(get_mac_cmd)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !mac_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("获取mac地址错误: {:?}", mac_out)));
|
||||
}
|
||||
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
|
||||
let mut mac = [0; 6];
|
||||
let mut split = mac_str.split(":");
|
||||
for i in 0..6 {
|
||||
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
|
||||
}
|
||||
DeviceW::Tap((writer, mac))
|
||||
}
|
||||
};
|
||||
let driver_info = DriverInfo {
|
||||
device_type,
|
||||
name:name.to_string(),
|
||||
version:String::new(),
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(device_w, Arc::new(Mutex::new(dev)), in_ips, address, packet_information),
|
||||
DeviceReader::new(reader),
|
||||
driver_info,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn delete_device(_device_type: DeviceType) {}
|
||||
@@ -0,0 +1,137 @@
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::BufMut;
|
||||
use tun::platform::posix::{Reader, Writer};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
use tun::platform::linux::Device;
|
||||
#[cfg(any(target_os = "macos"))]
|
||||
use tun::platform::macos::Device;
|
||||
use parking_lot::Mutex;
|
||||
use packet::ethernet;
|
||||
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
#[derive(Clone)]
|
||||
pub enum DeviceW {
|
||||
Tun(Writer),
|
||||
Tap((Writer, [u8; 6])),
|
||||
}
|
||||
|
||||
impl DeviceW {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
match self {
|
||||
DeviceW::Tun(_) => {
|
||||
true
|
||||
}
|
||||
DeviceW::Tap(_) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter {
|
||||
writer: DeviceW,
|
||||
pub lock: Arc<Mutex<Device>>,
|
||||
pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
packet_information: bool,
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn new(writer: DeviceW,lock: Arc<Mutex<Device>>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, _ip: Ipv4Addr, packet_information: bool) -> Self {
|
||||
Self {
|
||||
writer,
|
||||
lock,
|
||||
in_ips,
|
||||
packet_information,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn write(packet_information: bool, writer: &Writer, packet: &[u8]) -> io::Result<()> {
|
||||
if packet_information {
|
||||
let mut buf = Vec::<u8>::with_capacity(4 + packet.len());
|
||||
buf.put_u16(0);
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
buf.put_u16(libc::PF_INET as u16);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
buf.put_u16(libc::ETH_P_IP as u16);
|
||||
buf.extend_from_slice(packet);
|
||||
writer.write_all(&buf)
|
||||
} else {
|
||||
writer.write_all(packet)
|
||||
}
|
||||
}
|
||||
///tun网卡写入ipv4数据
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => {
|
||||
Self::write(self.packet_information, writer, buf)
|
||||
}
|
||||
DeviceW::Tap(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
}
|
||||
}
|
||||
/// tap网卡写入以太网帧
|
||||
pub fn write_ethernet_tap(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
DeviceW::Tap((writer, _)) => {
|
||||
Self::write(self.packet_information, writer, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,头部必须留14字节,给tap写入以太网帧头
|
||||
pub fn write_ipv4(&self, buf: &mut [u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => {
|
||||
Self::write(self.packet_information, writer, &buf[14..])
|
||||
}
|
||||
DeviceW::Tap((writer, mac)) => {
|
||||
let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], !mac[5], 234];
|
||||
let mut ethernet_packet = EthernetPacket::unchecked(buf);
|
||||
ethernet_packet.set_source(&source_mac);
|
||||
ethernet_packet.set_destination(mac);
|
||||
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||
Self::write(self.packet_information, writer, ðernet_packet.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
unsafe {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => {
|
||||
libc::close(writer.as_raw_fd());
|
||||
}
|
||||
DeviceW::Tap((writer, _)) => {
|
||||
libc::close(writer.as_raw_fd());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn is_tun(&self) -> bool {
|
||||
self.writer.is_tun()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeviceReader(Reader);
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn new(device: Reader) -> Self {
|
||||
DeviceReader(device)
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter, DriverInfo};
|
||||
use tun::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use crate::tun_tap_device::linux_mac::DeviceW;
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let mut config = tun::Configuration::default();
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.up();
|
||||
let mut dev = self.lock.lock();
|
||||
if let Err(e) = dev.configure(&config) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
if let Err(e) = config_ip(dev.name(), address, netmask, gateway) {
|
||||
log::error!("{}",e);
|
||||
}
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &self.in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_device(device_type: DeviceType,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
match device_type {
|
||||
DeviceType::Tun => {}
|
||||
DeviceType::Tap => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(mtu.into())
|
||||
.up();
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
let name = dev.name();
|
||||
config_ip(name, address, netmask, gateway)?;
|
||||
for (address, netmask) in &in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let driver_info = DriverInfo {
|
||||
device_type,
|
||||
name: name.to_string(),
|
||||
version: String::new(),
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(DeviceW::Tun(writer), Arc::new(Mutex::new(dev)), in_ips, address, packet_information),
|
||||
DeviceReader::new(reader),
|
||||
driver_info
|
||||
))
|
||||
}
|
||||
|
||||
fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!(
|
||||
"route -n add {} -netmask {} -interface {}",
|
||||
address, netmask, name
|
||||
);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: cmd:{},out:{:?}", route_add_str, route_add_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn config_ip(name: &str, address: Ipv4Addr, _netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, address, gateway);
|
||||
let up_eth_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&up_eth_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !up_eth_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: cmd:{},out:{:?}", up_eth_str, up_eth_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_device(_device_type: DeviceType) {}
|
||||
@@ -0,0 +1,53 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
mod linux;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod mac;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
mod linux_mac;
|
||||
#[cfg(target_os = "android")]
|
||||
mod android;
|
||||
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
pub use linux::create_device;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
pub use linux::delete_device;
|
||||
#[cfg(target_os = "android")]
|
||||
pub use android::create;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub use linux_mac::{DeviceWriter, DeviceReader};
|
||||
#[cfg(target_os = "android")]
|
||||
pub use android::{DeviceWriter, DeviceReader};
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::create_device;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::delete_device;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::create_device;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::delete_device;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{DeviceWriter, DeviceReader};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DeviceType {
|
||||
Tun,
|
||||
Tap,
|
||||
}
|
||||
|
||||
impl DeviceType {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
*self == DeviceType::Tun
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DriverInfo {
|
||||
pub device_type: DeviceType,
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub mac: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
use std::{io, thread};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use libloading::Library;
|
||||
use parking_lot::Mutex;
|
||||
use packet::ethernet;
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
use win_tun_tap::{IFace, TapDevice, TunDevice};
|
||||
use crate::tun_tap_device::{DriverInfo, DeviceType};
|
||||
|
||||
pub const TUN_INTERFACE_NAME: &str = "Vnt-Tun-V1";
|
||||
pub const TUN_POOL_NAME: &str = "Vnt-Tun-V1";
|
||||
pub const TAP_INTERFACE_NAME: &str = "Vnt-Tap-V1";
|
||||
|
||||
pub enum Device {
|
||||
Tun(TunDevice),
|
||||
Tap((TapDevice, [u8; 6])),
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
match self {
|
||||
Device::Tun(_) => {
|
||||
true
|
||||
}
|
||||
Device::Tap(_) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter {
|
||||
device: Arc<Device>,
|
||||
lock: Arc<Mutex<()>>,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn new(device: Arc<Device>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, _ip: Ipv4Addr) -> Self {
|
||||
Self {
|
||||
device,
|
||||
lock: Arc::new(Default::default()),
|
||||
in_ips,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
///tun网卡写入ipv4数据
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let mut packet = dev.allocate_send_packet(buf.len() as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(buf);
|
||||
dev.send_packet(packet);
|
||||
Ok(())
|
||||
}
|
||||
Device::Tap(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
}
|
||||
}
|
||||
/// tap网卡写入以太网帧
|
||||
pub fn write_ethernet_tap(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev.write(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,头部必须留14字节,给tap写入以太网帧头
|
||||
pub fn write_ipv4(&self, buf: &mut [u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let mut packet = dev.allocate_send_packet((buf.len() - 14) as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(&buf[14..]);
|
||||
dev.send_packet(packet);
|
||||
}
|
||||
Device::Tap((dev, mac)) => {
|
||||
let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], !mac[5], 234];
|
||||
let mut ethernet_packet = EthernetPacket::unchecked(buf);
|
||||
ethernet_packet.set_source(&source_mac);
|
||||
ethernet_packet.set_destination(mac);
|
||||
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||
dev.write(ðernet_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn change_ip(
|
||||
&self,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
old_netmask: Ipv4Addr,
|
||||
old_gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
let _guard = self.lock.lock();
|
||||
let dev: &dyn IFace = match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
dev as &dyn IFace
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev as &dyn IFace
|
||||
}
|
||||
};
|
||||
if let Err(e) =
|
||||
dev.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
|
||||
{
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
dev.set_ip(address, netmask)?;
|
||||
for (address, netmask) in &self.in_ips {
|
||||
dev.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
dev.add_route(address, netmask, gateway, 1)?;
|
||||
// 广播和组播路由
|
||||
dev.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
dev.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?;
|
||||
delete_cache();
|
||||
Ok(())
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
dev.shutdown()
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev.shutdown()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn is_tun(&self) -> bool {
|
||||
self.device.is_tun()
|
||||
}
|
||||
}
|
||||
|
||||
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
|
||||
let ip = ip.octets();
|
||||
let mask = mask.octets();
|
||||
Ipv4Addr::from([
|
||||
ip[0] & mask[0],
|
||||
ip[1] & mask[1],
|
||||
ip[2] & mask[2],
|
||||
ip[3] & mask[3],
|
||||
])
|
||||
}
|
||||
|
||||
pub struct DeviceReader {
|
||||
device: Arc<Device>,
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn new(device: Arc<Device>) -> Self {
|
||||
Self {
|
||||
device,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let packet = dev.receive_blocking()?;
|
||||
let packet = packet.bytes();
|
||||
let len = packet.len();
|
||||
if len > buf.len() {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "data too long"));
|
||||
}
|
||||
buf[..len].copy_from_slice(packet);
|
||||
Ok(len)
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev.read(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(_) => {
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("wintun.dll not found {:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
let tun_device = match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(_) => {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("{:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let name = tun_device.get_name()?;
|
||||
let version = format!("{:?}", tun_device.version()?);
|
||||
tun_device.set_ip(address, netmask)?;
|
||||
tun_device.set_metric(1)?;
|
||||
tun_device.set_mtu(mtu)?;
|
||||
// ip代理路由
|
||||
for (address, netmask) in &in_ips {
|
||||
tun_device.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
tun_device.add_route(address, netmask, gateway, 1)?;
|
||||
// 广播和组播路由
|
||||
tun_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
tun_device.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?;
|
||||
delete_cache();
|
||||
let device = Arc::new(Device::Tun(tun_device));
|
||||
let driver_info = DriverInfo {
|
||||
device_type: DeviceType::Tun,
|
||||
name,
|
||||
version,
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(device.clone(), in_ips, address),
|
||||
DeviceReader::new(device),
|
||||
driver_info
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_cache() {
|
||||
//清除路由缓存
|
||||
let delete_cache = "netsh interface ip delete destinationcache";
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(delete_cache)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
log::warn!("删除缓存失败:{:?}",out);
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_tun() {
|
||||
unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tap(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
let tap_device = TapDevice::create()?;
|
||||
tap_device.set_name(TAP_INTERFACE_NAME)?;
|
||||
tap_device
|
||||
}
|
||||
};
|
||||
let mac = tap_device.get_mac()?;
|
||||
let name = tap_device.get_name()?;
|
||||
let version = format!("{:?}", tap_device.get_version()?);
|
||||
let mac_str = format!("mac:{:x?}", mac);
|
||||
tap_device.set_ip(address, netmask)?;
|
||||
tap_device.set_metric(1)?;
|
||||
tap_device.set_mtu(mtu)?;
|
||||
tap_device.set_status(true)?;
|
||||
tap_device.add_route(address, netmask, gateway, 1)?;
|
||||
for (address, netmask) in &in_ips {
|
||||
tap_device.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 广播和组播路由
|
||||
tap_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
tap_device.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?;
|
||||
delete_cache();
|
||||
let tap = Arc::new(Device::Tap((tap_device, mac)));
|
||||
let driver_info = DriverInfo {
|
||||
device_type: DeviceType::Tap,
|
||||
name,
|
||||
version,
|
||||
mac: Some(mac_str),
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(tap.clone(), in_ips, address),
|
||||
DeviceReader::new(tap),
|
||||
driver_info
|
||||
))
|
||||
}
|
||||
|
||||
fn delete_tap() {
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(_) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let _ = tap_device.delete();
|
||||
}
|
||||
|
||||
pub fn create_device(device_type: DeviceType, address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
match device_type {
|
||||
DeviceType::Tun => {
|
||||
create_tun(address, netmask, gateway, in_ips, mtu)
|
||||
}
|
||||
DeviceType::Tap => {
|
||||
create_tap(address, netmask, gateway, in_ips, mtu)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_device(device_type: DeviceType) {
|
||||
match device_type {
|
||||
DeviceType::Tun => {
|
||||
delete_tun()
|
||||
}
|
||||
DeviceType::Tap => {
|
||||
delete_tap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod wait;
|
||||
@@ -0,0 +1,44 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
use tokio::sync::watch::{channel, Receiver, Sender};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WaitGroup {
|
||||
count: Arc<AtomicIsize>,
|
||||
receiver: Receiver<usize>,
|
||||
sender: Arc<Sender<usize>>,
|
||||
}
|
||||
|
||||
impl WaitGroup {
|
||||
pub fn new() -> Self {
|
||||
let (sender, receiver) = channel(1);
|
||||
Self {
|
||||
count: Arc::new(Default::default()),
|
||||
receiver,
|
||||
sender: Arc::new(sender),
|
||||
}
|
||||
}
|
||||
pub fn add(&self) {
|
||||
let _ = self.count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
pub fn done(&self) {
|
||||
let i = self.count.fetch_sub(1, Ordering::Relaxed);
|
||||
if i == 1 {
|
||||
let _ = self.sender.send(0);
|
||||
}
|
||||
}
|
||||
pub async fn wait(&mut self) {
|
||||
loop {
|
||||
if 0 == *self.receiver.borrow() {
|
||||
return;
|
||||
}
|
||||
if self.receiver.changed().await.is_ok() {
|
||||
if 0 == *self.receiver.borrow() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ libloading = "0.7"
|
||||
widestring = "0.4"
|
||||
once_cell = "1.8"
|
||||
itertools = "0.10.1"
|
||||
|
||||
rand = "0.8.5"
|
||||
[dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = [
|
||||
@@ -5,8 +5,8 @@ mod tun;
|
||||
mod ffi;
|
||||
mod netsh;
|
||||
mod route;
|
||||
|
||||
use std::{io, net};
|
||||
use std::net::Ipv4Addr;
|
||||
pub use tap::TapDevice;
|
||||
pub use tun::*;
|
||||
|
||||
@@ -23,7 +23,7 @@ fn decode_utf16(string: &[u16]) -> String {
|
||||
}
|
||||
|
||||
pub trait IFace {
|
||||
fn shutdown(&self)->io::Result<()>;
|
||||
fn shutdown(&self) -> io::Result<()>;
|
||||
/// 获取接口索引
|
||||
fn get_index(&self) -> io::Result<u32>;
|
||||
/// 获取名称
|
||||
@@ -31,18 +31,17 @@ pub trait IFace {
|
||||
/// 设置名称
|
||||
fn set_name(&self, new_name: &str) -> io::Result<()>;
|
||||
/// 设置ip
|
||||
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()>
|
||||
where IP: Into<net::Ipv4Addr>;
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()>;
|
||||
/// 设置路由
|
||||
fn add_route<IP>(&self, dest: IP,
|
||||
netmask: IP,
|
||||
gateway: IP, ) -> io::Result<()>
|
||||
where IP: Into<net::Ipv4Addr>;
|
||||
fn add_route(&self, dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, metric: u16) -> io::Result<()>;
|
||||
/// 删除路由
|
||||
fn delete_route<IP>(&self, dest: IP,
|
||||
netmask: IP,
|
||||
gateway: IP, ) -> io::Result<()>
|
||||
where IP: Into<net::Ipv4Addr>;
|
||||
fn delete_route(&self, dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, ) -> io::Result<()>;
|
||||
/// 设置最大传输单元
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()>;
|
||||
/// 设置跃点
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()>;
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
/// 设置网卡名称
|
||||
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
|
||||
let cmd = format!(" netsh interface set interface name={:?} newname={:?}", old_name, new_name);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000) //winapi-0.3.9/src/um/winbase.rs:283
|
||||
.arg("/C")
|
||||
.arg(&cmd)
|
||||
.output()?;
|
||||
@@ -21,6 +23,7 @@ pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> i
|
||||
index, address, netmask,
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_address)
|
||||
.output()?;
|
||||
@@ -37,6 +40,7 @@ pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> {
|
||||
index, mtu
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_mtu)
|
||||
.output()?;
|
||||
@@ -45,4 +49,17 @@ pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置mtu失败: {:?}", out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
|
||||
let set_metric = format!("netsh interface ip set interface {} metric={}", index,metric);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_metric)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}",set_metric,out);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置metric失败: {:?}", out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,16 +1,18 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
/// 添加路由
|
||||
pub fn add_route(index: u32, dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, ) -> io::Result<()> {
|
||||
gateway: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
let set_route = format!(
|
||||
"route add {:?} mask {:?} {:?} if {}",
|
||||
dest, netmask, gateway, index
|
||||
"route add {:?} mask {:?} {:?} metric {} if {}",
|
||||
dest, netmask, gateway, metric, index
|
||||
);
|
||||
// 执行添加路由命令
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_route)
|
||||
.output()
|
||||
@@ -23,7 +25,7 @@ pub fn add_route(index: u32, dest: Ipv4Addr,
|
||||
}
|
||||
|
||||
/// 删除路由
|
||||
pub fn delete_route(index: u32, dest: Ipv4Addr,netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
pub fn delete_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
if index == 0 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("网络接口索引错误: {:?}", index)));
|
||||
}
|
||||
@@ -33,6 +35,7 @@ pub fn delete_route(index: u32, dest: Ipv4Addr,netmask: Ipv4Addr, gateway: Ipv4A
|
||||
);
|
||||
// 删除路由
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(delete_route)
|
||||
.output()
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::{io, net, time};
|
||||
use std::{io, time};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use winapi::shared::ifdef::NET_LUID;
|
||||
use winapi::shared::minwindef::*;
|
||||
use winapi::um::winioctl::*;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
@@ -11,12 +10,15 @@ use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
|
||||
mod iface;
|
||||
|
||||
pub struct TapDevice {
|
||||
index: u32,
|
||||
luid: NET_LUID,
|
||||
handle: HANDLE,
|
||||
|
||||
}
|
||||
unsafe impl Send for TapDevice{}
|
||||
unsafe impl Sync for TapDevice{}
|
||||
|
||||
unsafe impl Send for TapDevice {}
|
||||
|
||||
unsafe impl Sync for TapDevice {}
|
||||
|
||||
impl TapDevice {
|
||||
/// Retieve the mac of the interface
|
||||
@@ -95,7 +97,8 @@ impl TapDevice {
|
||||
Ok(handle) => break handle,
|
||||
};
|
||||
};
|
||||
Ok(Self { luid, handle })
|
||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||
Ok(Self { index, luid, handle })
|
||||
}
|
||||
|
||||
pub fn open(name: &str) -> io::Result<Self> {
|
||||
@@ -105,7 +108,8 @@ impl TapDevice {
|
||||
iface::check_interface(&luid)?;
|
||||
|
||||
let handle = iface::open_interface(&luid)?;
|
||||
Ok(Self { luid, handle })
|
||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||
Ok(Self { index, luid, handle })
|
||||
}
|
||||
|
||||
pub fn delete(self) -> io::Result<()> {
|
||||
@@ -119,7 +123,7 @@ impl IFace for TapDevice {
|
||||
}
|
||||
|
||||
fn get_index(&self) -> io::Result<u32> {
|
||||
ffi::luid_to_index(&self.luid).map(|index| index as u32)
|
||||
Ok(self.index)
|
||||
}
|
||||
|
||||
fn get_name(&self) -> io::Result<String> {
|
||||
@@ -131,25 +135,30 @@ impl IFace for TapDevice {
|
||||
netsh::set_interface_name(&name, new_name)
|
||||
}
|
||||
|
||||
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_ip(index, &address.into(), &mask.into())
|
||||
netsh::set_interface_ip(index, &address, &mask)
|
||||
}
|
||||
|
||||
fn add_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
route::add_route(index, dest.into(), netmask.into(), gateway.into())
|
||||
route::add_route(index, dest, netmask, gateway,metric)
|
||||
}
|
||||
|
||||
fn delete_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
route::delete_route(index, dest.into(), netmask.into(), gateway.into())
|
||||
route::delete_route(index, dest, netmask, gateway)
|
||||
}
|
||||
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_mtu(index, mtu)
|
||||
}
|
||||
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_metric(index, metric)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::net::Ipv4Addr;
|
||||
use winapi::um::{handleapi, synchapi, winbase, winnt};
|
||||
|
||||
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
|
||||
use rand::Rng;
|
||||
mod wintun_raw;
|
||||
mod log;
|
||||
pub mod packet;
|
||||
@@ -19,6 +20,8 @@ pub const MAX_POOL: usize = 256;
|
||||
|
||||
|
||||
pub struct TunDevice {
|
||||
pub(crate) luid: u64,
|
||||
pub(crate) index: u32,
|
||||
/// The session handle given to us by WintunStartSession
|
||||
pub(crate) session: wintun_raw::WINTUN_SESSION_HANDLE,
|
||||
|
||||
@@ -41,11 +44,7 @@ pub struct TunDevice {
|
||||
unsafe impl Send for TunDevice {}
|
||||
|
||||
unsafe impl Sync for TunDevice {}
|
||||
winapi::DEFINE_GUID! {
|
||||
GUID_NETWORK_ADAPTER,
|
||||
0x4d36e972, 0xe325, 0x11ce,
|
||||
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
|
||||
}
|
||||
|
||||
impl TunDevice {
|
||||
pub unsafe fn create<L>(library: L, pool: &str, name: &str) -> io::Result<Self>
|
||||
where L: Into<libloading::Library>, {
|
||||
@@ -63,9 +62,13 @@ impl TunDevice {
|
||||
if name_utf16.len() > MAX_POOL {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("长度大于{}:{:?}", MAX_POOL, pool)));
|
||||
}
|
||||
let mut guid_bytes: [u8; 16] = [0u8; 16];
|
||||
rand::thread_rng().fill(&mut guid_bytes);
|
||||
let guid = u128::from_ne_bytes(guid_bytes);
|
||||
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
|
||||
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
|
||||
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(GUID_NETWORK_ADAPTER) };
|
||||
|
||||
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) };
|
||||
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
|
||||
|
||||
log::set_default_logger_if_unset(&win_tun);
|
||||
@@ -90,8 +93,12 @@ impl TunDevice {
|
||||
let shutdown_event = synchapi::CreateEventA(std::ptr::null_mut(),
|
||||
0, 0, std::ptr::null_mut());
|
||||
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
|
||||
|
||||
let mut luid: wintun_raw::NET_LUID = std::mem::zeroed();
|
||||
win_tun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID);
|
||||
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
|
||||
Ok(TunDevice {
|
||||
luid: std::mem::transmute(luid),
|
||||
index,
|
||||
session,
|
||||
win_tun,
|
||||
read_event,
|
||||
@@ -99,7 +106,7 @@ impl TunDevice {
|
||||
adapter,
|
||||
})
|
||||
}
|
||||
pub unsafe fn open<L>(library: L, name: &str) -> io::Result<Self>
|
||||
pub unsafe fn delete_for_name<L>(library: L, name: &str) -> io::Result<()>
|
||||
where L: Into<libloading::Library>, {
|
||||
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||
Ok(win_tun) => win_tun,
|
||||
@@ -113,7 +120,9 @@ impl TunDevice {
|
||||
if adapter.is_null() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Failed to open adapter"));
|
||||
}
|
||||
Self::init(win_tun, adapter)
|
||||
win_tun.WintunCloseAdapter(adapter);
|
||||
win_tun.WintunDeleteDriver();
|
||||
Ok(())
|
||||
}
|
||||
pub fn delete(self) -> io::Result<()> {
|
||||
drop(self);
|
||||
@@ -138,13 +147,14 @@ pub struct Version {
|
||||
pub minor: u16,
|
||||
}
|
||||
|
||||
impl TunDevice {
|
||||
fn get_adapter_luid(&self) -> u64 {
|
||||
let mut luid: wintun_raw::NET_LUID = unsafe { std::mem::zeroed() };
|
||||
unsafe { self.win_tun.WintunGetAdapterLUID(self.adapter, &mut luid as *mut wintun_raw::NET_LUID) };
|
||||
unsafe { std::mem::transmute(luid) }
|
||||
}
|
||||
}
|
||||
// impl TunDevice {
|
||||
// fn get_adapter_luid(&self) -> u64 {
|
||||
// let mut luid: wintun_raw::NET_LUID = unsafe { std::mem::zeroed() };
|
||||
// unsafe { self.win_tun.WintunGetAdapterLUID(self.adapter, &mut luid as *mut wintun_raw::NET_LUID) };
|
||||
// unsafe { std::mem::transmute(luid) }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
impl IFace for TunDevice {
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
@@ -154,12 +164,11 @@ impl IFace for TunDevice {
|
||||
}
|
||||
|
||||
fn get_index(&self) -> io::Result<u32> {
|
||||
let luid = self.get_adapter_luid();
|
||||
ffi::luid_to_index(&unsafe { std::mem::transmute(luid) }).map(|index| index as u32)
|
||||
Ok(self.index)
|
||||
}
|
||||
|
||||
fn get_name(&self) -> io::Result<String> {
|
||||
let luid = self.get_adapter_luid();
|
||||
let luid = self.luid;
|
||||
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| {
|
||||
decode_utf16(&name)
|
||||
})
|
||||
@@ -170,21 +179,26 @@ impl IFace for TunDevice {
|
||||
netsh::set_interface_name(&name, new_name)
|
||||
}
|
||||
|
||||
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||
netsh::set_interface_ip(self.get_index()?, &address.into(), &mask.into())
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()>{
|
||||
netsh::set_interface_ip(self.get_index()?, &address, &mask)
|
||||
}
|
||||
|
||||
fn add_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||
route::add_route(self.get_index()?, dest.into(), netmask.into(), gateway.into())
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
route::add_route(self.get_index()?, dest, netmask, gateway, metric)
|
||||
}
|
||||
|
||||
fn delete_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||
route::delete_route(self.get_index()?, dest.into(), netmask.into(), gateway.into())
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
route::delete_route(self.get_index()?, dest, netmask, gateway)
|
||||
}
|
||||
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||
netsh::set_interface_mtu(self.get_index()?, mtu)
|
||||
}
|
||||
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_metric(index, metric)
|
||||
}
|
||||
}
|
||||
|
||||
impl TunDevice {
|
||||
Reference in New Issue
Block a user