Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0b0c61a03 | ||
|
|
b0501db4e5 | ||
|
|
465a5c75ae | ||
|
|
978460aca8 | ||
|
|
4b86752c79 | ||
|
|
bd61cad7b6 | ||
|
|
40cbd2e26b | ||
|
|
2cab580b4e | ||
|
|
3d243fb01d | ||
|
|
ca4e8d14f0 | ||
|
|
9c098c55c9 | ||
|
|
707b07b8d3 | ||
|
|
de5a6971f0 | ||
|
|
056036c4d2 | ||
|
|
1cfb188845 | ||
|
|
73a2c31854 | ||
|
|
92eea536f8 | ||
|
|
00936a923e | ||
|
|
ba69ba78af | ||
|
|
17b206bace | ||
|
|
58d5a4f5da | ||
|
|
2438d14175 | ||
|
|
99f8526799 | ||
|
|
56fcbd64ed | ||
|
|
3766b2b7c1 | ||
|
|
baf0698fe4 | ||
|
|
301938b9fc | ||
|
|
16a37c713a | ||
|
|
d412a769dd | ||
|
|
c8eecc87fd | ||
|
|
6a11db70c8 |
@@ -3,7 +3,9 @@
|
|||||||
A virtual network tool (VPN)
|
A virtual network tool (VPN)
|
||||||
|
|
||||||
将不同网络下的多个设备虚拟到一个局域网下
|
将不同网络下的多个设备虚拟到一个局域网下
|
||||||
|
|
||||||
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
|
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
|
||||||
|
|
||||||
### 快速使用:
|
### 快速使用:
|
||||||
|
|
||||||
1. 指定一个token,在多台设备上运行该程序,例如:
|
1. 指定一个token,在多台设备上运行该程序,例如:
|
||||||
@@ -61,8 +63,27 @@ A virtual network tool (VPN)
|
|||||||
|
|
||||||
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
|
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
|
||||||
|
|
||||||
|
```
|
||||||
到项目根目录下执行 cargo build -p vnt-cli
|
到项目根目录下执行 cargo build -p vnt-cli
|
||||||
|
|
||||||
|
也可按需编译,将得到更小的二进制文件,使用--no-default-features排除默认features
|
||||||
|
|
||||||
|
cargo build -p vnt-cli --no-default-features
|
||||||
|
```
|
||||||
|
|
||||||
|
features说明
|
||||||
|
|
||||||
|
| feature | 说明 | 是否默认 |
|
||||||
|
|------------------|----------------------|------|
|
||||||
|
| openssl | 使用openssl中的aes_ecb算法 | 否 |
|
||||||
|
| openssl-vendored | 从源码编译openssl | 否 |
|
||||||
|
| ring-cipher | 使用ring中的aes_gcm算法 | 否 |
|
||||||
|
| aes_cbc | 支持aes_cbc加密 | 是 |
|
||||||
|
| aes_ecb | 支持aes_ecb加密 | 是 |
|
||||||
|
| aes_gcm | 支持aes_gcm加密 | 是 |
|
||||||
|
| aes_ecb | 支持aes_ecb加密 | 是 |
|
||||||
|
| server_encrypt | 支持服务端加密 | 是 |
|
||||||
|
|
||||||
### 支持平台
|
### 支持平台
|
||||||
|
|
||||||
- Mac
|
- Mac
|
||||||
@@ -86,7 +107,9 @@ A virtual network tool (VPN)
|
|||||||
- p2p组播/广播
|
- p2p组播/广播
|
||||||
- 客户端数据加密
|
- 客户端数据加密
|
||||||
- 服务端数据加密
|
- 服务端数据加密
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
<details> <summary>展开</summary>
|
<details> <summary>展开</summary>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
@@ -121,6 +144,7 @@ A virtual network tool (VPN)
|
|||||||
- 支持Ipv6(1.2.2已支持客户端之间的ipv6,待支持客户端和服务端之间的ipv6通信)
|
- 支持Ipv6(1.2.2已支持客户端之间的ipv6,待支持客户端和服务端之间的ipv6通信)
|
||||||
|
|
||||||
### 常见问题
|
### 常见问题
|
||||||
|
|
||||||
<details> <summary>展开</summary>
|
<details> <summary>展开</summary>
|
||||||
|
|
||||||
#### 问题1: 设置网络地址失败
|
#### 问题1: 设置网络地址失败
|
||||||
@@ -138,26 +162,35 @@ vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
|
|||||||
#### 问题2: windows系统上wintun.dll加载失败
|
#### 问题2: windows系统上wintun.dll加载失败
|
||||||
|
|
||||||
##### 可能原因:
|
##### 可能原因:
|
||||||
|
|
||||||
没有下载wintun.dll 或者使用的wintun.dll有问题
|
没有下载wintun.dll 或者使用的wintun.dll有问题
|
||||||
|
|
||||||
##### 解决方法:
|
##### 解决方法:
|
||||||
|
|
||||||
1. 下载最新版的wintun.dll [下载链接](https://www.wintun.net/builds/wintun-0.14.1.zip)
|
1. 下载最新版的wintun.dll [下载链接](https://www.wintun.net/builds/wintun-0.14.1.zip)
|
||||||
2. 解压后找到对应架构的目录,通常是amd64
|
2. 解压后找到对应架构的目录,通常是amd64
|
||||||
3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下)
|
3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下)
|
||||||
4. 再次启动vnt-cli
|
4. 再次启动vnt-cli
|
||||||
|
|
||||||
#### 问题3: 丢包严重,或是不能正常组网通信
|
#### 问题3: 丢包严重,或是不能正常组网通信
|
||||||
|
|
||||||
##### 可能原因:
|
##### 可能原因:
|
||||||
|
|
||||||
某些宽带下(比如广电宽带)UDP丢包严重
|
某些宽带下(比如广电宽带)UDP丢包严重
|
||||||
|
|
||||||
##### 解决方法:
|
##### 解决方法:
|
||||||
|
|
||||||
1. 使用TCP模式中继转发(vnt-cli增加--tcp参数)
|
1. 使用TCP模式中继转发(vnt-cli增加--tcp参数)
|
||||||
2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--relay参数)
|
2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--relay参数)
|
||||||
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 交流群
|
### 交流群
|
||||||
|
|
||||||
QQ:1034868233
|
QQ:1034868233
|
||||||
|
|
||||||
### 其他
|
### 其他
|
||||||
|
|
||||||
可使用社区小伙伴搭建的中继服务器
|
可使用社区小伙伴搭建的中继服务器
|
||||||
|
|
||||||
1. -s vnt.8443.eu.org:29871
|
1. -s vnt.8443.eu.org:29871
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "1.2.4"
|
version = "1.2.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
+10
-5
@@ -1,20 +1,21 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vnt-cli"
|
name = "vnt-cli"
|
||||||
version = "1.2.4"
|
version = "1.2.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vnt = { path = "../vnt", package = "vnt", optional = true }
|
vnt = { path = "../vnt", package = "vnt",default-features = false }
|
||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
tokio = { version = "1.32.0", features = ["full"] }
|
tokio = { version = "1.32.0", features = ["full"] }
|
||||||
getopts = "0.2.21"
|
getopts = "0.2.21"
|
||||||
console = "0.15.2"
|
console = "0.15.2"
|
||||||
os_info = "3.7.0"
|
os_info = "3.7.0"
|
||||||
dirs = "4.0.0"
|
dirs = "5.0.1"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0.94"
|
serde_json = "1.0.94"
|
||||||
|
serde_yaml = "0.9.25"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
log4rs = "1.2.0"
|
log4rs = "1.2.0"
|
||||||
[dependencies.uuid]
|
[dependencies.uuid]
|
||||||
@@ -30,11 +31,15 @@ sudo = "0.6.0"
|
|||||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["vnt"]
|
default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc"]
|
||||||
openssl = ["vnt/openssl"]
|
openssl = ["vnt/openssl"]
|
||||||
openssl-vendored = ["vnt/openssl-vendored"]
|
openssl-vendored = ["vnt/openssl-vendored"]
|
||||||
ring-cipher = ["vnt/ring-cipher"]
|
ring-cipher = ["vnt/ring-cipher"]
|
||||||
|
aes_cbc=["vnt/aes_cbc"]
|
||||||
|
aes_ecb=["vnt/aes_ecb"]
|
||||||
|
sm4_cbc=["vnt/sm4_cbc"]
|
||||||
|
aes_gcm=["vnt/aes_gcm"]
|
||||||
|
server_encrypt=["vnt/server_encrypt"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
embed-manifest = "1.4.0"
|
embed-manifest = "1.4.0"
|
||||||
+47
-5
@@ -29,10 +29,10 @@
|
|||||||
|
|
||||||
提升通信安全性,使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密(包括中继数据)。使用相同密码的客户端才能通信
|
提升通信安全性,使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密(包括中继数据)。使用相同密码的客户端才能通信
|
||||||
|
|
||||||
| 密码位数 | 加密算法 |
|
| 密码位数 | 加密算法 |
|
||||||
|---------|-------|
|
|-------|------------|
|
||||||
| 小于8 | AES128-GCM
|
| 小于8 | AES128-GCM |
|
||||||
| 大于等于8 | AES256-GCM |
|
| 大于等于8 | AES256-GCM |
|
||||||
|
|
||||||
### -W
|
### -W
|
||||||
开启和服务端通信的数据加密,采用rsa+aes256gcm加密客户端和服务端之间通信的数据,可以避免token泄漏、中间人攻击
|
开启和服务端通信的数据加密,采用rsa+aes256gcm加密客户端和服务端之间通信的数据,可以避免token泄漏、中间人攻击
|
||||||
@@ -59,7 +59,8 @@
|
|||||||
### --par `<parallel>`
|
### --par `<parallel>`
|
||||||
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
|
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
|
||||||
### --model `<model>`
|
### --model `<model>`
|
||||||
加密模式,可选值 aes_gcm/aes_cbc/aes_ecb,默认使用aes_gcm,通常情况aes_gcm安全性高、aes_ecb性能更好
|
加密模式,可选值 aes_gcm/aes_cbc/aes_ecb/sm4_cbc,默认使用aes_gcm,通常情况aes_gcm安全性高、aes_ecb性能更好,但是在低性能设备上sm4_cbc也许速度会更快;
|
||||||
|
|
||||||
|
|
||||||
| 密码位数 | model | 加密算法 |
|
| 密码位数 | model | 加密算法 |
|
||||||
|-------|---------|------------|
|
|-------|---------|------------|
|
||||||
@@ -69,12 +70,53 @@
|
|||||||
| `>=`8 | aes_cbc | AES256-CBC |
|
| `>=`8 | aes_cbc | AES256-CBC |
|
||||||
| 1~8位 | aes_ecb | AES128-ECB |
|
| 1~8位 | aes_ecb | AES128-ECB |
|
||||||
| `>=`8 | aes_ecb | AES256-ECB |
|
| `>=`8 | aes_ecb | AES256-ECB |
|
||||||
|
| `>0` | sm4_cbc | SM4-CBC |
|
||||||
### --finger
|
### --finger
|
||||||
|
|
||||||
开启数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启,开启会损耗一部分性能
|
开启数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启,开启会损耗一部分性能
|
||||||
|
|
||||||
注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数
|
注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数
|
||||||
|
### --punch `<punch>`
|
||||||
|
取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两则都会使用
|
||||||
|
### --port `<port>`
|
||||||
|
取值0~65535,指定本地监听的端口,默认取随机端口
|
||||||
|
### -f `<conf>`
|
||||||
|
指定配置文件
|
||||||
|
配置文件采用yaml格式,可参考:
|
||||||
|
```yaml
|
||||||
|
# 全部参数
|
||||||
|
tap: false #是否使用tap
|
||||||
|
token: xxx #组网token
|
||||||
|
device_id: xxx #当前设备id
|
||||||
|
name: windows 11 #当前设备名称
|
||||||
|
server_address: ip:port #注册和中继服务器
|
||||||
|
stun_server: #stun服务器
|
||||||
|
- stun1.l.google.com:19302
|
||||||
|
- stun2.l.google.com:19302
|
||||||
|
in_ips: #代理ip入站
|
||||||
|
- 192.168.1.0/24,10.26.0.3
|
||||||
|
out_ips: #代理ip出站
|
||||||
|
- 0.0.0.0/0
|
||||||
|
password: xxx #密码
|
||||||
|
simulate_multicast: false #模拟组播
|
||||||
|
mtu: 1420 #mtu
|
||||||
|
tcp: false #tcp模式
|
||||||
|
ip: 10.26.0.2 #指定虚拟ip
|
||||||
|
relay: false #中继模式
|
||||||
|
server_encrypt: true #服务端加密
|
||||||
|
parallel: 1 #任务并行度
|
||||||
|
cipher_model: aes_gcm #客户端加密算法
|
||||||
|
finger: false #关闭数据指纹
|
||||||
|
punch_model: ipv4 #打洞模式
|
||||||
|
port: 0 #使用随机端口
|
||||||
|
cmd: false #关闭控制台输入
|
||||||
|
```
|
||||||
|
|
||||||
|
或者需要哪个配置就加哪个,当然token是必须的
|
||||||
|
```yaml
|
||||||
|
# 部分参数
|
||||||
|
token: xxx #组网token
|
||||||
|
```
|
||||||
### --relay
|
### --relay
|
||||||
禁用p2p,在网络环境很差时,只使用服务器中转效果可能更好(可以配合--tcp参数一起使用)
|
禁用p2p,在网络环境很差时,只使用服务器中转效果可能更好(可以配合--tcp参数一起使用)
|
||||||
### --list
|
### --list
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ impl CommandClient {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let udp = UdpSocket::bind("127.0.0.1:0")?;
|
let udp = UdpSocket::bind("127.0.0.1:0")?;
|
||||||
udp.set_read_timeout(Some(Duration::from_secs(2)))?;
|
udp.set_read_timeout(Some(Duration::from_secs(5)))?;
|
||||||
udp.connect(SocketAddr::V4(SocketAddrV4::new(
|
udp.connect(SocketAddr::V4(SocketAddrV4::new(
|
||||||
Ipv4Addr::new(127, 0, 0, 1),
|
Ipv4Addr::new(127, 0, 0, 1),
|
||||||
port,
|
port,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub enum CommandEnum {
|
|||||||
|
|
||||||
pub fn command(cmd: CommandEnum) {
|
pub fn command(cmd: CommandEnum) {
|
||||||
if let Err(e) = command_(cmd) {
|
if let Err(e) = command_(cmd) {
|
||||||
println!("cmd: {}", e);
|
println!("cmd: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,20 @@ impl CommandServer {
|
|||||||
let udp = UdpSocket::bind("127.0.0.1:0").await?;
|
let udp = UdpSocket::bind("127.0.0.1:0").await?;
|
||||||
let path_buf = crate::app_home()?.join("command-port");
|
let path_buf = crate::app_home()?.join("command-port");
|
||||||
let mut file = std::fs::File::create(path_buf)?;
|
let mut file = std::fs::File::create(path_buf)?;
|
||||||
file.write_all(udp.local_addr()?.port().to_string().as_bytes())?;
|
let addr = udp.local_addr()?;
|
||||||
|
file.write_all(addr.port().to_string().as_bytes())?;
|
||||||
file.sync_all()?;
|
file.sync_all()?;
|
||||||
|
log::info!("启动后台cmd:{:?}", addr);
|
||||||
let mut buf = [0u8; 64];
|
let mut buf = [0u8; 64];
|
||||||
loop {
|
loop {
|
||||||
let (len, addr) = udp.recv_from(&mut buf).await?;
|
let (len, addr) = udp.recv_from(&mut buf).await?;
|
||||||
match std::str::from_utf8(&buf[..len]) {
|
match std::str::from_utf8(&buf[..len]) {
|
||||||
Ok(cmd) => {
|
Ok(cmd) => {
|
||||||
|
log::info!("收到cmd={:?}", cmd);
|
||||||
if let Ok(out) = command(cmd, &vnt) {
|
if let Ok(out) = command(cmd, &vnt) {
|
||||||
let _ = udp.send_to(out.as_bytes(), addr).await;
|
if let Err(e) = udp.send_to(out.as_bytes(), addr).await {
|
||||||
|
log::warn!("cmd={},err={:?}", cmd, e);
|
||||||
|
}
|
||||||
if "stopped" == &out {
|
if "stopped" == &out {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use vnt::channel::punch::PunchModel;
|
||||||
|
use vnt::cipher::CipherModel;
|
||||||
|
use vnt::core::Config;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct FileConfig {
|
||||||
|
pub tap: bool,
|
||||||
|
pub token: String,
|
||||||
|
pub device_id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub server_address: String,
|
||||||
|
pub stun_server: Vec<String>,
|
||||||
|
pub in_ips: Vec<String>,
|
||||||
|
pub out_ips: Vec<String>,
|
||||||
|
pub password: Option<String>,
|
||||||
|
pub simulate_multicast: bool,
|
||||||
|
pub mtu: Option<u16>,
|
||||||
|
pub tcp: bool,
|
||||||
|
pub ip: Option<String>,
|
||||||
|
pub relay: bool,
|
||||||
|
pub server_encrypt: bool,
|
||||||
|
pub parallel: usize,
|
||||||
|
pub cipher_model: String,
|
||||||
|
pub finger: bool,
|
||||||
|
pub punch_model: String,
|
||||||
|
pub port: u16,
|
||||||
|
pub cmd: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FileConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
tap: false,
|
||||||
|
token: "".to_string(),
|
||||||
|
device_id: get_device_id(),
|
||||||
|
name: os_info::get().to_string(),
|
||||||
|
server_address: "nat1.wherewego.top:29872".to_string(),
|
||||||
|
stun_server: vec![
|
||||||
|
"stun1.l.google.com:19302".to_string(),
|
||||||
|
"stun2.l.google.com:19302".to_string(),
|
||||||
|
"stun.qq.com:3478".to_string(),
|
||||||
|
],
|
||||||
|
in_ips: vec![],
|
||||||
|
out_ips: vec![],
|
||||||
|
password: None,
|
||||||
|
simulate_multicast: false,
|
||||||
|
mtu: None,
|
||||||
|
tcp: false,
|
||||||
|
ip: None,
|
||||||
|
relay: false,
|
||||||
|
server_encrypt: false,
|
||||||
|
parallel: 1,
|
||||||
|
cipher_model: "aes_gcm".to_string(),
|
||||||
|
finger: false,
|
||||||
|
punch_model: "".to_string(),
|
||||||
|
port: 0,
|
||||||
|
cmd: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
|
||||||
|
let conf = std::fs::read_to_string(file_path)?;
|
||||||
|
let file_conf = match serde_yaml::from_str::<FileConfig>(&conf) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("{}", e)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if file_conf.token.is_empty() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "token is_empty"));
|
||||||
|
}
|
||||||
|
let server_address = match file_conf.server_address.to_socket_addrs() {
|
||||||
|
Ok(mut addr) => {
|
||||||
|
if let Some(addr) = addr.next() {
|
||||||
|
addr
|
||||||
|
} else {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("server_address {:?} error", &file_conf.server_address),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("server_address {:?} error:{}", &file_conf.server_address, e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
|
||||||
|
Ok(in_ips) => in_ips,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("in_ips {:?} error:{}", &file_conf.in_ips, e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let out_ips = match common::args_parse::out_ips_parse(&file_conf.out_ips) {
|
||||||
|
Ok(out_ips) => out_ips,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("out_ips {:?} error:{}", &file_conf.out_ips, e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let virtual_ip = match file_conf.ip.clone().map(|v| Ipv4Addr::from_str(&v)) {
|
||||||
|
None => None,
|
||||||
|
Some(r) => Some(r.map_err(|e| {
|
||||||
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("ip {:?} error:{}", &file_conf.ip, e),
|
||||||
|
)
|
||||||
|
})?),
|
||||||
|
};
|
||||||
|
|
||||||
|
let cipher_model = CipherModel::from_str(&file_conf.cipher_model)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||||
|
|
||||||
|
let punch_model = PunchModel::from_str(&file_conf.punch_model)
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||||
|
let config = Config::new(
|
||||||
|
file_conf.tap,
|
||||||
|
file_conf.token,
|
||||||
|
file_conf.device_id,
|
||||||
|
file_conf.name,
|
||||||
|
server_address,
|
||||||
|
file_conf.server_address,
|
||||||
|
file_conf.stun_server,
|
||||||
|
in_ips,
|
||||||
|
out_ips,
|
||||||
|
file_conf.password,
|
||||||
|
file_conf.simulate_multicast,
|
||||||
|
file_conf.mtu,
|
||||||
|
file_conf.tcp,
|
||||||
|
virtual_ip,
|
||||||
|
file_conf.relay,
|
||||||
|
file_conf.server_encrypt,
|
||||||
|
file_conf.parallel,
|
||||||
|
cipher_model,
|
||||||
|
file_conf.finger,
|
||||||
|
punch_model,
|
||||||
|
file_conf.port,
|
||||||
|
);
|
||||||
|
Ok((config, file_conf.cmd))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_device_id() -> String {
|
||||||
|
if let Some(id) = common::identifier::get_unique_identifier() {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
let path_buf = crate::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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+199
-143
@@ -16,6 +16,7 @@ use vnt::handle::handshake_handler::HandshakeEnum;
|
|||||||
use vnt::handle::registration_handler::ReqEnum;
|
use vnt::handle::registration_handler::ReqEnum;
|
||||||
|
|
||||||
mod command;
|
mod command;
|
||||||
|
mod config;
|
||||||
mod console_out;
|
mod console_out;
|
||||||
mod root_check;
|
mod root_check;
|
||||||
|
|
||||||
@@ -54,12 +55,10 @@ fn main() {
|
|||||||
opts.optopt("", "thread", "线程数(必须为正整数)", "<thread>");
|
opts.optopt("", "thread", "线程数(必须为正整数)", "<thread>");
|
||||||
opts.optopt("", "model", "加密模式", "<model>");
|
opts.optopt("", "model", "加密模式", "<model>");
|
||||||
opts.optflag("", "finger", "指纹校验");
|
opts.optflag("", "finger", "指纹校验");
|
||||||
opts.optopt(
|
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
|
||||||
"",
|
opts.optopt("", "port", "监听的端口", "<port>");
|
||||||
"punch",
|
opts.optflag("", "cmd", "开启窗口输入");
|
||||||
"取值ipv4/ipv6,表示仅使用ipv4或ipv6打洞",
|
opts.optopt("f", "", "配置文件", "<conf>");
|
||||||
"<punch>",
|
|
||||||
);
|
|
||||||
//"后台运行时,查看其他设备列表"
|
//"后台运行时,查看其他设备列表"
|
||||||
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
||||||
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
|
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
|
||||||
@@ -101,156 +100,192 @@ fn main() {
|
|||||||
command::command(command::CommandEnum::All);
|
command::command(command::CommandEnum::All);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !matches.opt_present("k") {
|
let conf = matches.opt_str("f");
|
||||||
print_usage(&program, opts);
|
let (config, cmd) = if conf.is_some() {
|
||||||
println!("parameter -k not found .");
|
match config::read_config(&conf.unwrap()) {
|
||||||
return;
|
Ok(c) => c,
|
||||||
}
|
Err(e) => {
|
||||||
let tap = matches.opt_present("a");
|
println!("conf err {}", e);
|
||||||
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:29872".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 .", server_address_str);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
} else {
|
||||||
println!("parameter '-s {}' error {}.", server_address_str, e);
|
if !matches.opt_present("k") {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
println!("parameter -k not found .");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
let tap = matches.opt_present("a");
|
||||||
let mut stun_server = matches.opt_strs("e");
|
let token: String = matches.opt_get("k").unwrap().unwrap();
|
||||||
if stun_server.is_empty() {
|
let device_id = matches.opt_get_default("d", String::new()).unwrap();
|
||||||
stun_server.push("stun1.l.google.com:19302".to_string());
|
let device_id = if device_id.is_empty() {
|
||||||
stun_server.push("stun2.l.google.com:19302".to_string());
|
config::get_device_id()
|
||||||
stun_server.push("stun.qq.com:3478".to_string());
|
} 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:29872".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 .", server_address_str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("parameter '-s {}' error {}.", server_address_str, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut stun_server = matches.opt_strs("e");
|
||||||
|
if stun_server.is_empty() {
|
||||||
|
stun_server.push("stun1.l.google.com:19302".to_string());
|
||||||
|
stun_server.push("stun2.l.google.com:19302".to_string());
|
||||||
|
stun_server.push("stun.qq.com:3478".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
let in_ip = matches.opt_strs("i");
|
let in_ip = matches.opt_strs("i");
|
||||||
let in_ip = match ips_parse(&in_ip) {
|
let in_ip = match ips_parse(&in_ip) {
|
||||||
Ok(in_ip) => in_ip,
|
Ok(in_ip) => in_ip,
|
||||||
Err(e) => {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
println!();
|
|
||||||
println!("-i: {:?} {}", in_ip, 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: {:?} {}", out_ip, e);
|
|
||||||
println!("example: -o 0.0.0.0/0");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let password: Option<String> = matches.opt_get("w").unwrap();
|
|
||||||
let server_encrypt = matches.opt_present("W");
|
|
||||||
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) => {
|
Err(e) => {
|
||||||
print_usage(&program, opts);
|
print_usage(&program, opts);
|
||||||
println!();
|
println!();
|
||||||
println!("'-u {}' {}", mtu, e);
|
println!("-i: {:?} {}", in_ip, 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: {:?} {}", out_ip, e);
|
||||||
|
println!("example: -o 0.0.0.0/0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let password: Option<String> = matches.opt_get("w").unwrap();
|
||||||
|
let server_encrypt = matches.opt_present("W");
|
||||||
|
#[cfg(not(feature = "server_encrypt"))]
|
||||||
|
{
|
||||||
|
if server_encrypt {
|
||||||
|
println!("Server encryption not supported");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
let simulate_multicast = matches.opt_present("m");
|
||||||
None
|
let mtu: Option<String> = matches.opt_get("u").unwrap();
|
||||||
};
|
let mtu = if let Some(mtu) = mtu {
|
||||||
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
|
match u16::from_str(&mtu) {
|
||||||
let virtual_ip =
|
Ok(mtu) => Some(mtu),
|
||||||
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
|
Err(e) => {
|
||||||
if let Some(virtual_ip) = virtual_ip {
|
print_usage(&program, opts);
|
||||||
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast() {
|
println!();
|
||||||
println!("'--ip {}' invalid", virtual_ip);
|
println!("'-u {}' {}", mtu, 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(&format!("'--ip {}' error", v)));
|
||||||
|
if let Some(virtual_ip) = virtual_ip {
|
||||||
|
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
|
||||||
|
{
|
||||||
|
println!("'--ip {}' invalid", virtual_ip);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let tcp_channel = matches.opt_present("tcp");
|
||||||
|
let relay = matches.opt_present("relay");
|
||||||
|
let parallel = matches.opt_get::<usize>("par").unwrap().unwrap_or(1);
|
||||||
|
if parallel == 0 {
|
||||||
|
println!("'--par {}' invalid", parallel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let tcp_channel = matches.opt_present("tcp");
|
|
||||||
let relay = matches.opt_present("relay");
|
|
||||||
let parallel = matches.opt_get::<usize>("par").unwrap().unwrap_or(1);
|
|
||||||
if parallel == 0 {
|
|
||||||
println!("'--par {}' invalid", parallel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cipher_model = match matches.opt_get::<CipherModel>("model") {
|
let cipher_model = match matches.opt_get::<CipherModel>("model") {
|
||||||
Ok(model) => model.unwrap_or(CipherModel::AesGcm),
|
Ok(model) => {
|
||||||
Err(e) => {
|
#[cfg(not(any(
|
||||||
println!("'--model ' invalid,{}", e);
|
feature = "aes_gcm",
|
||||||
return;
|
feature = "server_encrypt",
|
||||||
}
|
feature = "aes_cbc",
|
||||||
|
feature = "aes_ecb",
|
||||||
|
feature = "sm4_cbc"
|
||||||
|
)))]
|
||||||
|
{
|
||||||
|
if password.is_some() && model.is_none() {
|
||||||
|
println!("Encryption not supported");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
||||||
|
{
|
||||||
|
if password.is_some() && model.is_none() {
|
||||||
|
println!("'--model ' undefined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
model.unwrap_or(CipherModel::None)
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
|
model.unwrap_or(CipherModel::AesGcm)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("'--model ' invalid,{}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let finger = matches.opt_present("finger");
|
||||||
|
let punch_model = matches
|
||||||
|
.opt_get::<PunchModel>("punch")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap_or(PunchModel::All);
|
||||||
|
let port = matches.opt_get::<u16>("port").unwrap_or(None).unwrap_or(0);
|
||||||
|
let cmd = matches.opt_present("cmd");
|
||||||
|
let config = Config::new(
|
||||||
|
tap,
|
||||||
|
token,
|
||||||
|
device_id,
|
||||||
|
name,
|
||||||
|
server_address,
|
||||||
|
server_address_str,
|
||||||
|
stun_server,
|
||||||
|
in_ip,
|
||||||
|
out_ip,
|
||||||
|
password,
|
||||||
|
simulate_multicast,
|
||||||
|
mtu,
|
||||||
|
tcp_channel,
|
||||||
|
virtual_ip,
|
||||||
|
relay,
|
||||||
|
server_encrypt,
|
||||||
|
parallel,
|
||||||
|
cipher_model,
|
||||||
|
finger,
|
||||||
|
punch_model,
|
||||||
|
port,
|
||||||
|
);
|
||||||
|
(config, cmd)
|
||||||
};
|
};
|
||||||
|
|
||||||
let finger = matches.opt_present("finger");
|
|
||||||
let punch_model = matches
|
|
||||||
.opt_get::<PunchModel>("punch")
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_or(PunchModel::All);
|
|
||||||
println!("version {}", vnt::VNT_VERSION);
|
println!("version {}", vnt::VNT_VERSION);
|
||||||
let config = Config::new(
|
|
||||||
tap,
|
main0(config, cmd);
|
||||||
token,
|
|
||||||
device_id,
|
|
||||||
name,
|
|
||||||
server_address,
|
|
||||||
server_address_str,
|
|
||||||
stun_server,
|
|
||||||
in_ip,
|
|
||||||
out_ip,
|
|
||||||
password,
|
|
||||||
simulate_multicast,
|
|
||||||
mtu,
|
|
||||||
tcp_channel,
|
|
||||||
virtual_ip,
|
|
||||||
relay,
|
|
||||||
server_encrypt,
|
|
||||||
parallel,
|
|
||||||
cipher_model,
|
|
||||||
finger,
|
|
||||||
punch_model,
|
|
||||||
);
|
|
||||||
main0(config, !unused_cmd);
|
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,6 +397,7 @@ async fn main0(config: Config, show_cmd: bool) {
|
|||||||
let vnt_c = vnt.clone();
|
let vnt_c = vnt.clone();
|
||||||
tokio::spawn(async {
|
tokio::spawn(async {
|
||||||
if let Err(e) = command::server::CommandServer::new().start(vnt_c).await {
|
if let Err(e) = command::server::CommandServer::new().start(vnt_c).await {
|
||||||
|
log::warn!("cmd:{:?}", e);
|
||||||
println!("command error :{}", e);
|
println!("command error :{}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -437,28 +473,48 @@ fn print_usage(program: &str, _opts: Options) {
|
|||||||
println!("Options:");
|
println!("Options:");
|
||||||
println!(
|
println!(
|
||||||
" -k <token> {}",
|
" -k <token> {}",
|
||||||
green("必选,使用相同的token,就能组建一个局域网络".to_string())
|
green("使用相同的token,就能组建一个局域网络".to_string())
|
||||||
);
|
);
|
||||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
||||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip");
|
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip");
|
||||||
println!(" -c 关闭交互式命令,使用此参数禁用控制台输入");
|
|
||||||
println!(" -s <server> 注册和中继服务器地址");
|
println!(" -s <server> 注册和中继服务器地址");
|
||||||
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2");
|
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2");
|
||||||
println!(" -a 使用tap模式,默认使用tun模式");
|
println!(" -a 使用tap模式,默认使用tun模式");
|
||||||
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
|
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
|
||||||
println!(" 并转发到10.26.0.3,可指定多个网段");
|
println!(" 并转发到10.26.0.3,可指定多个网段");
|
||||||
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
|
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
|
||||||
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
|
let mut enums = String::new();
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
|
enums.push_str("/aes_gcm");
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
|
enums.push_str("/aes_cbc");
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
|
enums.push_str("/aes_ecb");
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
enums.push_str("/sm4_cbc");
|
||||||
|
if !enums.is_empty() {
|
||||||
|
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
|
||||||
|
}
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
|
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
|
||||||
println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
|
println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
|
||||||
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
|
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
|
||||||
|
println!(" -f <conf_file> 读取配置文件中的配置");
|
||||||
|
|
||||||
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
|
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
|
||||||
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
|
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
|
||||||
println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p");
|
println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p");
|
||||||
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
|
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
|
||||||
println!(" --model <model> 加密模式(默认aes_gcm),可选值aes_gcm/aes_cbc/aes_ecb,一般来说性能:aes_ecb>aes_cbc>aes_gcm");
|
if !enums.is_empty() {
|
||||||
|
println!(
|
||||||
|
" --model <model> 加密模式(默认aes_gcm),可选值{}",
|
||||||
|
&enums[1..]
|
||||||
|
);
|
||||||
|
}
|
||||||
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
|
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
|
||||||
println!(" --punch <punch> 取值ipv4/ipv6,ipv4表示仅使用ipv4打洞");
|
println!(" --punch <punch> 取值ipv4/ipv6,ipv4表示仅使用ipv4打洞");
|
||||||
|
println!(" --port <port> 取值0~65535,指定本地监听的端口,默认取随机端口");
|
||||||
|
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vnt-jni"
|
name = "vnt-jni"
|
||||||
version = "1.2.4"
|
version = "1.2.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<VntUtilSync, Error> {
|
|||||||
let finger = env.get_field(&config, "finger", "Z")?.z()?;
|
let finger = env.get_field(&config, "finger", "Z")?.z()?;
|
||||||
let in_ips = to_string(env, &config, "inIps")?;
|
let in_ips = to_string(env, &config, "inIps")?;
|
||||||
let out_ips = to_string(env, &config, "outIps")?;
|
let out_ips = to_string(env, &config, "outIps")?;
|
||||||
|
let port = env.get_field(&config, "port", "I")?.i()? as u16;
|
||||||
let in_ips = if let Some(in_ips) = in_ips {
|
let in_ips = if let Some(in_ips) = in_ips {
|
||||||
let in_ips: Vec<&str> = in_ips.split("\n").collect();
|
let in_ips: Vec<&str> = in_ips.split("\n").collect();
|
||||||
let in_ips = in_ips.iter().map(|v| v.to_string()).collect();
|
let in_ips = in_ips.iter().map(|v| v.to_string()).collect();
|
||||||
@@ -149,6 +150,7 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<VntUtilSync, Error> {
|
|||||||
cipher_model,
|
cipher_model,
|
||||||
finger,
|
finger,
|
||||||
PunchModel::All,
|
PunchModel::All,
|
||||||
|
port,
|
||||||
);
|
);
|
||||||
match VntUtilSync::new(config) {
|
match VntUtilSync::new(config) {
|
||||||
Ok(vnt_util) => Ok(vnt_util),
|
Ok(vnt_util) => Ok(vnt_util),
|
||||||
|
|||||||
+13
-9
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vnt"
|
name = "vnt"
|
||||||
version = "1.2.4"
|
version = "1.2.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -20,16 +20,16 @@ thiserror = "1.0.37"
|
|||||||
protobuf = "3.2.0"
|
protobuf = "3.2.0"
|
||||||
socket2 = { version = "0.5.2", features = ["all"] }
|
socket2 = { version = "0.5.2", features = ["all"] }
|
||||||
tokio = { version = "1.32.0", features = ["full"] }
|
tokio = { version = "1.32.0", features = ["full"] }
|
||||||
aes-gcm = { version = "0.10.2" }
|
aes-gcm = { version = "0.10.2",optional = true }
|
||||||
ring = { version = "0.16.20", optional = true }
|
ring = { version = "0.16.20", optional = true }
|
||||||
cbc = "0.1.2"
|
cbc = {version = "0.1.2",optional = true}
|
||||||
ecb = "0.1.2"
|
ecb = {version = "0.1.2",optional = true}
|
||||||
aes = "0.8.3"
|
aes = "0.8.3"
|
||||||
stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] }
|
stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] }
|
||||||
rsa = { version = "0.7.2", features = [] }
|
rsa = { version = "0.7.2", features = [] ,optional = true}
|
||||||
spki = { version = "0.6.0", features = ["fingerprint", "alloc"] }
|
spki = { version = "0.6.0", features = ["fingerprint", "alloc"] ,optional = true}
|
||||||
openssl-sys = { git = "https://github.com/lbl8603/rust-openssl" ,optional = true}
|
openssl-sys = { git = "https://github.com/lbl8603/rust-openssl" ,optional = true}
|
||||||
|
libsm = {git="https://github.com/lbl8603/libsm" ,optional = true}
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||||
tun = { path = "./rust-tun" }
|
tun = { path = "./rust-tun" }
|
||||||
@@ -44,10 +44,14 @@ protobuf-codegen = "3.2.0"
|
|||||||
protoc-bin-vendored = "3.0.0"
|
protoc-bin-vendored = "3.0.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc"]
|
||||||
openssl = ["openssl-sys"]
|
openssl = ["openssl-sys"]
|
||||||
# 从源码编译
|
# 从源码编译
|
||||||
openssl-vendored = ["openssl-sys/vendored"]
|
openssl-vendored = ["openssl-sys/vendored"]
|
||||||
ring-cipher = ["ring"]
|
ring-cipher = ["ring"]
|
||||||
|
aes_cbc=["cbc"]
|
||||||
|
aes_ecb=["ecb"]
|
||||||
|
sm4_cbc=["libsm"]
|
||||||
|
aes_gcm=["aes-gcm"]
|
||||||
|
server_encrypt =["rsa","spki"]
|
||||||
|
|
||||||
|
|||||||
+51
-47
@@ -522,10 +522,6 @@ impl Context {
|
|||||||
pub fn update_read_time(&self, id: &Ipv4Addr, route_key: &RouteKey) {
|
pub fn update_read_time(&self, id: &Ipv4Addr, route_key: &RouteKey) {
|
||||||
if let Some(mut time) = self.inner.route_table_time.get_mut(&(*route_key, *id)) {
|
if let Some(mut time) = self.inner.route_table_time.get_mut(&(*route_key, *id)) {
|
||||||
*time.value_mut() = Instant::now();
|
*time.value_mut() = Instant::now();
|
||||||
} else {
|
|
||||||
self.inner
|
|
||||||
.route_table_time
|
|
||||||
.insert((*route_key, *id), Instant::now());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,8 +591,7 @@ impl Channel {
|
|||||||
tcp_r
|
tcp_r
|
||||||
.read_exact(&mut buf[head_reserve..head_reserve + len])
|
.read_exact(&mut buf[head_reserve..head_reserve + len])
|
||||||
.await?;
|
.await?;
|
||||||
handler
|
handler.handle(&mut buf, head_reserve, head_reserve + len, key, &context);
|
||||||
.handle(&mut buf, head_reserve, head_reserve + len, key, &context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn start_tcp(
|
async fn start_tcp(
|
||||||
@@ -679,16 +674,20 @@ impl Channel {
|
|||||||
let main_channel = context.inner.main_channel.clone();
|
let main_channel = context.inner.main_channel.clone();
|
||||||
let buf_sender = if parallel > 1 {
|
let buf_sender = if parallel > 1 {
|
||||||
let (buf_sender, buf_receiver) = buf_channel_group(parallel);
|
let (buf_sender, buf_receiver) = buf_channel_group(parallel);
|
||||||
|
let mut num = 0;
|
||||||
for buf_receiver in buf_receiver.0 {
|
for buf_receiver in buf_receiver.0 {
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
let handler = handler.clone();
|
let handler = handler.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::Builder::new()
|
||||||
while let Ok((mut buf, start, end, route_key)) = buf_receiver.recv() {
|
.name(format!("recv-handler-{}", num))
|
||||||
handler
|
.spawn(move || {
|
||||||
.handle(&mut buf, start, end, route_key, &context);
|
while let Ok((mut buf, start, end, route_key)) = buf_receiver.recv() {
|
||||||
}
|
handler.handle(&mut buf, start, end, route_key, &context);
|
||||||
log::warn!("异步处理停止");
|
}
|
||||||
});
|
log::warn!("异步处理停止");
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
num += 1;
|
||||||
}
|
}
|
||||||
Some(buf_sender)
|
Some(buf_sender)
|
||||||
} else {
|
} else {
|
||||||
@@ -711,18 +710,21 @@ impl Channel {
|
|||||||
let main_channel_ipv6 = main_channel_ipv6.clone();
|
let main_channel_ipv6 = main_channel_ipv6.clone();
|
||||||
let handler = handler.clone();
|
let handler = handler.clone();
|
||||||
let buf_sender = buf_sender.clone();
|
let buf_sender = buf_sender.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::Builder::new()
|
||||||
log::info!("启动udp v6");
|
.name("ipv6-recv".into())
|
||||||
Self::main_start_(
|
.spawn(move || {
|
||||||
worker,
|
log::info!("启动udp v6");
|
||||||
context,
|
Self::main_start_(
|
||||||
UDP_V6_ID,
|
worker,
|
||||||
main_channel_ipv6,
|
context,
|
||||||
handler,
|
UDP_V6_ID,
|
||||||
buf_sender,
|
main_channel_ipv6,
|
||||||
head_reserve,
|
handler,
|
||||||
)
|
buf_sender,
|
||||||
});
|
head_reserve,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let worker = worker.worker("main_channel_1");
|
let worker = worker.worker("main_channel_1");
|
||||||
@@ -730,18 +732,21 @@ impl Channel {
|
|||||||
let main_channel = main_channel.clone();
|
let main_channel = main_channel.clone();
|
||||||
let handler = handler.clone();
|
let handler = handler.clone();
|
||||||
let buf_sender = buf_sender.clone();
|
let buf_sender = buf_sender.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::Builder::new()
|
||||||
log::info!("启动udp v4");
|
.name("ipv4-recv".into())
|
||||||
Self::main_start_(
|
.spawn(move || {
|
||||||
worker,
|
log::info!("启动udp v4");
|
||||||
context,
|
Self::main_start_(
|
||||||
UDP_ID,
|
worker,
|
||||||
main_channel,
|
context,
|
||||||
handler,
|
UDP_ID,
|
||||||
buf_sender,
|
main_channel,
|
||||||
head_reserve,
|
handler,
|
||||||
)
|
buf_sender,
|
||||||
});
|
head_reserve,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
if relay {
|
if relay {
|
||||||
worker.stop_wait().await;
|
worker.stop_wait().await;
|
||||||
@@ -815,14 +820,13 @@ impl Channel {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler
|
handler.handle(
|
||||||
.handle(
|
&mut buf,
|
||||||
&mut buf,
|
head_reserve,
|
||||||
head_reserve,
|
end,
|
||||||
end,
|
RouteKey::new(id, addr),
|
||||||
RouteKey::new(id, addr),
|
&context,
|
||||||
&context,
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("udp :{:?}", e);
|
log::error!("udp :{:?}", e);
|
||||||
@@ -864,11 +868,11 @@ impl Channel {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use std::os::windows::io::AsRawSocket;
|
use std::os::windows::io::AsRawSocket;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let id = 3 + udp.as_raw_socket() as usize;
|
let id = 3 + udp.as_raw_socket() as usize;
|
||||||
#[cfg(any(unix))]
|
#[cfg(any(unix))]
|
||||||
use std::os::fd::AsRawFd;
|
use std::os::fd::AsRawFd;
|
||||||
#[cfg(any(unix))]
|
#[cfg(any(unix))]
|
||||||
let id = 3 + udp.as_raw_fd() as usize;
|
let id = 3 + udp.as_raw_fd() as usize;
|
||||||
|
|
||||||
context.insert_udp(id, udp.clone());
|
context.insert_udp(id, udp.clone());
|
||||||
match buf_sender {
|
match buf_sender {
|
||||||
|
|||||||
@@ -51,10 +51,6 @@ impl AesEcbCipher {
|
|||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||||
}
|
}
|
||||||
if net_packet.payload().len() < 16 {
|
|
||||||
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let mut nonce_raw = [0; 12];
|
||||||
@@ -75,6 +71,10 @@ impl AesEcbCipher {
|
|||||||
}
|
}
|
||||||
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
||||||
}
|
}
|
||||||
|
if net_packet.payload().len() < 16 {
|
||||||
|
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
let mut out = [0u8; 1024 * 5];
|
let mut out = [0u8; 1024 * 5];
|
||||||
let rs = match self.key {
|
let rs = match self.key {
|
||||||
AesEcbEnum::AES128ECB(key) => Aes128EcbDec::new(&key.into())
|
AesEcbEnum::AES128ECB(key) => Aes128EcbDec::new(&key.into())
|
||||||
@@ -111,7 +111,7 @@ impl AesEcbCipher {
|
|||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
format!("解密失败:{}", e),
|
format!("aes_ecb解密失败:{}", e),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ impl AesEcbCipher {
|
|||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
format!("加密失败:{}", e),
|
format!("aes_ecb加密失败:{}", e),
|
||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -164,6 +164,8 @@ impl AesEcbCipher {
|
|||||||
fn test_aes_ecb() {
|
fn test_aes_ecb() {
|
||||||
let d = AesEcbCipher::new_128([0; 16], Some(Finger::new("123")));
|
let d = AesEcbCipher::new_128([0; 16], Some(Finger::new("123")));
|
||||||
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
|
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
d.encrypt_ipv4(&mut p).unwrap();
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
d.decrypt_ipv4(&mut p).unwrap();
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src)
|
||||||
}
|
}
|
||||||
|
|||||||
+95
-13
@@ -1,23 +1,37 @@
|
|||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
||||||
use crate::cipher::aes_ecb::AesEcbCipher;
|
use crate::cipher::aes_ecb::AesEcbCipher;
|
||||||
|
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
|
use crate::cipher::aes_cbc::AesCbcCipher;
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
#[cfg(not(feature = "ring-cipher"))]
|
#[cfg(not(feature = "ring-cipher"))]
|
||||||
use crate::cipher::aes_gcm_cipher::AesGcmCipher;
|
use crate::cipher::aes_gcm_cipher::AesGcmCipher;
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
||||||
use crate::cipher::openssl_aes_ecb::AesEcbCipher;
|
use crate::cipher::openssl_aes_ecb::AesEcbCipher;
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
#[cfg(feature = "ring-cipher")]
|
#[cfg(feature = "ring-cipher")]
|
||||||
use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher;
|
use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher;
|
||||||
use crate::cipher::{aes_cbc, Finger};
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
use crate::cipher::sm4_cbc::Sm4CbcCipher;
|
||||||
|
use crate::cipher::Finger;
|
||||||
use crate::protocol::NetPacket;
|
use crate::protocol::NetPacket;
|
||||||
use aes_cbc::AesCbcCipher;
|
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum CipherModel {
|
pub enum CipherModel {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
AesGcm,
|
AesGcm,
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
AesCbc,
|
AesCbc,
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
AesEcb,
|
AesEcb,
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
Sm4Cbc,
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for CipherModel {
|
impl FromStr for CipherModel {
|
||||||
@@ -25,19 +39,45 @@ impl FromStr for CipherModel {
|
|||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s.to_lowercase().trim() {
|
match s.to_lowercase().trim() {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
"aes_gcm" => Ok(CipherModel::AesGcm),
|
"aes_gcm" => Ok(CipherModel::AesGcm),
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
"aes_cbc" => Ok(CipherModel::AesCbc),
|
"aes_cbc" => Ok(CipherModel::AesCbc),
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
"aes_ecb" => Ok(CipherModel::AesEcb),
|
"aes_ecb" => Ok(CipherModel::AesEcb),
|
||||||
_ => Err(format!("not match '{}', enum:aes_gcm/aes_cbc/aes_ecb", s)),
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
"sm4_cbc" => Ok(CipherModel::Sm4Cbc),
|
||||||
|
_ => {
|
||||||
|
let mut enums = String::new();
|
||||||
|
#[cfg(feature = "aes_gcm")]
|
||||||
|
enums.push_str("/aes_gcm");
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
|
enums.push_str("/aes_cbc");
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
|
enums.push_str("/aes_ecb");
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
enums.push_str("/sm4_cbc");
|
||||||
|
let str = if enums.is_empty() {
|
||||||
|
"no encrypt"
|
||||||
|
} else {
|
||||||
|
&enums[1..]
|
||||||
|
};
|
||||||
|
Err(format!("not match '{}', enum:{}", s, str))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Cipher {
|
pub enum Cipher {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
AesGcm((AesGcmCipher, Vec<u8>)),
|
AesGcm((AesGcmCipher, Vec<u8>)),
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
AesCbc(AesCbcCipher),
|
AesCbc(AesCbcCipher),
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
AesEcb(AesEcbCipher),
|
AesEcb(AesEcbCipher),
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
Sm4Cbc(Sm4CbcCipher),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +93,7 @@ impl Cipher {
|
|||||||
hasher.update(password.as_bytes());
|
hasher.update(password.as_bytes());
|
||||||
let key: [u8; 32] = hasher.finalize().into();
|
let key: [u8; 32] = hasher.finalize().into();
|
||||||
match model {
|
match model {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
CipherModel::AesGcm => {
|
CipherModel::AesGcm => {
|
||||||
if password.len() < 8 {
|
if password.len() < 8 {
|
||||||
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
@@ -62,6 +103,7 @@ impl Cipher {
|
|||||||
Cipher::AesGcm((aes, key.to_vec()))
|
Cipher::AesGcm((aes, key.to_vec()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
CipherModel::AesCbc => {
|
CipherModel::AesCbc => {
|
||||||
if password.len() < 8 {
|
if password.len() < 8 {
|
||||||
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
@@ -71,6 +113,7 @@ impl Cipher {
|
|||||||
Cipher::AesCbc(aes)
|
Cipher::AesCbc(aes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
CipherModel::AesEcb => {
|
CipherModel::AesEcb => {
|
||||||
if password.len() < 8 {
|
if password.len() < 8 {
|
||||||
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
@@ -80,6 +123,12 @@ impl Cipher {
|
|||||||
Cipher::AesEcb(aes)
|
Cipher::AesEcb(aes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
CipherModel::Sm4Cbc => {
|
||||||
|
let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
|
Cipher::Sm4Cbc(aes)
|
||||||
|
}
|
||||||
|
CipherModel::None => Cipher::None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Cipher::None
|
Cipher::None
|
||||||
@@ -88,10 +137,12 @@ impl Cipher {
|
|||||||
pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> {
|
pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> {
|
||||||
let finger = Some(Finger::new(&token));
|
let finger = Some(Finger::new(&token));
|
||||||
match key.len() {
|
match key.len() {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
16 => {
|
16 => {
|
||||||
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
|
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
|
||||||
}
|
}
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
32 => {
|
32 => {
|
||||||
let aes = AesGcmCipher::new_256(key, finger);
|
let aes = AesGcmCipher::new_256(key, finger);
|
||||||
Ok(Cipher::AesGcm((aes, key.to_vec())))
|
Ok(Cipher::AesGcm((aes, key.to_vec())))
|
||||||
@@ -104,9 +155,14 @@ impl Cipher {
|
|||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet),
|
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet),
|
Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet),
|
Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.decrypt_ipv4(net_packet),
|
||||||
Cipher::None => {
|
Cipher::None => {
|
||||||
if net_packet.is_encrypt() {
|
if net_packet.is_encrypt() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not key"));
|
return Err(io::Error::new(io::ErrorKind::Other, "not key"));
|
||||||
@@ -120,30 +176,56 @@ impl Cipher {
|
|||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet),
|
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet),
|
Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet),
|
Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.encrypt_ipv4(net_packet),
|
||||||
Cipher::None => Ok(()),
|
Cipher::None => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
|
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
|
||||||
let finger = match self {
|
match self {
|
||||||
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.finger.as_ref(),
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesCbc(aes_cbc) => aes_cbc.finger.as_ref(),
|
Cipher::AesGcm((aes_gcm, _)) => aes_gcm
|
||||||
Cipher::AesEcb(aes_ecb) => aes_ecb.finger.as_ref(),
|
.finger
|
||||||
Cipher::None => None,
|
.as_ref()
|
||||||
};
|
.map(|f| f.check_finger(net_packet))
|
||||||
if let Some(finger) = finger {
|
.unwrap_or(Ok(())),
|
||||||
finger.check_finger(net_packet)
|
#[cfg(feature = "aes_cbc")]
|
||||||
} else {
|
Cipher::AesCbc(aes_cbc) => aes_cbc
|
||||||
Ok(())
|
.finger
|
||||||
|
.as_ref()
|
||||||
|
.map(|f| f.check_finger(net_packet))
|
||||||
|
.unwrap_or(Ok(())),
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
|
Cipher::AesEcb(aes_ecb) => aes_ecb
|
||||||
|
.finger
|
||||||
|
.as_ref()
|
||||||
|
.map(|f| f.check_finger(net_packet))
|
||||||
|
.unwrap_or(Ok(())),
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc
|
||||||
|
.finger
|
||||||
|
.as_ref()
|
||||||
|
.map(|f| f.check_finger(net_packet))
|
||||||
|
.unwrap_or(Ok(())),
|
||||||
|
Cipher::None => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn key(&self) -> Option<&[u8]> {
|
pub fn key(&self) -> Option<&[u8]> {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesGcm((_, key)) => Some(key),
|
Cipher::AesGcm((_, key)) => Some(key),
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()),
|
Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()),
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()),
|
Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()),
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
Cipher::Sm4Cbc(sm4_cbc) => Some(sm4_cbc.key()),
|
||||||
Cipher::None => None,
|
Cipher::None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
mod aes_cbc;
|
mod aes_cbc;
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
||||||
mod aes_ecb;
|
mod aes_ecb;
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
#[cfg(not(feature = "ring-cipher"))]
|
#[cfg(not(feature = "ring-cipher"))]
|
||||||
mod aes_gcm_cipher;
|
mod aes_gcm_cipher;
|
||||||
mod cipher;
|
mod cipher;
|
||||||
mod finger;
|
mod finger;
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
|
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
||||||
|
mod openssl_aes_ecb;
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
#[cfg(feature = "ring-cipher")]
|
#[cfg(feature = "ring-cipher")]
|
||||||
mod ring_aes_gcm_cipher;
|
mod ring_aes_gcm_cipher;
|
||||||
mod rsa_cipher;
|
mod rsa_cipher;
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
mod sm4_cbc;
|
||||||
mod openssl_aes_ecb;
|
|
||||||
|
|
||||||
pub use cipher::Cipher;
|
pub use cipher::Cipher;
|
||||||
pub use cipher::CipherModel;
|
pub use cipher::CipherModel;
|
||||||
pub use finger::Finger;
|
pub use finger::Finger;
|
||||||
|
|||||||
@@ -105,10 +105,6 @@ impl AesEcbCipher {
|
|||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||||
}
|
}
|
||||||
if net_packet.payload().len() < 16 {
|
|
||||||
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let mut nonce_raw = [0; 12];
|
||||||
@@ -129,6 +125,10 @@ impl AesEcbCipher {
|
|||||||
}
|
}
|
||||||
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
||||||
}
|
}
|
||||||
|
if net_packet.payload().len() < 16 {
|
||||||
|
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
let input = net_packet.payload();
|
let input = net_packet.payload();
|
||||||
let mut out = [0u8; 1024 * 5];
|
let mut out = [0u8; 1024 * 5];
|
||||||
let mut out_len = 0;
|
let mut out_len = 0;
|
||||||
|
|||||||
@@ -1,23 +1,32 @@
|
|||||||
use crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED};
|
|
||||||
use crate::protocol::NetPacket;
|
use crate::protocol::NetPacket;
|
||||||
use rand::Rng;
|
|
||||||
use rsa::pkcs8::der::Decode;
|
|
||||||
use rsa::{PublicKey, RsaPublicKey};
|
|
||||||
use sha2::Digest;
|
|
||||||
use spki::{DecodePublicKey, EncodePublicKey};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
|
use crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED};
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
|
use rand::Rng;
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
|
use rsa::pkcs8::der::Decode;
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
|
use rsa::{PublicKey, RsaPublicKey};
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
|
use sha2::Digest;
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
|
use spki::{DecodePublicKey, EncodePublicKey};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RsaCipher {
|
pub struct RsaCipher {
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
inner: Inner,
|
inner: Inner,
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Inner {
|
struct Inner {
|
||||||
public_key: RsaPublicKey,
|
public_key: RsaPublicKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RsaCipher {
|
impl RsaCipher {
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
pub fn new(der: &[u8]) -> io::Result<Self> {
|
pub fn new(der: &[u8]) -> io::Result<Self> {
|
||||||
match RsaPublicKey::from_public_key_der(der) {
|
match RsaPublicKey::from_public_key_der(der) {
|
||||||
Ok(public_key) => {
|
Ok(public_key) => {
|
||||||
@@ -30,6 +39,11 @@ impl RsaCipher {
|
|||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "server_encrypt"))]
|
||||||
|
pub fn new(_der: &[u8]) -> io::Result<Self> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
pub fn finger(&self) -> io::Result<String> {
|
pub fn finger(&self) -> io::Result<String> {
|
||||||
match self.inner.public_key.to_public_key_der() {
|
match self.inner.public_key.to_public_key_der() {
|
||||||
Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfo::from_der(der.as_bytes()) {
|
Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfo::from_der(der.as_bytes()) {
|
||||||
@@ -51,9 +65,21 @@ impl RsaCipher {
|
|||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "server_encrypt"))]
|
||||||
|
pub fn finger(&self) -> io::Result<String> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RsaCipher {
|
impl RsaCipher {
|
||||||
|
#[cfg(not(feature = "server_encrypt"))]
|
||||||
|
pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
_net_packet: &mut NetPacket<B>,
|
||||||
|
) -> io::Result<NetPacket<Vec<u8>>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
/// net_packet 必须预留足够长度
|
/// net_packet 必须预留足够长度
|
||||||
pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
use crate::cipher::Finger;
|
||||||
|
use crate::protocol::{NetPacket, HEAD_LEN};
|
||||||
|
use libsm::sm4::cipher_mode::CipherMode;
|
||||||
|
use libsm::sm4::Sm4CipherMode;
|
||||||
|
use rand::RngCore;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub struct Sm4CbcCipher {
|
||||||
|
key: [u8; 16],
|
||||||
|
pub(crate) cipher: Sm4CipherMode,
|
||||||
|
pub(crate) finger: Option<Finger>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Sm4CbcCipher {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let cipher = Sm4CipherMode::new(&self.key, CipherMode::Cbc).unwrap();
|
||||||
|
Self {
|
||||||
|
key: self.key,
|
||||||
|
cipher,
|
||||||
|
finger: self.finger.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sm4CbcCipher {
|
||||||
|
pub fn key(&self) -> &[u8] {
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sm4CbcCipher {
|
||||||
|
pub fn new_128(key: [u8; 16], finger: Option<Finger>) -> Self {
|
||||||
|
let cipher = Sm4CipherMode::new(&key, CipherMode::Cbc).unwrap();
|
||||||
|
Self {
|
||||||
|
key,
|
||||||
|
cipher,
|
||||||
|
finger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if !net_packet.is_encrypt() {
|
||||||
|
//未加密的数据直接丢弃
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let mut nonce_raw = [0; 12];
|
||||||
|
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
|
||||||
|
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||||
|
nonce_raw[8] = net_packet.protocol().into();
|
||||||
|
nonce_raw[9] = net_packet.transport_protocol();
|
||||||
|
nonce_raw[10] = net_packet.is_gateway() as u8;
|
||||||
|
nonce_raw[11] = net_packet.source_ttl();
|
||||||
|
let len = net_packet.payload().len();
|
||||||
|
if len < 12 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "payload len <12"));
|
||||||
|
}
|
||||||
|
let secret_body = &net_packet.payload()[..len - 12];
|
||||||
|
let finger = finger.calculate_finger(&nonce_raw, secret_body);
|
||||||
|
if &finger != &net_packet.payload()[len - 12..] {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
||||||
|
}
|
||||||
|
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
||||||
|
}
|
||||||
|
let payload = net_packet.payload();
|
||||||
|
let len = payload.len();
|
||||||
|
if len < 16 || len > 1024 * 4 {
|
||||||
|
log::error!("数据异常,长度{}小于16或大于4096", len);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
let mut out = [0u8; 1024 * 4];
|
||||||
|
let data = &payload[..len - 16];
|
||||||
|
let iv = &payload[len - 16..];
|
||||||
|
match self.cipher.decrypt(data, iv, &mut out) {
|
||||||
|
Ok(len) => {
|
||||||
|
let src_net_packet = NetPacket::new(&out[..len])?;
|
||||||
|
if src_net_packet.source() != net_packet.source() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
if src_net_packet.destination() != net_packet.destination() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
if src_net_packet.protocol() != net_packet.protocol() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
if src_net_packet.is_gateway() != net_packet.is_gateway() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
if src_net_packet.source_ttl() != net_packet.source_ttl() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
net_packet.set_data_len(len)?;
|
||||||
|
net_packet.set_payload(src_net_packet.payload())?;
|
||||||
|
net_packet.set_encrypt_flag(false);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("sm4_cbc解密失败:{}", e),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// net_packet 必须预留足够长度
|
||||||
|
/// data_len是有效载荷的长度
|
||||||
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let mut out = [0u8; 1024 * 4];
|
||||||
|
let mut iv = [0u8; 16];
|
||||||
|
rand::thread_rng().fill_bytes(&mut iv);
|
||||||
|
if net_packet.data_len() > 1024 * 4 - 32 {
|
||||||
|
log::error!(
|
||||||
|
"数据异常,长度{}大于1024 * 4 - 32",
|
||||||
|
net_packet.buffer().len()
|
||||||
|
);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||||
|
}
|
||||||
|
match self.cipher.encrypt(net_packet.buffer(), &iv, &mut out) {
|
||||||
|
Ok(len) => {
|
||||||
|
net_packet.set_data_len(HEAD_LEN + len + 16)?;
|
||||||
|
net_packet.payload_mut()[..len].copy_from_slice(&out[..len]);
|
||||||
|
net_packet.payload_mut()[len..].copy_from_slice(&iv);
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let mut nonce_raw = [0; 12];
|
||||||
|
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
|
||||||
|
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||||
|
nonce_raw[8] = net_packet.protocol().into();
|
||||||
|
nonce_raw[9] = net_packet.transport_protocol();
|
||||||
|
nonce_raw[10] = net_packet.is_gateway() as u8;
|
||||||
|
nonce_raw[11] = net_packet.source_ttl();
|
||||||
|
let finger = finger.calculate_finger(&nonce_raw, net_packet.payload());
|
||||||
|
let src_data_len = net_packet.data_len();
|
||||||
|
//设置实际长度
|
||||||
|
net_packet.set_data_len(src_data_len + finger.len())?;
|
||||||
|
|
||||||
|
net_packet.buffer_mut()[src_data_len..].copy_from_slice(&finger);
|
||||||
|
}
|
||||||
|
net_packet.set_encrypt_flag(true);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("sm4_cbc加密失败:{}", e),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sm4_ecb() {
|
||||||
|
let d = Sm4CbcCipher::new_128([0; 16], Some(Finger::new("123")));
|
||||||
|
let mut p = NetPacket::new_encrypt([1; 1024]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
let d = Sm4CbcCipher::new_128([0; 16], None);
|
||||||
|
let mut p = NetPacket::new_encrypt([1; 102]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src)
|
||||||
|
}
|
||||||
+14
-3
@@ -69,11 +69,11 @@ pub struct VntUtil {
|
|||||||
impl VntUtil {
|
impl VntUtil {
|
||||||
pub async fn new(config: Config) -> io::Result<VntUtil> {
|
pub async fn new(config: Config) -> io::Result<VntUtil> {
|
||||||
//单个udp用同步的性能更好,但是代理和多端口监听用异步更方便,这里将两者结合起来
|
//单个udp用同步的性能更好,但是代理和多端口监听用异步更方便,这里将两者结合起来
|
||||||
let main_channel = UdpSocket::bind("0.0.0.0:0")?;
|
let main_channel = UdpSocket::bind(format!("0.0.0.0:{}", config.port))?;
|
||||||
main_channel.set_write_timeout(Some(Duration::from_secs(5)))?;
|
main_channel.set_write_timeout(Some(Duration::from_secs(5)))?;
|
||||||
main_channel.set_read_timeout(Some(Duration::from_secs(2)))?;
|
main_channel.set_read_timeout(Some(Duration::from_secs(2)))?;
|
||||||
let main_channel_ipv6 = if config.punch_model != PunchModel::IPv4 {
|
let main_channel_ipv6 = if config.punch_model != PunchModel::IPv4 {
|
||||||
match UdpSocket::bind("[::]:0") {
|
match UdpSocket::bind(format!("[::]:{}", config.port)) {
|
||||||
Ok(main_channel_ipv6) => {
|
Ok(main_channel_ipv6) => {
|
||||||
main_channel_ipv6.set_write_timeout(Some(Duration::from_secs(5)))?;
|
main_channel_ipv6.set_write_timeout(Some(Duration::from_secs(5)))?;
|
||||||
Some(main_channel_ipv6)
|
Some(main_channel_ipv6)
|
||||||
@@ -403,12 +403,20 @@ impl VntUtil {
|
|||||||
let device_list = device_list.clone();
|
let device_list = device_list.clone();
|
||||||
let current_device = current_device.clone();
|
let current_device = current_device.clone();
|
||||||
// 定时心跳
|
// 定时心跳
|
||||||
|
heartbeat_handler::start_heartbeat_main(
|
||||||
|
vnt_status_manager.worker("main-heartbeat"),
|
||||||
|
channel_sender.clone(),
|
||||||
|
device_list.clone(),
|
||||||
|
current_device.clone(),
|
||||||
|
config.server_address_str,
|
||||||
|
client_cipher.clone(),
|
||||||
|
self.server_cipher.clone(),
|
||||||
|
);
|
||||||
heartbeat_handler::start_heartbeat(
|
heartbeat_handler::start_heartbeat(
|
||||||
vnt_status_manager.worker("heartbeat"),
|
vnt_status_manager.worker("heartbeat"),
|
||||||
channel_sender.clone(),
|
channel_sender.clone(),
|
||||||
device_list.clone(),
|
device_list.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
config.server_address_str,
|
|
||||||
client_cipher.clone(),
|
client_cipher.clone(),
|
||||||
self.server_cipher.clone(),
|
self.server_cipher.clone(),
|
||||||
);
|
);
|
||||||
@@ -569,6 +577,7 @@ pub struct Config {
|
|||||||
pub cipher_model: CipherModel,
|
pub cipher_model: CipherModel,
|
||||||
pub finger: bool,
|
pub finger: bool,
|
||||||
pub punch_model: PunchModel,
|
pub punch_model: PunchModel,
|
||||||
|
pub port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -593,6 +602,7 @@ impl Config {
|
|||||||
cipher_model: CipherModel,
|
cipher_model: CipherModel,
|
||||||
finger: bool,
|
finger: bool,
|
||||||
punch_model: PunchModel,
|
punch_model: PunchModel,
|
||||||
|
port: u16,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
for x in stun_server.iter_mut() {
|
for x in stun_server.iter_mut() {
|
||||||
if !x.contains(":") {
|
if !x.contains(":") {
|
||||||
@@ -620,6 +630,7 @@ impl Config {
|
|||||||
cipher_model,
|
cipher_model,
|
||||||
finger,
|
finger,
|
||||||
punch_model,
|
punch_model,
|
||||||
|
port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,28 @@ async fn start_idle_(idle: Idle, sender: ChannelSender) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_heartbeat(
|
pub fn start_heartbeat(
|
||||||
|
mut worker: VntWorker,
|
||||||
|
sender: ChannelSender,
|
||||||
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
client_cipher: Cipher,
|
||||||
|
server_cipher: Cipher,
|
||||||
|
) {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
tokio::select! {
|
||||||
|
_=worker.stop_wait()=>{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rs=start_heartbeat_(sender, device_list, current_device,client_cipher,server_cipher)=>{
|
||||||
|
if let Err(e) = rs {
|
||||||
|
log::warn!("心跳任务停止:{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
worker.stop_all();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pub fn start_heartbeat_main(
|
||||||
mut worker: VntWorker,
|
mut worker: VntWorker,
|
||||||
sender: ChannelSender,
|
sender: ChannelSender,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
@@ -56,11 +78,11 @@ pub fn start_heartbeat(
|
|||||||
_=worker.stop_wait()=>{
|
_=worker.stop_wait()=>{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rs=start_heartbeat_(sender, device_list, current_device,server_address_str,client_cipher,server_cipher)=>{
|
rs=start_heartbeat_main_(sender, device_list, current_device,server_address_str,client_cipher,server_cipher)=>{
|
||||||
if let Err(e) = rs {
|
if let Err(e) = rs {
|
||||||
log::warn!("心跳任务停止:{:?}", e);
|
log::warn!("主心跳任务停止:{:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
worker.stop_all();
|
worker.stop_all();
|
||||||
});
|
});
|
||||||
@@ -97,7 +119,7 @@ fn heartbeat_packet(
|
|||||||
net_packet
|
net_packet
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_heartbeat_(
|
async fn start_heartbeat_main_(
|
||||||
sender: ChannelSender,
|
sender: ChannelSender,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
@@ -106,26 +128,14 @@ async fn start_heartbeat_(
|
|||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
log::info!("启动心跳任务");
|
log::info!("启动主心跳任务");
|
||||||
loop {
|
loop {
|
||||||
if sender.is_close() {
|
if sender.is_close() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let mut current_dev = current_device.load();
|
let mut current_dev = current_device.load();
|
||||||
//如果和服务端使用tcp连接,则维持udp洞的频率要更高些
|
let src = current_dev.virtual_ip();
|
||||||
if (sender.is_main_tcp() && count % 2 == 0) || (!sender.is_main_tcp() && count % 20 == 1) {
|
if count % 40 == 19 {
|
||||||
let mut packet = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
|
|
||||||
packet.set_version(Version::V1);
|
|
||||||
packet.set_gateway_flag(true);
|
|
||||||
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);
|
|
||||||
server_cipher.encrypt_ipv4(&mut packet)?;
|
|
||||||
let _ = sender.send_main_udp(packet.buffer(), current_dev.connect_server);
|
|
||||||
}
|
|
||||||
if count % 20 == 19 {
|
|
||||||
if let Ok(mut addr) = server_address_str.to_socket_addrs() {
|
if let Ok(mut addr) = server_address_str.to_socket_addrs() {
|
||||||
if let Some(addr) = addr.next() {
|
if let Some(addr) = addr.next() {
|
||||||
if addr != current_dev.connect_server {
|
if addr != current_dev.connect_server {
|
||||||
@@ -143,7 +153,6 @@ async fn start_heartbeat_(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let src = current_dev.virtual_ip();
|
|
||||||
let server_packet = heartbeat_packet(
|
let server_packet = heartbeat_packet(
|
||||||
MAX_TTL,
|
MAX_TTL,
|
||||||
&device_list,
|
&device_list,
|
||||||
@@ -156,6 +165,41 @@ async fn start_heartbeat_(
|
|||||||
if let Err(e) = sender.send_main(server_packet.buffer(), current_dev.connect_server) {
|
if let Err(e) = sender.send_main(server_packet.buffer(), current_dev.connect_server) {
|
||||||
log::warn!("connect_server:{:?},e:{:?}", current_dev.connect_server, e);
|
log::warn!("connect_server:{:?},e:{:?}", current_dev.connect_server, e);
|
||||||
}
|
}
|
||||||
|
count += 1;
|
||||||
|
tokio::time::sleep(Duration::from_millis(3000)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_heartbeat_(
|
||||||
|
sender: ChannelSender,
|
||||||
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
client_cipher: Cipher,
|
||||||
|
server_cipher: Cipher,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let mut count = 0;
|
||||||
|
log::info!("启动心跳任务");
|
||||||
|
loop {
|
||||||
|
if sender.is_close() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let current_dev = current_device.load();
|
||||||
|
//如果和服务端使用tcp连接,则维持udp洞的频率要更高些
|
||||||
|
if (sender.is_main_tcp() && count % 4 == 0) || (!sender.is_main_tcp() && count % 40 == 1) {
|
||||||
|
let mut packet = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
|
||||||
|
packet.set_version(Version::V1);
|
||||||
|
packet.set_gateway_flag(true);
|
||||||
|
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);
|
||||||
|
server_cipher.encrypt_ipv4(&mut packet)?;
|
||||||
|
let _ = sender.send_main_udp(packet.buffer(), current_dev.connect_server);
|
||||||
|
}
|
||||||
|
|
||||||
|
let src = current_dev.virtual_ip();
|
||||||
|
|
||||||
if count < 7 || count % 7 == 0 {
|
if count < 7 || count % 7 == 0 {
|
||||||
let mut route_list: Option<Vec<(Ipv4Addr, Vec<Route>)>> = None;
|
let mut route_list: Option<Vec<(Ipv4Addr, Vec<Route>)>> = None;
|
||||||
let peer_list = { device_list.lock().1.clone() };
|
let peer_list = { device_list.lock().1.clone() };
|
||||||
@@ -251,6 +295,6 @@ async fn start_heartbeat_(
|
|||||||
}
|
}
|
||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
tokio::time::sleep(Duration::from_millis(5000)).await;
|
tokio::time::sleep(Duration::from_millis(3000)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
@@ -53,6 +54,7 @@ pub struct ChannelDataHandler {
|
|||||||
rsa_cipher: Option<RsaCipher>,
|
rsa_cipher: Option<RsaCipher>,
|
||||||
relay: bool,
|
relay: bool,
|
||||||
token: String,
|
token: String,
|
||||||
|
time: Arc<AtomicCell<Instant>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelDataHandler {
|
impl ChannelDataHandler {
|
||||||
@@ -93,6 +95,7 @@ impl ChannelDataHandler {
|
|||||||
rsa_cipher,
|
rsa_cipher,
|
||||||
relay,
|
relay,
|
||||||
token,
|
token,
|
||||||
|
time: Arc::new(AtomicCell::new(Instant::now())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,6 +135,7 @@ impl ChannelDataHandler {
|
|||||||
&& !destination.is_multicast()
|
&& !destination.is_multicast()
|
||||||
&& destination != current_device.broadcast_address;
|
&& destination != current_device.broadcast_address;
|
||||||
if current_device.virtual_ip() != destination
|
if current_device.virtual_ip() != destination
|
||||||
|
&& !net_packet.is_gateway()
|
||||||
&& not_broadcast
|
&& not_broadcast
|
||||||
&& !destination.is_unspecified()
|
&& !destination.is_unspecified()
|
||||||
{
|
{
|
||||||
@@ -160,6 +164,14 @@ impl ChannelDataHandler {
|
|||||||
== crate::protocol::error_packet::Protocol::NoKey.into()
|
== crate::protocol::error_packet::Protocol::NoKey.into()
|
||||||
{
|
{
|
||||||
if let Some(rsa_cipher) = &self.rsa_cipher {
|
if let Some(rsa_cipher) = &self.rsa_cipher {
|
||||||
|
let last = self.time.load();
|
||||||
|
if last.elapsed() < Duration::from_secs(3)
|
||||||
|
|| self.time.compare_exchange(last, Instant::now()).is_err()
|
||||||
|
{
|
||||||
|
//短时间不重复上传服务端密钥
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
log::warn!("上传服务端密钥");
|
||||||
secret_handshake_req(
|
secret_handshake_req(
|
||||||
context,
|
context,
|
||||||
current_device.connect_server,
|
current_device.connect_server,
|
||||||
@@ -273,8 +285,10 @@ impl ChannelDataHandler {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"不支持的ip代理Icmp协议:{}",
|
"不支持的ip代理Icmp协议:{}->{}->{}",
|
||||||
destination
|
source,
|
||||||
|
destination,
|
||||||
|
dest_ip
|
||||||
);
|
);
|
||||||
return Err(Error::Warn(
|
return Err(Error::Warn(
|
||||||
"不支持的ip代理Icmp协议".to_string(),
|
"不支持的ip代理Icmp协议".to_string(),
|
||||||
@@ -283,18 +297,36 @@ impl ChannelDataHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!("不支持的ip代理ipv4协议:{}", destination);
|
log::warn!(
|
||||||
|
"不支持的ip代理ipv4协议{:?}:{}->{}->{}",
|
||||||
|
ipv4.protocol(),
|
||||||
|
source,
|
||||||
|
destination,
|
||||||
|
ipv4.destination_ip()
|
||||||
|
);
|
||||||
return Err(Error::Warn(
|
return Err(Error::Warn(
|
||||||
"不支持的ip代理ipv4协议".to_string(),
|
"不支持的ip代理ipv4协议".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("没有ip代理规则:{}", destination);
|
log::warn!(
|
||||||
|
"没有ip代理规则{:?}:{}->{}->{}",
|
||||||
|
ipv4.protocol(),
|
||||||
|
source,
|
||||||
|
destination,
|
||||||
|
ipv4.destination_ip()
|
||||||
|
);
|
||||||
return Err(Error::Warn("没有ip代理规则".to_string()));
|
return Err(Error::Warn("没有ip代理规则".to_string()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("不支持ip代理:{}", destination);
|
log::warn!(
|
||||||
|
"不支持ip代理{:?}:{}->{}->{}",
|
||||||
|
ipv4.protocol(),
|
||||||
|
source,
|
||||||
|
destination,
|
||||||
|
ipv4.destination_ip()
|
||||||
|
);
|
||||||
return Err(Error::Warn("不支持ip代理".to_string()));
|
return Err(Error::Warn("不支持ip代理".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -632,12 +664,14 @@ impl ChannelDataHandler {
|
|||||||
service_packet::Protocol::RegistrationResponse => {
|
service_packet::Protocol::RegistrationResponse => {
|
||||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||||
|
|
||||||
{
|
if self.nat_test.can_update() {
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
let nat_test = self.nat_test.clone();
|
let nat_test = self.nat_test.clone();
|
||||||
std::thread::spawn(move ||{
|
std::thread::spawn(move || {
|
||||||
tokio::runtime::Builder::new_current_thread()
|
tokio::runtime::Builder::new_current_thread()
|
||||||
.enable_all().build().unwrap()
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
.block_on(async move {
|
.block_on(async move {
|
||||||
let local_port = context.main_local_ipv4_port().unwrap_or(0);
|
let local_port = context.main_local_ipv4_port().unwrap_or(0);
|
||||||
let local_ipv4_addr = nat::local_ipv4_addr(local_port);
|
let local_ipv4_addr = nat::local_ipv4_addr(local_port);
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ impl Register {
|
|||||||
}
|
}
|
||||||
pub fn fast_register(&self, ip: Ipv4Addr) -> crate::Result<()> {
|
pub fn fast_register(&self, ip: Ipv4Addr) -> crate::Result<()> {
|
||||||
let last = self.time.load();
|
let last = self.time.load();
|
||||||
if last.elapsed() < Duration::from_secs(2)
|
if last.elapsed() < Duration::from_secs(3)
|
||||||
|| self.time.compare_exchange(last, Instant::now()).is_err()
|
|| self.time.compare_exchange(last, Instant::now()).is_err()
|
||||||
{
|
{
|
||||||
//短时间不重复注册
|
//短时间不重复注册
|
||||||
|
|||||||
@@ -139,6 +139,9 @@ fn start_simple(
|
|||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let mut buf = [0; 4096];
|
let mut buf = [0; 4096];
|
||||||
loop {
|
loop {
|
||||||
|
if sender.is_close() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let len = device_reader.read(&mut buf)?;
|
let len = device_reader.read(&mut buf)?;
|
||||||
if let Err(e) = handle(
|
if let Err(e) = handle(
|
||||||
&mut buf,
|
&mut buf,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{SocketAddr, SocketAddrV4};
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::{Duration, Instant};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
|
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
|
||||||
@@ -84,15 +85,21 @@ impl TcpProxy {
|
|||||||
async fn proxy(client: TcpStream, server: TcpStream) -> io::Result<()> {
|
async fn proxy(client: TcpStream, server: TcpStream) -> io::Result<()> {
|
||||||
let (client_read, client_write) = client.into_split();
|
let (client_read, client_write) = client.into_split();
|
||||||
let (server_read, server_write) = server.into_split();
|
let (server_read, server_write) = server.into_split();
|
||||||
|
let time = Arc::new(AtomicCell::new(Instant::now()));
|
||||||
|
let time1 = time.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = copy(client_read, server_write).await {
|
if let Err(e) = copy(client_read, server_write, &time1).await {
|
||||||
log::warn!("{:?}", e);
|
log::warn!("{:?}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
copy(server_read, client_write).await
|
copy(server_read, client_write, &time).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn copy(mut read: OwnedReadHalf, mut write: OwnedWriteHalf) -> io::Result<()> {
|
async fn copy(
|
||||||
|
mut read: OwnedReadHalf,
|
||||||
|
mut write: OwnedWriteHalf,
|
||||||
|
time: &AtomicCell<Instant>,
|
||||||
|
) -> io::Result<()> {
|
||||||
let mut buf = [0; 10240];
|
let mut buf = [0; 10240];
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
@@ -102,9 +109,13 @@ async fn copy(mut read: OwnedReadHalf, mut write: OwnedWriteHalf) -> io::Result<
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
write.write_all(&buf[..len]).await?;
|
write.write_all(&buf[..len]).await?;
|
||||||
|
time.store(Instant::now());
|
||||||
}
|
}
|
||||||
_ = tokio::time::sleep(Duration::from_secs(300)) =>{
|
_ = tokio::time::sleep(Duration::from_secs(600)) =>{
|
||||||
break;
|
if time.load().elapsed()>=Duration::from_secs(580){
|
||||||
|
//读写均超时再退出
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use crate::ip_proxy::DashMapNew;
|
use crate::ip_proxy::DashMapNew;
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{SocketAddr, SocketAddrV4};
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
|
use tokio::time::Instant;
|
||||||
|
|
||||||
/// 一个udp代理,作用是利用系统协议栈,将udp数据报解析出来再转发到目的地址
|
/// 一个udp代理,作用是利用系统协议栈,将udp数据报解析出来再转发到目的地址
|
||||||
pub struct UdpProxy {
|
pub struct UdpProxy {
|
||||||
@@ -22,7 +24,8 @@ impl UdpProxy {
|
|||||||
let udp_socket = self.udp_socket;
|
let udp_socket = self.udp_socket;
|
||||||
let mut buf = [0u8; 65536];
|
let mut buf = [0u8; 65536];
|
||||||
|
|
||||||
let inner_map: Arc<DashMap<SocketAddrV4, Arc<UdpSocket>>> = Arc::new(DashMap::new0());
|
let inner_map: Arc<DashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>> =
|
||||||
|
Arc::new(DashMap::new0());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match udp_socket.recv_from(&mut buf).await {
|
match udp_socket.recv_from(&mut buf).await {
|
||||||
@@ -49,29 +52,36 @@ impl UdpProxy {
|
|||||||
async fn start0(
|
async fn start0(
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
sender_addr: SocketAddrV4,
|
sender_addr: SocketAddrV4,
|
||||||
inner_map: &Arc<DashMap<SocketAddrV4, Arc<UdpSocket>>>,
|
inner_map: &Arc<DashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>,
|
||||||
map: &Arc<DashMap<SocketAddrV4, SocketAddrV4>>,
|
map: &Arc<DashMap<SocketAddrV4, SocketAddrV4>>,
|
||||||
udp_socket: &Arc<UdpSocket>,
|
udp_socket: &Arc<UdpSocket>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
if let Some(entry) = inner_map.get(&sender_addr) {
|
if let Some(entry) = inner_map.get(&sender_addr) {
|
||||||
let udp = entry.value().clone();
|
entry.value().1.store(Instant::now());
|
||||||
|
let udp = entry.value().0.clone();
|
||||||
drop(entry);
|
drop(entry);
|
||||||
udp.send(buf).await?;
|
udp.send(buf).await?;
|
||||||
} else if let Some(entry) = map.get(&sender_addr) {
|
} else if let Some(entry) = map.get(&sender_addr) {
|
||||||
let dest_addr = *entry.value();
|
let dest_addr = *entry.value();
|
||||||
drop(entry);
|
drop(entry);
|
||||||
let peer_udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
//先使用相同的端口,冲突了再随机端口
|
||||||
|
let peer_udp_socket = match UdpSocket::bind(format!("0.0.0.0:{}", sender_addr.port())).await
|
||||||
|
{
|
||||||
|
Ok(udp) => udp,
|
||||||
|
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
|
||||||
|
};
|
||||||
peer_udp_socket.connect(dest_addr).await?;
|
peer_udp_socket.connect(dest_addr).await?;
|
||||||
peer_udp_socket.send(buf).await?;
|
peer_udp_socket.send(buf).await?;
|
||||||
let peer_udp_socket = Arc::new(peer_udp_socket);
|
let peer_udp_socket = Arc::new(peer_udp_socket);
|
||||||
let inner_map = inner_map.clone();
|
let inner_map = inner_map.clone();
|
||||||
inner_map.insert(sender_addr, peer_udp_socket.clone());
|
let time = Arc::new(AtomicCell::new(Instant::now()));
|
||||||
|
inner_map.insert(sender_addr, (peer_udp_socket.clone(), time.clone()));
|
||||||
let udp_socket = udp_socket.clone();
|
let udp_socket = udp_socket.clone();
|
||||||
let map = map.clone();
|
let map = map.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut buf = [0u8; 65536];
|
let mut buf = [0u8; 65536];
|
||||||
loop {
|
loop {
|
||||||
match tokio::time::timeout(Duration::from_secs(300), peer_udp_socket.recv(&mut buf))
|
match tokio::time::timeout(Duration::from_secs(600), peer_udp_socket.recv(&mut buf))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(rs) => match rs {
|
Ok(rs) => match rs {
|
||||||
@@ -98,9 +108,11 @@ async fn start0(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
//超时关闭
|
if time.load().elapsed() > Duration::from_secs(580) {
|
||||||
log::warn!("udp代理超时关闭,来源:{},目标:{}", sender_addr, dest_addr);
|
//超时关闭
|
||||||
break;
|
log::warn!("udp代理超时关闭,来源:{},目标:{}", sender_addr, dest_addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
pub const VNT_VERSION: &'static str = "1.2.4";
|
pub const VNT_VERSION: &'static str = "1.2.5";
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
|
|||||||
+15
-2
@@ -1,7 +1,9 @@
|
|||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
@@ -22,7 +24,7 @@ pub fn local_ipv4() -> io::Result<Ipv4Addr> {
|
|||||||
|
|
||||||
pub fn local_ipv6() -> io::Result<Ipv6Addr> {
|
pub fn local_ipv6() -> io::Result<Ipv6Addr> {
|
||||||
let socket = UdpSocket::bind("[::]:0")?;
|
let socket = UdpSocket::bind("[::]:0")?;
|
||||||
socket.connect("[2001:4860:4860::8888]:80")?;
|
socket.connect("[2001:4860:4860:0000:0000:0000:0000:8888]:80")?;
|
||||||
let addr = socket.local_addr()?;
|
let addr = socket.local_addr()?;
|
||||||
match addr.ip() {
|
match addr.ip() {
|
||||||
IpAddr::V4(_) => Ok(Ipv6Addr::UNSPECIFIED),
|
IpAddr::V4(_) => Ok(Ipv6Addr::UNSPECIFIED),
|
||||||
@@ -54,6 +56,7 @@ pub fn local_ipv6_addr(port: u16) -> SocketAddrV6 {
|
|||||||
pub struct NatTest {
|
pub struct NatTest {
|
||||||
stun_server: Vec<String>,
|
stun_server: Vec<String>,
|
||||||
info: Arc<Mutex<NatInfo>>,
|
info: Arc<Mutex<NatInfo>>,
|
||||||
|
time: Arc<AtomicCell<Instant>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NatType> for PunchNatType {
|
impl From<NatType> for PunchNatType {
|
||||||
@@ -93,7 +96,16 @@ impl NatTest {
|
|||||||
NatType::Cone,
|
NatType::Cone,
|
||||||
);
|
);
|
||||||
let info = Arc::new(Mutex::new(nat_info));
|
let info = Arc::new(Mutex::new(nat_info));
|
||||||
NatTest { stun_server, info }
|
NatTest {
|
||||||
|
stun_server,
|
||||||
|
info,
|
||||||
|
time: Arc::new(AtomicCell::new(Instant::now())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn can_update(&self) -> bool {
|
||||||
|
let last = self.time.load();
|
||||||
|
last.elapsed() > Duration::from_secs(10)
|
||||||
|
&& self.time.compare_exchange(last, Instant::now()).is_ok()
|
||||||
}
|
}
|
||||||
pub fn nat_info(&self) -> NatInfo {
|
pub fn nat_info(&self) -> NatInfo {
|
||||||
self.info.lock().clone()
|
self.info.lock().clone()
|
||||||
@@ -128,6 +140,7 @@ impl NatTest {
|
|||||||
ipv6_addr,
|
ipv6_addr,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
log::info!("探测nat类型={:?}", info);
|
||||||
*self.info.lock() = info.clone();
|
*self.info.lock() = info.clone();
|
||||||
info
|
info
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
pub const ENCRYPTION_RESERVED: usize = 32 + 12;
|
pub const ENCRYPTION_RESERVED: usize = 16 + 32 + 12;
|
||||||
pub const AES_GCM_ENCRYPTION_RESERVED: usize = 32;
|
pub const AES_GCM_ENCRYPTION_RESERVED: usize = 32;
|
||||||
pub const RSA_ENCRYPTION_RESERVED: usize = 32;
|
pub const RSA_ENCRYPTION_RESERVED: usize = 32;
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
|
|||||||
}
|
}
|
||||||
/// 网关通信的标识
|
/// 网关通信的标识
|
||||||
pub fn is_gateway(&self) -> bool {
|
pub fn is_gateway(&self) -> bool {
|
||||||
self.buffer.as_ref()[0] & 0x50 == 0x50
|
self.buffer.as_ref()[0] & 0x40 == 0x40
|
||||||
}
|
}
|
||||||
pub fn version(&self) -> Version {
|
pub fn version(&self) -> Version {
|
||||||
Version::from(self.buffer.as_ref()[0] & 0x0F)
|
Version::from(self.buffer.as_ref()[0] & 0x0F)
|
||||||
@@ -198,6 +198,7 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
|||||||
}
|
}
|
||||||
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
|
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
|
||||||
if is_gateway {
|
if is_gateway {
|
||||||
|
// 后面的版本再改为0x40,改了之后不兼容1.2.5之前的版本
|
||||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
|
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
|
||||||
} else {
|
} else {
|
||||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
|
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use bytes::BufMut;
|
|||||||
use packet::ethernet;
|
use packet::ethernet;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
#[cfg(any(target_os = "linux"))]
|
#[cfg(any(target_os = "linux"))]
|
||||||
use tun::platform::linux::Device;
|
use tun::platform::linux::Device;
|
||||||
#[cfg(any(target_os = "macos"))]
|
#[cfg(any(target_os = "macos"))]
|
||||||
@@ -112,16 +111,17 @@ impl DeviceWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn close(&self) -> io::Result<()> {
|
pub fn close(&self) -> io::Result<()> {
|
||||||
unsafe {
|
//早期使用close直接切断网卡,现在并不需要这么做也能正常关闭
|
||||||
match &self.writer {
|
// unsafe {
|
||||||
DeviceW::Tun(writer) => {
|
// match &self.writer {
|
||||||
libc::close(writer.as_raw_fd());
|
// DeviceW::Tun(writer) => {
|
||||||
}
|
// libc::close(writer.as_raw_fd());
|
||||||
DeviceW::Tap((writer, _)) => {
|
// }
|
||||||
libc::close(writer.as_raw_fd());
|
// DeviceW::Tap((writer, _)) => {
|
||||||
}
|
// libc::close(writer.as_raw_fd());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn is_tun(&self) -> bool {
|
pub fn is_tun(&self) -> bool {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ impl DeviceWriter {
|
|||||||
// 当前网段路由
|
// 当前网段路由
|
||||||
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::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||||
dev.add_route(
|
dev.add_route(
|
||||||
Ipv4Addr::from([224, 0, 0, 0]),
|
Ipv4Addr::from([224, 0, 0, 0]),
|
||||||
Ipv4Addr::from([240, 0, 0, 0]),
|
Ipv4Addr::from([240, 0, 0, 0]),
|
||||||
@@ -230,8 +230,8 @@ fn create_tun(
|
|||||||
}
|
}
|
||||||
// 当前网段路由
|
// 当前网段路由
|
||||||
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::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||||
tun_device.add_route(
|
tun_device.add_route(
|
||||||
Ipv4Addr::from([224, 0, 0, 0]),
|
Ipv4Addr::from([224, 0, 0, 0]),
|
||||||
Ipv4Addr::from([240, 0, 0, 0]),
|
Ipv4Addr::from([240, 0, 0, 0]),
|
||||||
@@ -309,7 +309,7 @@ fn create_tap(
|
|||||||
tap_device.add_route(*address, *netmask, gateway, 1)?;
|
tap_device.add_route(*address, *netmask, gateway, 1)?;
|
||||||
}
|
}
|
||||||
// 广播和组播路由
|
// 广播和组播路由
|
||||||
tap_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
// tap_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||||
tap_device.add_route(
|
tap_device.add_route(
|
||||||
Ipv4Addr::from([224, 0, 0, 0]),
|
Ipv4Addr::from([224, 0, 0, 0]),
|
||||||
Ipv4Addr::from([240, 0, 0, 0]),
|
Ipv4Addr::from([240, 0, 0, 0]),
|
||||||
|
|||||||
@@ -29,5 +29,6 @@ features = [
|
|||||||
"winerror",
|
"winerror",
|
||||||
"ipexport",
|
"ipexport",
|
||||||
"iphlpapi",
|
"iphlpapi",
|
||||||
"handleapi"
|
"handleapi",
|
||||||
|
"ifdef"
|
||||||
]
|
]
|
||||||
@@ -119,7 +119,8 @@ impl TapDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self) -> io::Result<()> {
|
pub fn delete(self) -> io::Result<()> {
|
||||||
iface::delete_interface(&self.luid)
|
// iface::delete_interface(&self.luid)
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
use winapi::um::{handleapi, synchapi, winbase, winnt};
|
use winapi::um::{synchapi, winbase, winnt};
|
||||||
|
|
||||||
use crate::{decode_utf16, encode_utf16, ffi, netsh, route, IFace};
|
use crate::{decode_utf16, encode_utf16, ffi, netsh, route, IFace};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
mod log;
|
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
|
mod wintun_log;
|
||||||
mod wintun_raw;
|
mod wintun_raw;
|
||||||
|
|
||||||
/// The maximum size of wintun's internal ring buffer (in bytes)
|
/// The maximum size of wintun's internal ring buffer (in bytes)
|
||||||
@@ -80,7 +80,7 @@ impl TunDevice {
|
|||||||
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) };
|
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) };
|
||||||
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
|
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
|
||||||
|
|
||||||
log::set_default_logger_if_unset(&win_tun);
|
wintun_log::set_default_logger_if_unset(&win_tun);
|
||||||
|
|
||||||
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
|
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
|
||||||
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
|
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
|
||||||
@@ -88,6 +88,7 @@ impl TunDevice {
|
|||||||
let adapter =
|
let adapter =
|
||||||
win_tun.WintunCreateAdapter(pool_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
|
win_tun.WintunCreateAdapter(pool_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
|
||||||
if adapter.is_null() {
|
if adapter.is_null() {
|
||||||
|
log::error!("adapter.is_null {:?}", io::Error::last_os_error());
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"Failed to crate adapter",
|
"Failed to crate adapter",
|
||||||
@@ -102,6 +103,7 @@ impl TunDevice {
|
|||||||
// 开启session
|
// 开启session
|
||||||
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
||||||
if session.is_null() {
|
if session.is_null() {
|
||||||
|
log::error!("session.is_null {:?}", io::Error::last_os_error());
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"WintunStartSession failed",
|
"WintunStartSession failed",
|
||||||
@@ -138,10 +140,14 @@ impl TunDevice {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log::set_default_logger_if_unset(&win_tun);
|
wintun_log::set_default_logger_if_unset(&win_tun);
|
||||||
let name_utf16 = encode_utf16(name);
|
let name_utf16 = encode_utf16(name);
|
||||||
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
|
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
|
||||||
if adapter.is_null() {
|
if adapter.is_null() {
|
||||||
|
log::error!(
|
||||||
|
"delete_for_name adapter.is_null {:?}",
|
||||||
|
io::Error::last_os_error()
|
||||||
|
);
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"Failed to open adapter",
|
"Failed to open adapter",
|
||||||
@@ -187,8 +193,8 @@ pub struct Version {
|
|||||||
|
|
||||||
impl IFace for TunDevice {
|
impl IFace for TunDevice {
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
fn shutdown(&self) -> io::Result<()> {
|
||||||
let _ = unsafe { synchapi::SetEvent(self.shutdown_event) };
|
// let _ = unsafe { synchapi::SetEvent(self.shutdown_event) };
|
||||||
let _ = unsafe { handleapi::CloseHandle(self.shutdown_event) };
|
// let _ = unsafe { handleapi::CloseHandle(self.shutdown_event) };
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user