Compare commits

...
18 Commits
Author SHA1 Message Date
lubeilin f104e191ed 修复route next显示问题 2023-07-30 10:54:37 +08:00
lubeilin 6311d75ac0 去除-o的ip指定 2023-07-30 10:52:07 +08:00
lubeilin c3f134e332 -o 使用默认网卡 2023-07-29 23:25:39 +08:00
lubeilin 5bccdf3bbe 修改版本,修改帮助信息 2023-07-29 23:03:52 +08:00
lubeilin 9e881eeecd 增加-o默认ip 2023-07-29 21:31:34 +08:00
lubeilin fbe01d8cbf 修复--route命令显示异常的问题 2023-07-29 21:14:31 +08:00
lbl8603 d336d938a9 Update README.md 2023-07-29 20:31:39 +08:00
lbl8603 598923c95a Update README.md 2023-07-29 20:29:38 +08:00
lbl8603 0afe4c4417 Update README.md 2023-07-29 20:02:44 +08:00
lubeilin dff51caf35 增加条件编译 2023-07-29 18:19:53 +08:00
lubeilin 7c30f2691a 增加条件编译 2023-07-29 18:09:15 +08:00
lubeilin c6aca2c2dc 添加编译依赖 2023-07-28 00:28:44 +08:00
lubeilin 28ac8cf88e 优化加解密速度 2023-07-26 21:32:10 +08:00
lubeilin 62b2af54a2 展示客户端中继状态 2023-07-26 21:31:34 +08:00
lubeilin a2d45da44d 修复校验和计算异常 2023-07-26 21:31:07 +08:00
lubeilin d937f392d3 修复代理icmp异常 2023-07-26 21:30:19 +08:00
lbl8603 2c9abf314a Update README.md 2023-07-25 23:15:09 +08:00
lbl8603 ab7abd0c1f Update README.md 2023-07-25 21:56:52 +08:00
26 changed files with 463 additions and 222 deletions
+16 -2
View File
@@ -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
+10
View File
@@ -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
View File
@@ -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
+38 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
停止后台运行
+8 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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"]
+1 -1
View File
@@ -103,9 +103,9 @@ pub fn ipv4_cal_checksum(
src_ip: &Ipv4Addr,
dest_ip: &Ipv4Addr,
protocol: u8,
length: u16,
) -> u16 {
use std::io::Cursor;
let length = buffer.len();
let mut sum = 0;
let src_ip = src_ip.octets();
sum += u32c(src_ip[0], src_ip[1]);
-1
View File
@@ -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 {
-1
View File
@@ -102,7 +102,6 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
&self.source_ip,
&self.destination_ip,
17,
self.length(),
)
}
}
+6 -4
View File
@@ -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) {
+1
View File
@@ -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 {
+115
View File
@@ -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
View File
@@ -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;
+132
View File
@@ -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
View File
@@ -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 {
+23 -1
View File
@@ -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
}
}
+1 -2
View File
@@ -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;
}
}
+8 -10
View File
@@ -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(
+1 -1
View File
@@ -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)?;
+2 -2
View File
@@ -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
View File
@@ -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,
}))
}
+5 -5
View File
@@ -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);
+7 -7
View File
@@ -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;
}
}