Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f104e191ed | ||
|
|
6311d75ac0 | ||
|
|
c3f134e332 | ||
|
|
5bccdf3bbe | ||
|
|
9e881eeecd | ||
|
|
fbe01d8cbf | ||
|
|
d336d938a9 | ||
|
|
598923c95a | ||
|
|
0afe4c4417 | ||
|
|
dff51caf35 | ||
|
|
7c30f2691a | ||
|
|
c6aca2c2dc | ||
|
|
28ac8cf88e | ||
|
|
62b2af54a2 | ||
|
|
a2d45da44d | ||
|
|
d937f392d3 | ||
|
|
2c9abf314a | ||
|
|
ab7abd0c1f |
@@ -40,36 +40,50 @@ jobs:
|
||||
include:
|
||||
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: x86_64-unknown-linux-gnu # tested in a debian container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-unknown-linux-gnu # tested on aws t4g.nano
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: armv7-unknown-linux-gnueabihf # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: arm-unknown-linux-gnueabihf # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: i686-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-latest
|
||||
FEATURES: ring-cipher
|
||||
# needs: test
|
||||
runs-on: ${{ matrix.OS }}
|
||||
env:
|
||||
NAME: vnt-cli # change with the name of your project
|
||||
TARGET: ${{ matrix.TARGET }}
|
||||
OS: ${{ matrix.OS }}
|
||||
FEATURES: ${{ matrix.FEATURES }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Init submodules
|
||||
@@ -88,7 +102,7 @@ jobs:
|
||||
# dependencies are only needed on ubuntu as that's the only place where
|
||||
# we make cross-compilation
|
||||
if [[ $OS =~ ^ubuntu.*$ ]]; then
|
||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf
|
||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools
|
||||
fi
|
||||
# some additional configuration for cross-compilation on linux
|
||||
cat >>~/.cargo/config <<EOF
|
||||
@@ -108,7 +122,7 @@ jobs:
|
||||
- name: Install rust target
|
||||
run: rustup target add $TARGET
|
||||
- name: Run build
|
||||
run: cargo build --package vnt-cli --release --verbose --target $TARGET
|
||||
run: cargo build --package vnt-cli --release --verbose --target $TARGET --features $FEATURES
|
||||
- name: List target
|
||||
run: find ./target
|
||||
- name: Compress
|
||||
|
||||
@@ -115,6 +115,13 @@ vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
|
||||
2. 解压后找到对应架构的目录,通常是amd64
|
||||
3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下)
|
||||
4. 再次启动vnt-cli
|
||||
|
||||
#### 问题3: 丢包严重,或是不能正常组网通信
|
||||
##### 可能原因:
|
||||
某些宽带下(比如广电宽带)UDP丢包严重
|
||||
##### 解决方法:
|
||||
1. 使用TCP模式中继转发(vnt-cli增加--tcp参数)
|
||||
2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--relay参数)
|
||||
|
||||
|
||||
</details>
|
||||
@@ -122,3 +129,6 @@ vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
|
||||
### 交流群
|
||||
|
||||
QQ:1034868233
|
||||
### 其他
|
||||
可使用社区小伙伴搭建的中继服务器
|
||||
1. -s vnt.8443.eu.org:29871
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -35,16 +35,45 @@ pub fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, String>
|
||||
} else {
|
||||
return Err("not ipv4".to_string());
|
||||
};
|
||||
let mask = if let Ok(m) = mask.parse::<u32>() {
|
||||
let mut mask = 0 as u32;
|
||||
for i in 0..m {
|
||||
mask = mask | (1 << (31 - i));
|
||||
}
|
||||
mask
|
||||
} else {
|
||||
return Err("not netmask".to_string());
|
||||
};
|
||||
let mask = to_ip(mask)?;
|
||||
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
|
||||
}
|
||||
Ok(in_ips_c)
|
||||
}
|
||||
|
||||
pub fn out_ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32)>, String> {
|
||||
let mut in_ips_c = vec![];
|
||||
for x in ips {
|
||||
let mut split = x.split("/");
|
||||
let dest = if let Some(dest) = split.next() {
|
||||
dest
|
||||
} else {
|
||||
return Err("no ipv4/mask".to_string());
|
||||
};
|
||||
let mask = if let Some(mask) = split.next() {
|
||||
mask
|
||||
} else {
|
||||
return Err("no netmask".to_string());
|
||||
};
|
||||
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
|
||||
dest
|
||||
} else {
|
||||
return Err("not ipv4".to_string());
|
||||
};
|
||||
let mask = to_ip(mask)?;
|
||||
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask));
|
||||
}
|
||||
Ok(in_ips_c)
|
||||
}
|
||||
|
||||
pub fn to_ip(mask: &str) -> Result<u32, String> {
|
||||
if let Ok(m) = mask.parse::<u32>() {
|
||||
let mut mask = 0 as u32;
|
||||
for i in 0..m {
|
||||
mask = mask | (1 << (31 - i));
|
||||
}
|
||||
Ok(mask)
|
||||
} else {
|
||||
Err("not netmask".to_string())
|
||||
}
|
||||
}
|
||||
+9
-6
@@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "vnt-cli"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vnt = {path="../vnt"}
|
||||
common = {path="../common"}
|
||||
vnt = { path = "../vnt", package = "vnt", optional = true }
|
||||
common = { path = "../common" }
|
||||
tokio = { version = "1.28.1", features = ["full"] }
|
||||
getopts = "0.2.21"
|
||||
console = "0.15.2"
|
||||
@@ -19,7 +19,7 @@ log = "0.4.17"
|
||||
[dependencies.uuid]
|
||||
version = "1.4.1"
|
||||
features = [
|
||||
"v4", # Lets you generate random UUIDs
|
||||
"v4", # Lets you generate random UUIDs
|
||||
]
|
||||
|
||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
@@ -27,9 +27,12 @@ sudo = "0.6.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
mini = []
|
||||
default = ["normal"]
|
||||
normal = ["vnt"]
|
||||
ring-cipher = ["vnt/ring-cipher"]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
embed-manifest = "1.4.0"
|
||||
+32
-9
@@ -1,21 +1,21 @@
|
||||
## 模块介绍
|
||||
体积小,可以在服务器、路由器等环境使用
|
||||
## 详细参数说明
|
||||
### -k
|
||||
### -k `<token>`
|
||||
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
|
||||
### -n
|
||||
### -n `<name>`
|
||||
设备名称,方便区分不同设备
|
||||
### -d
|
||||
### -d `<id>`
|
||||
设备id,每台设备的唯一标识,注意不要重复
|
||||
### -c
|
||||
关闭控制台交互式命令,后台运行时可以加此参数
|
||||
### -s
|
||||
### -s `<server>`
|
||||
注册和中继服务器地址,注册和转发数据
|
||||
### -e
|
||||
### -e `<addr1,addr2>`
|
||||
探测客户端NAT类型,不同类型有不同的打洞策略
|
||||
### -a
|
||||
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
|
||||
### -i、-o
|
||||
### -i `<in-ip>`、-o `<out-ip>`
|
||||
|
||||
配置点对网(IP代理)时使用,例如A(虚拟ip:10.26.0.2)通过B(虚拟ip:10.26.0.3,本地出口ip:192.168.0.10)访问C(目标网段192.168.0.0/24),
|
||||
|
||||
@@ -23,9 +23,17 @@
|
||||
|
||||
在B配置 **-o 192.168.0.0/24,192.168.0.10** ,表示允许将192.168.0.0/24的数据从网卡192.168.0.10转发出去
|
||||
|
||||
### -w
|
||||
注:-o 可以不配置出口ip,如直接使用 **-o 192.168.0.0/24** , 这将使用默认ip转发
|
||||
|
||||
### -w `<password>`
|
||||
|
||||
提升通信安全性,使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密。使用相同密码的客户端才能通信
|
||||
|
||||
| 密码位数 | 加密算法 |
|
||||
|---------|-------|
|
||||
| 小于8 | AES128-GCM
|
||||
| 大于等于8 | AES256-GCM |
|
||||
|
||||
### -m
|
||||
模拟组播,高频使用组播通信时,可以尝试开启此参数,默认情况下会把组播当作广播发给所有节点
|
||||
|
||||
@@ -33,8 +41,23 @@
|
||||
|
||||
模拟组播:高频使用组播时防止广播泛洪,客户端和中继服务器会维护组播成员等信息,注意使用此选项时,虚拟网内所有成员都需要开启此选项
|
||||
|
||||
### -u
|
||||
### -u `<mtu>`
|
||||
|
||||
设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值,默认值为1430
|
||||
|
||||
|
||||
### --tcp
|
||||
和服务端使用tcp通信。有些网络提供商对UDP限制比较大,这个时候可以选择使用TCP模式,提高稳定性。一般来说udp延迟和消耗更低
|
||||
### --ip `<IP>`
|
||||
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
|
||||
### --relay
|
||||
禁用p2p,在网络环境很差时,只使用服务器中转效果可能更好(可以配合--tcp参数一起使用)
|
||||
### --list
|
||||
在后台运行时,查看其他设备列表
|
||||
### --all
|
||||
在后台运行时,查看其他设备完整信息
|
||||
### --info
|
||||
在后台运行时,查看当前设备信息
|
||||
### --route
|
||||
在后台运行时,查看数据转发路径
|
||||
### --stop
|
||||
停止后台运行
|
||||
|
||||
@@ -72,6 +72,7 @@ pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
|
||||
}
|
||||
|
||||
pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
let info = vnt.current_device();
|
||||
let device_list = vnt.device_list();
|
||||
let mut list = Vec::new();
|
||||
for peer in device_list {
|
||||
@@ -87,7 +88,13 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
("".to_string(), "".to_string(), "".to_string())
|
||||
};
|
||||
let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
||||
let nat_traversal_type = if route.metric == 1 { "p2p" } else { "relay" }.to_string();
|
||||
let nat_traversal_type = if route.metric == 1 {
|
||||
"p2p"
|
||||
} else if route.addr == info.connect_server {
|
||||
"server-relay"
|
||||
} else {
|
||||
"client-relay"
|
||||
}.to_string();
|
||||
let rt = if route.rt < 0 {
|
||||
"".to_string()
|
||||
} else {
|
||||
|
||||
+9
-8
@@ -5,7 +5,7 @@ use std::str::FromStr;
|
||||
use console::style;
|
||||
use getopts::Options;
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
use common::args_parse::ips_parse;
|
||||
use common::args_parse::{ips_parse, out_ips_parse};
|
||||
use vnt::core::{Config, VntUtil};
|
||||
use vnt::handle::registration_handler::ReqEnum;
|
||||
|
||||
@@ -31,19 +31,18 @@ async fn main0() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let program = args[0].clone();
|
||||
let mut opts = Options::new();
|
||||
opts.long_only(false);
|
||||
opts.optopt("k", "", &format!("{}", green("必选,使用相同的token,就能组建一个局域网络".to_string())), "<token>");
|
||||
opts.optopt("n", "", "给设备一个名字,默认使用系统版本", "<name>");
|
||||
opts.optopt("d", "", "设备唯一标识符,不使用--ip参数时,服务端凭此参数分配ip", "<id>");
|
||||
opts.optopt("d", "", "设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip", "<id>");
|
||||
opts.optflag("c", "", "关闭交互式命令,使用此参数禁用控制台输入");
|
||||
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
|
||||
opts.optopt("e", "", "NAT探测服务器地址,使用逗号分隔", "<addr1,addr2>");
|
||||
opts.optflag("a", "", "使用tap模式,默认使用tun模式");
|
||||
opts.optmulti("i", "", "配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3,表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3", "<in-ip>");
|
||||
opts.optmulti("o", "", "配置点对网时使用,-o 192.168.0.0/24,192.168.0.10,表示允许目标为192.168.0.0/24的数据从网卡192.168.0.10转发出去", "<out-ip>");
|
||||
opts.optmulti("i", "", "配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3 \n表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3", "<in-ip>");
|
||||
opts.optmulti("o", "", "配置点对网时使用,-o 192.168.0.0/24 \n表示允许目标为192.168.0.0/24的数据转发出去", "<out-ip>");
|
||||
opts.optopt("w", "", "使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "<password>");
|
||||
opts.optflag("m", "", "模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
|
||||
opts.optopt("u", "", "虚拟网卡mtu值", "<mtu>");
|
||||
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
||||
opts.optflag("", "tcp", "和服务端使用tcp通信,默认使用udp,一般来说udp延迟和消耗更低");
|
||||
opts.optopt("", "ip", "指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配", "<IP>");
|
||||
opts.optflag("", "relay", "仅使用服务器转发,不使用p2p,默认情况允许使用p2p");
|
||||
@@ -146,16 +145,18 @@ async fn main0() {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-i {}", e);
|
||||
println!("example: -i 192.168.0.0/24,10.26.0.3");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let out_ip = matches.opt_strs("o");
|
||||
let out_ip = match ips_parse(&out_ip) {
|
||||
let out_ip = match out_ips_parse(&out_ip) {
|
||||
Ok(out_ip) => { out_ip }
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-o {}", e);
|
||||
println!("example: -o 0.0.0.0/0");
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -310,7 +311,7 @@ async fn main0() {
|
||||
|
||||
fn print_usage(program: &str, opts: Options) {
|
||||
let brief = format!("Usage: {} [options]", program);
|
||||
println!("version:1.1.1");
|
||||
println!("version:1.1.2");
|
||||
println!("{}", opts.usage(&brief));
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "vnt"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -15,12 +15,12 @@ crossbeam-skiplist = "0.1"
|
||||
parking_lot = "0.12.1"
|
||||
rand = "0.8.5"
|
||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||
aes-gcm = "0.10.2"
|
||||
|
||||
thiserror = "1.0.37"
|
||||
protobuf = "3.2.0"
|
||||
socket2 ={ version = "0.5.2", features = ["all"] }
|
||||
tokio = { version = "1.28.1", features = ["full"] }
|
||||
aes-gcm = {version="0.10.2", optional = true}
|
||||
ring = {version="0.16.20", optional = true}
|
||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
tun = { path = "./rust-tun" }
|
||||
|
||||
@@ -33,3 +33,8 @@ libloading = "0.7.4"
|
||||
protobuf-codegen = "3.2.0"
|
||||
protoc-bin-vendored = "3.0.0"
|
||||
|
||||
[features]
|
||||
default=["aes-gcm"]
|
||||
ring-cipher=["ring"]
|
||||
|
||||
|
||||
|
||||
@@ -103,9 +103,9 @@ pub fn ipv4_cal_checksum(
|
||||
src_ip: &Ipv4Addr,
|
||||
dest_ip: &Ipv4Addr,
|
||||
protocol: u8,
|
||||
length: u16,
|
||||
) -> u16 {
|
||||
use std::io::Cursor;
|
||||
let length = buffer.len();
|
||||
let mut sum = 0;
|
||||
let src_ip = src_ip.octets();
|
||||
sum += u32c(src_ip[0], src_ip[1]);
|
||||
|
||||
@@ -134,7 +134,6 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||
&self.source_ip,
|
||||
&self.destination_ip,
|
||||
6,
|
||||
self.buffer.as_ref().len() as u16,
|
||||
)
|
||||
}
|
||||
pub fn urgent_pointer(&self) -> u16 {
|
||||
|
||||
@@ -102,7 +102,6 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||
&self.source_ip,
|
||||
&self.destination_ip,
|
||||
17,
|
||||
self.length(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,9 +257,11 @@ impl Context {
|
||||
}
|
||||
}
|
||||
pub fn route_to_id(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
|
||||
for x in self.inner.route_table_time.iter() {
|
||||
if &x.key().0 == route_key {
|
||||
return Some(x.key().1);
|
||||
for x in self.inner.route_table.iter() {
|
||||
for route in x.value() {
|
||||
if &route.route_key() == route_key && route.is_p2p() {
|
||||
return Some(*x.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
@@ -311,8 +313,8 @@ impl Context {
|
||||
drop(v);
|
||||
routes.retain(|x| x.route_key() != route_key);
|
||||
self.inner.route_table.insert(*id, routes);
|
||||
self.inner.route_table_time.remove(&(route_key, *id));
|
||||
}
|
||||
self.inner.route_table_time.remove(&(route_key, *id));
|
||||
drop(guard);
|
||||
}
|
||||
pub fn update_read_time(&self, id: &Ipv4Addr, route_key: &RouteKey) {
|
||||
|
||||
@@ -29,6 +29,7 @@ impl Idle {
|
||||
for entry in self.context.inner.route_table_time.iter() {
|
||||
let last_read = entry.value().load().elapsed();
|
||||
if last_read >= self.read_idle {
|
||||
entry.remove();
|
||||
return Ok((entry.key().1.clone(), entry.key().0.clone()));
|
||||
} else {
|
||||
if max < last_read {
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
use std::io;
|
||||
|
||||
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, Nonce, Tag,KeyInit};
|
||||
use aes_gcm::aead::consts::{U12, U16};
|
||||
use aes_gcm::aead::generic_array::GenericArray;
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::protocol;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Cipher {
|
||||
AesGCM128(Aes128Gcm),
|
||||
AesGCM256(Aes256Gcm),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
pub fn new(password: Option<String>) -> Self {
|
||||
if let Some(password) = password {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(password.as_bytes());
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
if password.len() < 8 {
|
||||
let key: &Key<Aes128Gcm> = key[..16].into();
|
||||
Cipher::AesGCM128(Aes128Gcm::new(&key))
|
||||
} else {
|
||||
let key: &Key<Aes256Gcm> = &key.into();
|
||||
Cipher::AesGCM256(Aes256Gcm::new(&key))
|
||||
}
|
||||
} else {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
pub fn decrypt_ipv4(&self, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < 16 {
|
||||
log::error!("数据异常,长度小于16");
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce);
|
||||
let payload_len = net_packet.payload().len() - 16;
|
||||
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(&net_packet.payload()[payload_len..]);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher) => {
|
||||
cipher.decrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len], &tag)
|
||||
}
|
||||
Cipher::AesGCM256(cipher) => {
|
||||
cipher.decrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len], &tag)
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
if let Err(e) = rs {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)));
|
||||
}
|
||||
return Ok(Some(payload_len));
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
/// 返回加密后载荷的长度
|
||||
pub fn encrypt_ipv4(&self, payload_len: usize, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher) => {
|
||||
cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::AesGCM256(cipher) => {
|
||||
cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
return match rs {
|
||||
Ok(tag) => {
|
||||
if tag.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("加密tag长度错误:{}", tag.len())));
|
||||
}
|
||||
net_packet.set_encrypt_flag(true);
|
||||
net_packet.payload_mut()[payload_len..payload_len + 16].copy_from_slice(tag.as_slice());
|
||||
Ok(Some(payload_len + 16))
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+8
-115
@@ -1,115 +1,8 @@
|
||||
use std::io;
|
||||
|
||||
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, Nonce, Tag,KeyInit};
|
||||
use aes_gcm::aead::consts::{U12, U16};
|
||||
use aes_gcm::aead::generic_array::GenericArray;
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::protocol;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Cipher {
|
||||
AesGCM128(Aes128Gcm),
|
||||
AesGCM256(Aes256Gcm),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
pub fn new(password: Option<String>) -> Self {
|
||||
if let Some(password) = password {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(password.as_bytes());
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
if password.len() < 8 {
|
||||
let key: &Key<Aes128Gcm> = key[..16].into();
|
||||
Cipher::AesGCM128(Aes128Gcm::new(&key))
|
||||
} else {
|
||||
let key: &Key<Aes256Gcm> = &key.into();
|
||||
Cipher::AesGCM256(Aes256Gcm::new(&key))
|
||||
}
|
||||
} else {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
pub fn decrypt_ipv4(&self, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < 16 {
|
||||
log::error!("数据异常,长度小于16");
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce);
|
||||
let payload_len = net_packet.payload().len() - 16;
|
||||
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(&net_packet.payload()[payload_len..]);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher) => {
|
||||
cipher.decrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len], &tag)
|
||||
}
|
||||
Cipher::AesGCM256(cipher) => {
|
||||
cipher.decrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len], &tag)
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
if let Err(e) = rs {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)));
|
||||
}
|
||||
return Ok(Some(payload_len));
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
/// 返回加密后载荷的长度
|
||||
pub fn encrypt_ipv4(&self, payload_len: usize, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher) => {
|
||||
cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::AesGCM256(cipher) => {
|
||||
cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
return match rs {
|
||||
Ok(tag) => {
|
||||
if tag.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("加密tag长度错误:{}", tag.len())));
|
||||
}
|
||||
net_packet.set_encrypt_flag(true);
|
||||
net_packet.payload_mut()[payload_len..payload_len + 16].copy_from_slice(tag.as_slice());
|
||||
Ok(Some(payload_len + 16))
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "ring-cipher")]
|
||||
mod ring_cipher;
|
||||
#[cfg(feature = "ring-cipher")]
|
||||
pub use ring_cipher::Cipher;
|
||||
#[cfg(not(feature = "ring-cipher"))]
|
||||
mod aes_gcm_cipher;
|
||||
#[cfg(not(feature = "ring-cipher"))]
|
||||
pub use aes_gcm_cipher::Cipher;
|
||||
@@ -0,0 +1,132 @@
|
||||
|
||||
|
||||
use std::io;
|
||||
use ring::aead;
|
||||
use ring::aead::{LessSafeKey, UnboundKey};
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::protocol;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket};
|
||||
|
||||
pub enum Cipher {
|
||||
AesGCM128(LessSafeKey, [u8; 16]),
|
||||
AesGCM256(LessSafeKey, [u8; 32]),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Clone for Cipher {
|
||||
fn clone(&self) -> Self {
|
||||
match &self {
|
||||
Cipher::AesGCM128(_, key) => {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, key.as_slice()).unwrap());
|
||||
Cipher::AesGCM128(c, *key)
|
||||
}
|
||||
Cipher::AesGCM256(_, key) => {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, key.as_slice()).unwrap());
|
||||
Cipher::AesGCM256(c, *key)
|
||||
}
|
||||
Cipher::None => {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
pub fn new(password: Option<String>) -> Self {
|
||||
if let Some(password) = password {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(password.as_bytes());
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
if password.len() < 8 {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, &key[..16]).unwrap());
|
||||
Cipher::AesGCM128(c, key[..16].try_into().unwrap())
|
||||
} else {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, &key).unwrap());
|
||||
Cipher::AesGCM256(c, key)
|
||||
}
|
||||
} else {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
pub fn decrypt_ipv4(&self, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < 16 {
|
||||
log::error!("数据异常,长度小于16");
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce = aead::Nonce::assume_unique_for_key(nonce);
|
||||
let payload_len = net_packet.payload().len() - 16;
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher, _) => {
|
||||
cipher.open_in_place(nonce, aead::Aad::empty(), net_packet.payload_mut())
|
||||
}
|
||||
Cipher::AesGCM256(cipher, _) => {
|
||||
cipher.open_in_place(nonce, aead::Aad::empty(), net_packet.payload_mut())
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
if let Err(e) = rs {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)));
|
||||
}
|
||||
return Ok(Some(payload_len));
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
/// 返回加密后载荷的长度
|
||||
pub fn encrypt_ipv4(&self, payload_len: usize, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<Option<usize>> {
|
||||
match &self {
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let mut nonce = [0; 12];
|
||||
nonce[0..4].copy_from_slice(&net_packet.source().octets());
|
||||
nonce[4..8].copy_from_slice(&net_packet.destination().octets());
|
||||
nonce[8] = protocol::Protocol::IpTurn.into();
|
||||
nonce[9] = ip_turn_packet::Protocol::Ipv4.into();
|
||||
let nonce = aead::Nonce::assume_unique_for_key(nonce);
|
||||
let rs = match &self {
|
||||
Cipher::AesGCM128(cipher, _) => {
|
||||
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::AesGCM256(cipher, _) => {
|
||||
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), &mut net_packet.payload_mut()[..payload_len])
|
||||
}
|
||||
Cipher::None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
return match rs {
|
||||
Ok(tag) => {
|
||||
let tag = tag.as_ref();
|
||||
if tag.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("加密tag长度错误:{}", tag.len())));
|
||||
}
|
||||
net_packet.set_encrypt_flag(true);
|
||||
net_packet.payload_mut()[payload_len..payload_len + 16].copy_from_slice(tag);
|
||||
Ok(Some(payload_len + 16))
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+6
-8
@@ -17,7 +17,7 @@ use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntStatusManger;
|
||||
use crate::error::Error;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::external_route::{AllowExternalRoute, ExternalRoute};
|
||||
use crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, registration_handler};
|
||||
use crate::handle::recv_handler::ChannelDataHandler;
|
||||
use crate::handle::registration_handler::{RegResponse, ReqEnum};
|
||||
@@ -182,20 +182,18 @@ impl VntUtil {
|
||||
let local_port = context.main_local_port()?;
|
||||
// NAT检测
|
||||
let nat_test = NatTest::new(config.nat_test_server.clone(), response.public_ip, response.public_port, local_ip, local_port);
|
||||
|
||||
let out_ips = config.out_ips.iter().map(|(_, _, ip)| *ip).collect::<Vec<Ipv4Addr>>();
|
||||
let out_external_route = ExternalRoute::new(config.out_ips);
|
||||
let in_external_route = if config.in_ips.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ExternalRoute::new(config.in_ips))
|
||||
};
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = if out_ips.is_empty() {
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = if config.out_ips.is_empty() {
|
||||
(None, None, None)
|
||||
} else {
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = crate::ip_proxy::init_proxy(channel_sender.clone(), out_ips, current_device.clone()).await?;
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = crate::ip_proxy::init_proxy(channel_sender.clone(), current_device.clone()).await?;
|
||||
(Some(tcp_proxy), Some(udp_proxy), Some(ip_proxy_map))
|
||||
};
|
||||
let out_external_route = AllowExternalRoute::new(config.out_ips);
|
||||
|
||||
let igmp_server = if config.simulate_multicast {
|
||||
Some(IgmpServer::new(device_writer.clone()))
|
||||
@@ -339,7 +337,7 @@ pub struct Config {
|
||||
pub server_address_str: String,
|
||||
pub nat_test_server: Vec<SocketAddr>,
|
||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32)>,
|
||||
pub password: Option<String>,
|
||||
pub simulate_multicast: bool,
|
||||
pub mtu: Option<u16>,
|
||||
@@ -356,7 +354,7 @@ impl Config {
|
||||
server_address: SocketAddr,
|
||||
server_address_str: String,
|
||||
nat_test_server: Vec<SocketAddr>,
|
||||
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32)>,
|
||||
password: Option<String>, simulate_multicast: bool, mtu: Option<u16>, tcp: bool,
|
||||
ip: Option<Ipv4Addr>,
|
||||
relay: bool, ) -> Self {
|
||||
|
||||
@@ -11,7 +11,7 @@ pub struct ExternalRoute {
|
||||
impl ExternalRoute {
|
||||
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
|
||||
Self {
|
||||
route_table:Arc::new(route_table)
|
||||
route_table: Arc::new(route_table)
|
||||
}
|
||||
}
|
||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
|
||||
@@ -23,4 +23,26 @@ impl ExternalRoute {
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AllowExternalRoute {
|
||||
route_table: Arc<Vec<(u32, u32)>>,
|
||||
}
|
||||
|
||||
impl AllowExternalRoute {
|
||||
pub fn new(route_table: Vec<(u32, u32)>) -> Self {
|
||||
Self {
|
||||
route_table: Arc::new(route_table)
|
||||
}
|
||||
}
|
||||
pub fn allow(&self, ip: &Ipv4Addr) -> bool {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
for (dest, mask) in self.route_table.iter() {
|
||||
if *mask & ip == *mask & *dest {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,6 @@ async fn start_heartbeat_(
|
||||
} else {
|
||||
//没有直连路由则发送到网关
|
||||
let _ = sender.send_main(net_packet.buffer(), current_dev.connect_server).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
//再随机发送到其他地址,看有没有客户端符合转发条件
|
||||
@@ -167,7 +166,7 @@ async fn start_heartbeat_(
|
||||
num += 1;
|
||||
break;
|
||||
}
|
||||
if num >= 3 {
|
||||
if num >= 2 {
|
||||
break 'a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::channel::{Route, RouteKey};
|
||||
use crate::cipher::Cipher;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::external_route::AllowExternalRoute;
|
||||
use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, PeerDeviceStatus};
|
||||
use crate::handle::registration_handler::Register;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
@@ -41,7 +41,7 @@ pub struct ChannelDataHandler {
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
out_external_route: ExternalRoute,
|
||||
out_external_route: AllowExternalRoute,
|
||||
cone_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
symmetric_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
cipher: Cipher,
|
||||
@@ -58,7 +58,7 @@ impl ChannelDataHandler {
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
out_external_route: ExternalRoute,
|
||||
out_external_route: AllowExternalRoute,
|
||||
cone_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
symmetric_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
cipher: Cipher,
|
||||
@@ -185,7 +185,7 @@ impl ChannelDataHandler {
|
||||
}
|
||||
if not_broadcast && ipv4.destination_ip() != destination {
|
||||
if let Some(ip_proxy_map) = &self.ip_proxy_map {
|
||||
if let Some(gate_way) = self.out_external_route.route(&ipv4.destination_ip()) {
|
||||
if self.out_external_route.allow(&ipv4.destination_ip()) {
|
||||
match ipv4.protocol() {
|
||||
ipv4::protocol::Protocol::Tcp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
@@ -197,8 +197,7 @@ impl ChannelDataHandler {
|
||||
tcp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
ip_proxy_map.tcp_proxy_map.insert(SocketAddrV4::new(source, source_port),
|
||||
(SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port)));
|
||||
ip_proxy_map.tcp_proxy_map.insert(SocketAddrV4::new(source, source_port), SocketAddrV4::new(dest_ip, dest_port));
|
||||
}
|
||||
ipv4::protocol::Protocol::Udp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
@@ -210,8 +209,7 @@ impl ChannelDataHandler {
|
||||
udp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
ip_proxy_map.udp_proxy_map.insert(SocketAddrV4::new(source, source_port),
|
||||
(SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port)));
|
||||
ip_proxy_map.udp_proxy_map.insert(SocketAddrV4::new(source, source_port), SocketAddrV4::new(dest_ip, dest_port));
|
||||
}
|
||||
ipv4::protocol::Protocol::Icmp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
@@ -220,7 +218,7 @@ impl ChannelDataHandler {
|
||||
match icmp_packet.header_other() {
|
||||
HeaderOther::Identifier(id, seq) => {
|
||||
ip_proxy_map.icmp_proxy_map.insert((dest_ip, id, seq), source);
|
||||
ip_proxy_map.send_icmp(ipv4.payload(), &gate_way, &dest_ip)?;
|
||||
ip_proxy_map.send_icmp(ipv4.payload(), &dest_ip)?;
|
||||
}
|
||||
_ => {
|
||||
return Ok(());
|
||||
@@ -419,7 +417,7 @@ impl ChannelDataHandler {
|
||||
ControlPacket::AddrRequest => {
|
||||
match route_key.addr.ip() {
|
||||
std::net::IpAddr::V4(ipv4) => {
|
||||
let mut packet = NetPacket::new([0;12+6])?;
|
||||
let mut packet = NetPacket::new([0; 12 + 6])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(
|
||||
|
||||
@@ -178,7 +178,7 @@ fn registration_request_packet(
|
||||
request.virtual_ip = ip.into();
|
||||
request.allow_ip_change = allow_ip_change;
|
||||
request.is_fast = is_fast;
|
||||
request.version = "1.1.1".to_string();
|
||||
request.version = "1.1.2".to_string();
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let buf = vec![0u8; 12 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
|
||||
@@ -190,7 +190,7 @@ pub async fn base_handle(sender: &ChannelSender, buf: &mut [u8],
|
||||
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.tcp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value().1;
|
||||
let source_addr = entry.value();
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut tcp_packet = TcpPacket::new(source_ip, dest_ip, &mut net_packet.buffer_mut()[12 + ip_head_len..data_len])?;
|
||||
tcp_packet.set_source_port(source_addr.port());
|
||||
@@ -206,7 +206,7 @@ pub async fn base_handle(sender: &ChannelSender, buf: &mut [u8],
|
||||
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.udp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value().1;
|
||||
let source_addr = entry.value();
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut udp_packet = UdpPacket::new(source_ip, dest_ip, &mut net_packet.buffer_mut()[12 + ip_head_len..data_len])?;
|
||||
udp_packet.set_source_port(source_addr.port());
|
||||
|
||||
+16
-25
@@ -1,5 +1,4 @@
|
||||
use std::{io, thread};
|
||||
use std::collections::HashMap;
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
@@ -27,28 +26,23 @@ pub enum Protocol {
|
||||
pub struct IpProxyMap {
|
||||
pub(crate) tcp_proxy_port: u16,
|
||||
pub(crate) udp_proxy_port: u16,
|
||||
//真实源地址 -> (绑定地址,目的地址)
|
||||
pub(crate) tcp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
pub(crate) udp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
//真实源地址 -> 目的地址
|
||||
pub(crate) tcp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
pub(crate) udp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
// icmp用Identifier来区分,没有Identifier的一律不转发
|
||||
pub(crate) icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||
icmp_sockets: HashMap<Ipv4Addr, Arc<Socket>>,
|
||||
icmp_socket: Arc<Socket>,
|
||||
}
|
||||
|
||||
impl IpProxyMap {
|
||||
pub fn send_icmp(&self, buf: &[u8], src: &Ipv4Addr, dest: &Ipv4Addr) -> io::Result<usize> {
|
||||
if let Some(socket) = self.icmp_sockets.get(src) {
|
||||
socket.send_to(buf, &SockAddr::from(SocketAddrV4::new(*dest, 0)))
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("not found src:{},dest:{}", src, dest)))
|
||||
}
|
||||
pub fn send_icmp(&self, buf: &[u8], dest: &Ipv4Addr) -> io::Result<usize> {
|
||||
self.icmp_socket.send_to(buf, &SockAddr::from(SocketAddrV4::new(*dest, 0)))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init_proxy(sender: ChannelSender, bind_ips: Vec<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<(TcpProxy, UdpProxy, IpProxyMap)> {
|
||||
let mut icmp_sockets = HashMap::new();
|
||||
let tcp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>> = Arc::new(SkipMap::new());
|
||||
let udp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>> = Arc::new(SkipMap::new());
|
||||
pub async fn init_proxy(sender: ChannelSender, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<(TcpProxy, UdpProxy, IpProxyMap)> {
|
||||
let tcp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>> = Arc::new(SkipMap::new());
|
||||
let udp_proxy_map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>> = Arc::new(SkipMap::new());
|
||||
let icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>> = Arc::new(SkipMap::new());
|
||||
let tcp_listener = TcpListener::bind("0.0.0.0:0").await?;
|
||||
let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
@@ -56,15 +50,12 @@ pub async fn init_proxy(sender: ChannelSender, bind_ips: Vec<Ipv4Addr>, current_
|
||||
let udp_proxy_port = udp_socket.local_addr()?.port();
|
||||
let tcp_proxy = TcpProxy::new(tcp_listener, tcp_proxy_map.clone());
|
||||
let udp_proxy = UdpProxy::new(udp_socket, udp_proxy_map.clone());
|
||||
for ip in bind_ips {
|
||||
let addr = SocketAddrV4::new(ip, 0);
|
||||
let icmp_proxy_map = icmp_proxy_map.clone();
|
||||
let icmp_proxy = IcmpProxy::new(addr, icmp_proxy_map, sender.clone(), current_device.clone())?;
|
||||
icmp_sockets.insert(ip, icmp_proxy.icmp_socket());
|
||||
thread::spawn(move || {
|
||||
icmp_proxy.start();
|
||||
});
|
||||
}
|
||||
let addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0);
|
||||
let icmp_proxy = IcmpProxy::new(addr, icmp_proxy_map.clone(), sender.clone(), current_device.clone())?;
|
||||
let icmp_socket = icmp_proxy.icmp_socket();
|
||||
thread::spawn(move || {
|
||||
icmp_proxy.start();
|
||||
});
|
||||
|
||||
Ok((tcp_proxy, udp_proxy, IpProxyMap {
|
||||
tcp_proxy_port,
|
||||
@@ -72,6 +63,6 @@ pub async fn init_proxy(sender: ChannelSender, bind_ips: Vec<Ipv4Addr>, current_
|
||||
tcp_proxy_map,
|
||||
udp_proxy_map,
|
||||
icmp_proxy_map,
|
||||
icmp_sockets,
|
||||
icmp_socket,
|
||||
}))
|
||||
}
|
||||
@@ -6,11 +6,11 @@ use tokio::net::{TcpListener, TcpStream};
|
||||
|
||||
pub struct TcpProxy {
|
||||
tcp_listener: TcpListener,
|
||||
map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
}
|
||||
|
||||
impl TcpProxy {
|
||||
pub fn new(tcp_listener: TcpListener, map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>) -> Self {
|
||||
pub fn new(tcp_listener: TcpListener, map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>) -> Self {
|
||||
Self {
|
||||
tcp_listener,
|
||||
map,
|
||||
@@ -25,11 +25,11 @@ impl TcpProxy {
|
||||
match sender_addr {
|
||||
SocketAddr::V4(sender_addr) => {
|
||||
if let Some(entry) = map.get(&sender_addr) {
|
||||
let (src_addr, dest_addr) = *entry.value();
|
||||
let dest_addr = *entry.value();
|
||||
let peer_tcp_stream = match TcpStream::connect(dest_addr).await {
|
||||
Ok(peer_tcp_stream) => {peer_tcp_stream}
|
||||
Err(e) => {
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
@@ -38,7 +38,7 @@ impl TcpProxy {
|
||||
match proxy(tcp_stream, peer_tcp_stream).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
}
|
||||
}
|
||||
map.remove(&sender_addr);
|
||||
|
||||
@@ -8,11 +8,11 @@ use tokio::net::UdpSocket;
|
||||
/// 一个udp代理,作用是利用系统协议栈,将udp数据报解析出来再转发到目的地址
|
||||
pub struct UdpProxy {
|
||||
udp_socket: Arc<UdpSocket>,
|
||||
map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||
map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>,
|
||||
}
|
||||
|
||||
impl UdpProxy {
|
||||
pub fn new(udp_socket: UdpSocket, map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>) -> Self {
|
||||
pub fn new(udp_socket: UdpSocket, map: Arc<SkipMap<SocketAddrV4, SocketAddrV4>>) -> Self {
|
||||
let udp_socket = Arc::new(udp_socket);
|
||||
Self {
|
||||
udp_socket,
|
||||
@@ -48,11 +48,11 @@ impl UdpProxy {
|
||||
}
|
||||
}
|
||||
|
||||
async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<SocketAddrV4, Arc<UdpSocket>>>, map: &Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>, udp_socket: &Arc<UdpSocket>) -> io::Result<()> {
|
||||
async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<SocketAddrV4, Arc<UdpSocket>>>, map: &Arc<SkipMap<SocketAddrV4, SocketAddrV4>>, udp_socket: &Arc<UdpSocket>) -> io::Result<()> {
|
||||
if let Some(entry) = inner_map.get(&sender_addr) {
|
||||
entry.value().send(buf).await?;
|
||||
} else if let Some(entry) = map.get(&sender_addr) {
|
||||
let (src_addr, dest_addr) = *entry.value();
|
||||
let dest_addr = *entry.value();
|
||||
let peer_udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
peer_udp_socket.connect(dest_addr).await?;
|
||||
peer_udp_socket.send(buf).await?;
|
||||
@@ -71,20 +71,20 @@ async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<S
|
||||
match udp_socket.send_to(&buf[..len], sender_addr).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
//超时关闭
|
||||
log::warn!("udp代理超时关闭,来源:{},目标:{}",src_addr,dest_addr);
|
||||
log::warn!("udp代理超时关闭,来源:{},目标:{}",sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user