Merge pull request #38 from lbl8603/1.2.x

1.2.x
This commit is contained in:
lbl8603
2024-05-11 09:21:57 +08:00
committed by GitHub
62 changed files with 1805 additions and 1278 deletions
+9 -1
View File
@@ -105,6 +105,8 @@ jobs:
run: |
# dependencies are only needed on ubuntu as that's the only place where
# we make cross-compilation
rustup set auto-self-update disable
if [[ $OS =~ ^ubuntu.*$ ]]; then
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools
# curl -s musl.cc | grep mipsel
@@ -136,6 +138,9 @@ jobs:
# mips平台使用1.71.1版本
rustup install 1.71.1
rustup default 1.71.1
else
rustup install 1.77
rustup default 1.77
fi
if [ -n "$MUSL_URI" ]; then
@@ -144,8 +149,11 @@ jobs:
tar zxf ./musl_gcc/$MUSL_URI.tgz -C ./musl_gcc/
sudo ln -s $(pwd)/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
fi
else
rustup install 1.77
rustup default 1.77
fi
rustup -V
# some additional configuration for cross-compilation on linux
cat >>~/.cargo/config <<EOF
Generated
+151
View File
@@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aead"
version = "0.5.2"
@@ -52,6 +67,24 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_log-sys"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
[[package]]
name = "android_logger"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f"
dependencies = [
"android_log-sys",
"env_logger",
"log",
"once_cell",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
@@ -79,6 +112,21 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
[[package]]
name = "backtrace"
version = "0.3.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "base64ct"
version = "1.6.0"
@@ -352,6 +400,16 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "env_logger"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
dependencies = [
"log",
"regex",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@@ -422,6 +480,12 @@ dependencies = [
"polyval",
]
[[package]]
name = "gimli"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -434,6 +498,12 @@ version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "home"
version = "0.5.9"
@@ -656,6 +726,15 @@ version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.11"
@@ -726,6 +805,25 @@ dependencies = [
"libm",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "object"
version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -817,6 +915,12 @@ dependencies = [
"base64ct",
]
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pkcs1"
version = "0.7.5"
@@ -1096,6 +1200,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.32"
@@ -1195,6 +1305,15 @@ dependencies = [
"digest",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
[[package]]
name = "signature"
version = "2.2.0"
@@ -1343,6 +1462,36 @@ dependencies = [
"winapi",
]
[[package]]
name = "tokio"
version = "1.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"num_cpus",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-macros"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
]
[[package]]
name = "tun"
version = "0.1.0"
@@ -1468,6 +1617,7 @@ dependencies = [
"spki",
"stun-format",
"thiserror",
"tokio",
"tun",
]
@@ -1496,6 +1646,7 @@ dependencies = [
name = "vnt-jni"
version = "1.2.9"
dependencies = [
"android_logger",
"common",
"jni",
"log",
+9 -9
View File
@@ -7,33 +7,33 @@ pub fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, String>
let net = if let Some(net) = split.next() {
net
} else {
return Err("ipv4/mask,ipv4".to_string());
return Err(format!("ipv4/mask,ipv4 {:?}", x));
};
let ip = if let Some(ip) = split.next() {
ip
} else {
return Err("ipv4/mask,ipv4".to_string());
return Err(format!("ipv4/mask,ipv4 {:?}", x));
};
let ip = if let Ok(ip) = ip.parse::<Ipv4Addr>() {
ip
} else {
return Err("not ipv4".to_string());
return Err(format!("not ipv4 {:?}", ip));
};
let mut split = net.split("/");
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err("no ipv4/mask".to_string());
return Err(format!("no ipv4/mask {:?}", net));
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err("no netmask".to_string());
return Err(format!("no netmask {:?}", net));
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err("not ipv4".to_string());
return Err(format!("not ipv4 {:?}", dest));
};
let mask = to_ip(mask)?;
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
@@ -48,17 +48,17 @@ pub fn out_ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32)>, String> {
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err("no ipv4/mask".to_string());
return Err(format!("no ipv4/mask {:?}", x));
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err("no netmask".to_string());
return Err(format!("no netmask {:?}", x));
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err("not ipv4".to_string());
return Err(format!("not ipv4 {:?}", dest));
};
let mask = to_ip(mask)?;
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask));
+5 -2
View File
@@ -55,7 +55,10 @@ pub fn get_unique_identifier() -> Option<String> {
// 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的
// 唯一标识,而且某些环境没有预装`dmidecode`命令
if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") {
return Some(identifier);
let identifier = identifier.trim();
if !identifier.is_empty() {
return Some(identifier.to_string());
}
}
let output = match Command::new("dmidecode")
@@ -70,7 +73,7 @@ pub fn get_unique_identifier() -> Option<String> {
};
let result = String::from_utf8_lossy(&output.stdout);
let identifier = result.trim().to_string();
let identifier = result.trim();
if identifier.is_empty() {
None
} else {
+9 -8
View File
@@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
vnt = { path = "../vnt", package = "vnt",default-features = false }
vnt = { path = "../vnt", package = "vnt", default-features = false }
common = { path = "../common" }
getopts = "0.2.21"
console = "0.15.2"
@@ -28,16 +28,17 @@ sudo = "0.6.0"
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
[features]
default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc","ip_proxy"]
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping"]
openssl = ["vnt/openssl"]
openssl-vendored = ["vnt/openssl-vendored"]
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"]
ip_proxy=["vnt/ip_proxy"]
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"]
ip_proxy = ["vnt/ip_proxy"]
port_mapping = ["vnt/port_mapping"]
[build-dependencies]
embed-manifest = "1.4.0"
rand = "0.8.5"
+24 -7
View File
@@ -10,11 +10,13 @@
### -c
关闭控制台交互式命令,后台运行时可以加此参数
### -s `<server>`
注册和中继服务器地址,注册和转发数据
注册和中继服务器地址,注册和转发数据,以'TXT:'开头表示解析TXT记录,TXT记录内容必须是'host:port'形式的服务器地址
### -e `<stun-server>`
使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略
### -a
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
注意:仅在windows上支持使用tap,用于兼容低版本windows系统(低版本windows不支持wintun
### --nic `<tun0>`
指定虚拟网卡名称,默认tun模式使用vnt-tuntap模式使用vnt-tap
### -i `<in-ip>`、-o `<out-ip>`
@@ -72,9 +74,9 @@
注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数
### --punch `<punch>`
取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两都会使用
取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两都会使用
### --ports `<port1,port2>`
指定本地监听的端口组,多个端口使用逗号分隔,多个端口可以分摊流量,增加并发,tcp会监听端口组的第一个端口,用于tcp直连
指定本地监听的端口组,多个端口使用逗号分隔,多个端口可以分摊流量,增加并发、减缓流量限制,tcp会监听端口组的第一个端口,用于tcp直连
- 例1:‘--ports 12345,12346,12347 表示udp监听12345、12346、12347这三个端口,tcp监听12345端口
- 例2:‘--ports 0,0’ 表示udp监听两个未使用的端口,tcp监听一个未使用的端口
@@ -85,12 +87,20 @@
### --no-proxy
关闭内置的ip代理,内置的代理较为简单,而且一般来说直接使用网卡NAT转发性能会更高,
有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/lbl8603/vnt#%E7%BC%96%E8%AF%91)
### --dns `<223.5.5.5>`
设置域名解析服务器地址,可以设置多个。如果使用TXT记录的域名,则dns默认使用223.5.5.5和114.114.114.114,端口省略值为53
当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果
### --mapping `<udp:0.0.0.0:80->10.26.0.10:80>`
端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.11:81'
表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口
### -f `<conf>`
指定配置文件
配置文件采用yaml格式,可参考:
```yaml
# 全部参数
tap: false #是否使用tap
tap: false #是否使用tap 仅在windows上支持使用tap
token: xxx #组网token
device_id: xxx #当前设备id
name: windows 11 #当前设备名称
@@ -111,7 +121,7 @@ server_encrypt: true #服务端加密
parallel: 1 #任务并行度
cipher_model: aes_gcm #客户端加密算法
finger: false #关闭数据指纹
punch_model: ipv4 #打洞模式
punch_model: ipv4 #打洞模式,表示只使用ipv4地址打洞,默认会同时使用v6和v4
ports:
- 0 #使用随机端口,tcp监听此端口
- 0
@@ -122,7 +132,12 @@ device_name: vnt-tun #网卡名称
packet_loss: 0 #指定丢包率 取值0~1之间的数 用于模拟弱网
packet_delay: 0 #指定延迟 单位毫秒 用于模拟弱网
dns:
- 8.8.8.8:53
- 223.5.5.5 # 首选dns
- 8.8.8.8 # 备选dns
mapping:
- udp:0.0.0.0:80->10.26.0.10:80 # 映射udp数据
- tcp:0.0.0.0:80->10.26.0.10:81 # 映射tcp数据
- tcp:0.0.0.0:82->localhost:83 # 映射tcp数据
```
或者需要哪个配置就加哪个,当然token是必须的
@@ -134,7 +149,9 @@ token: xxx #组网token
- relay:仅中继模式,会禁止打洞/p2p直连,只使用服务器转发
- p2p:仅直连模式,会禁止网络数据从服务器/客户端转发,只会使用服务器转发控制包
### --packet-loss `<0>`
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境会有帮助。
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境会有帮助。
### --packet-delay `<0>`
模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网
### --list
在后台运行时,查看其他设备列表
+4
View File
@@ -1,4 +1,5 @@
use serde::{Deserialize, Serialize};
use std::net::{Ipv4Addr, SocketAddr};
#[derive(Serialize, Deserialize, Debug)]
pub struct Info {
pub name: String,
@@ -13,6 +14,9 @@ pub struct Info {
pub ipv6_addr: String,
pub up: u64,
pub down: u64,
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
pub out_ips: Vec<(u32, u32)>,
}
#[derive(Serialize, Deserialize, Debug)]
+6
View File
@@ -185,6 +185,9 @@ pub fn command_info(vnt: &Vnt) -> Info {
.unwrap_or("None".to_string());
let up = vnt.up_stream();
let down = vnt.down_stream();
let port_mapping_list = vnt.config().port_mapping_list.clone();
let in_ips = vnt.config().in_ips.clone();
let out_ips = vnt.config().out_ips.clone();
Info {
name,
virtual_ip,
@@ -198,5 +201,8 @@ pub fn command_info(vnt: &Vnt) -> Info {
ipv6_addr,
up,
down,
port_mapping_list,
in_ips,
out_ips,
}
}
+10 -4
View File
@@ -12,7 +12,7 @@ use vnt::core::Config;
#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct FileConfig {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
pub tap: bool,
pub token: String,
pub device_id: String,
@@ -40,12 +40,14 @@ pub struct FileConfig {
pub device_name: Option<String>,
pub packet_loss: Option<f64>,
pub packet_delay: u32,
#[cfg(feature = "port_mapping")]
pub mapping: Vec<String>,
}
impl Default for FileConfig {
fn default() -> Self {
Self {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
tap: false,
token: "".to_string(),
device_id: get_device_id(),
@@ -54,7 +56,7 @@ impl Default for FileConfig {
stun_server: vec![
"stun1.l.google.com:19302".to_string(),
"stun2.l.google.com:19302".to_string(),
"stun.qq.com:3478".to_string(),
"stun.miwifi.com:3478".to_string(),
],
dns: vec![],
in_ips: vec![],
@@ -77,6 +79,8 @@ impl Default for FileConfig {
device_name: None,
packet_loss: None,
packet_delay: 0,
#[cfg(feature = "port_mapping")]
mapping: vec![],
}
}
}
@@ -130,7 +134,7 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
let use_channel_type = UseChannelType::from_str(&file_conf.use_channel)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let config = Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
file_conf.tap,
file_conf.token,
file_conf.device_id,
@@ -157,6 +161,8 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
use_channel_type,
file_conf.packet_loss,
file_conf.packet_delay,
#[cfg(feature = "port_mapping")]
file_conf.mapping,
)
.unwrap();
Ok((config, file_conf.cmd))
+42 -4
View File
@@ -1,4 +1,5 @@
use console::{style, Style};
use std::net::Ipv4Addr;
use crate::command::entity::{DeviceItem, Info, RouteItem};
@@ -9,10 +10,15 @@ pub fn console_info(status: Info) {
println!("Virtual ip: {}", style(status.virtual_ip).green());
println!("Virtual gateway: {}", style(status.virtual_gateway).green());
println!("Virtual netmask: {}", style(status.virtual_netmask).green());
println!(
"Connection status: {}",
style(status.connect_status).green()
);
if status.connect_status.eq_ignore_ascii_case("Connected") {
println!(
"Connection status: {}",
style(status.connect_status).green()
);
} else {
println!("Connection status: {}", style(status.connect_status).red());
}
println!("NAT type: {}", style(status.nat_type).green());
println!("Relay server: {}", style(status.relay_server).green());
println!("Public ips: {}", style(status.public_ips).green());
@@ -20,6 +26,38 @@ pub fn console_info(status: Info) {
println!("IPv6: {}", style(status.ipv6_addr).green());
println!("Up: {}", style(convert(status.up)).green());
println!("Down: {}", style(convert(status.down)).green());
if !status.port_mapping_list.is_empty() {
println!("------------------------------------------");
println!("Port mapping {}", status.port_mapping_list.len());
for (is_tcp, addr, dest) in status.port_mapping_list {
if is_tcp {
println!(" TCP: {} -> {}", addr, dest)
} else {
println!(" UDP: {} -> {}", addr, dest)
}
}
}
if !status.in_ips.is_empty() || !status.out_ips.is_empty() {
println!("------------------------------------------");
}
if !status.in_ips.is_empty() {
println!("IP forwarding {}", status.in_ips.len());
for (dest, mask, ip) in status.in_ips {
println!(
" -- {} --> {}/{}",
ip,
Ipv4Addr::from(dest),
mask.count_ones()
)
}
}
if !status.out_ips.is_empty() {
println!("Allows network {}", status.out_ips.len());
for (dest, mask) in status.out_ips {
println!(" {}/{}", Ipv4Addr::from(dest), mask.count_ones())
}
}
}
fn convert(num: u64) -> String {
+20 -4
View File
@@ -73,6 +73,7 @@ fn main() {
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
opts.optmulti("", "dns", "dns", "<dns>");
opts.optmulti("", "mapping", "mapping", "<mapping>");
opts.optopt("f", "", "配置文件", "<conf>");
//"后台运行时,查看其他设备列表"
opts.optflag("", "list", "后台运行时,查看其他设备列表");
@@ -130,7 +131,7 @@ fn main() {
println!("parameter -k not found .");
return;
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
let tap = matches.opt_present("a");
let device_name = matches.opt_str("nic");
let token: String = matches.opt_get("k").unwrap().unwrap();
@@ -156,7 +157,7 @@ fn main() {
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());
stun_server.push("stun.miwifi.com:3478".to_string());
}
let dns = matches.opt_strs("dns");
let in_ip = matches.opt_strs("i");
@@ -287,8 +288,10 @@ fn main() {
.opt_get::<u32>("packet-delay")
.expect("--packet-delay")
.unwrap_or(0);
#[cfg(feature = "port_mapping")]
let port_mapping_list = matches.opt_strs("mapping");
let config = match Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
tap,
token,
device_id,
@@ -315,6 +318,8 @@ fn main() {
use_channel_type,
packet_loss,
packet_delay,
#[cfg(feature = "port_mapping")]
port_mapping_list,
) {
Ok(config) => config,
Err(e) => {
@@ -338,6 +343,14 @@ fn main() {
mod callback;
fn main0(config: Config, show_cmd: bool) {
#[cfg(feature = "port_mapping")]
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
if *is_tcp {
println!("TCP port mapping {}->{}", addr, dest)
} else {
println!("UDP port mapping {}->{}", addr, dest)
}
}
let vnt_util = Vnt::new(config, callback::VntHandler {}).unwrap();
let vnt_c = vnt_util.clone();
thread::Builder::new()
@@ -412,7 +425,8 @@ fn print_usage(program: &str, _opts: Options) {
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2");
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com");
#[cfg(target_os = "windows")]
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!(" 并转发到10.26.0.3,可指定多个网段");
@@ -475,6 +489,8 @@ fn print_usage(program: &str, _opts: Options) {
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
);
println!(" --dns <host:port> DNS服务器地址,可使用多个dns,不指定时使用系统解析");
#[cfg(feature = "port_mapping")]
println!(" --mapping <mapping> 端口映射,例如 --mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.10:80");
println!();
println!(
+3
View File
@@ -14,5 +14,8 @@ jni = { version = "0.21.1", default-features = false }
log = "0.4.20"
spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64","pem"]}
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.13"
[lib]
crate-type = ["staticlib", "cdylib"]
+46 -13
View File
@@ -1,13 +1,16 @@
package top.wherewego.vnt.jni;
import java.io.Serializable;
import java.util.Arrays;
/**
* 启动配置
*
* @author https://github.com/lbl8603/vnt
*/
public class Config {
public class Config implements Serializable {
/**
* 是否是tap模式,仅支持windows和linux
* 是否是tap模式,仅支持windows
*/
private boolean tap;
/**
@@ -38,10 +41,6 @@ public class Config {
* 是否开启服务端加密
*/
private boolean serverEncrypt;
/**
* 仅使用中继转发
*/
private boolean relay;
/**
* 设备id,请使用唯一值
*/
@@ -54,6 +53,10 @@ public class Config {
* dns地址
*/
private String[] dns;
/**
* 端口映射
*/
private String[] portMapping;
/**
* stun服务地址
*/
@@ -170,13 +173,6 @@ public class Config {
this.serverEncrypt = serverEncrypt;
}
public boolean isRelay() {
return relay;
}
public void setRelay(boolean relay) {
this.relay = relay;
}
public String getDeviceId() {
return deviceId;
@@ -201,6 +197,13 @@ public class Config {
public void setDns(String[] dns) {
this.dns = dns;
}
public String[] getPortMapping() {
return portMapping;
}
public void setPortMapping(String[] portMapping) {
this.portMapping = portMapping;
}
public String[] getStunServer() {
return stunServer;
@@ -297,4 +300,34 @@ public class Config {
public void setPacketDelay(Integer packetDelay) {
this.packetDelay = packetDelay;
}
@Override
public String toString() {
return "Config{" +
"tap=" + tap +
", token='" + token + '\'' +
", name='" + name + '\'' +
", password='" + password + '\'' +
", cipherModel='" + cipherModel + '\'' +
", punchModel='" + punchModel + '\'' +
", mtu=" + mtu +
", serverEncrypt=" + serverEncrypt +
", deviceId='" + deviceId + '\'' +
", server='" + server + '\'' +
", dns=" + Arrays.toString(dns) +
", portMapping=" + Arrays.toString(portMapping) +
", stunServer=" + Arrays.toString(stunServer) +
", tcp=" + tcp +
", ip='" + ip + '\'' +
", finger=" + finger +
", firstLatency=" + firstLatency +
", inIps=" + Arrays.toString(inIps) +
", outIps=" + Arrays.toString(outIps) +
", ports=" + Arrays.toString(ports) +
", deviceName='" + deviceName + '\'' +
", useChannel='" + useChannel + '\'' +
", packetLossRate=" + packetLossRate +
", packetDelay=" + packetDelay +
'}';
}
}
+7 -1
View File
@@ -11,7 +11,7 @@ import java.io.IOException;
public class Vnt implements Closeable {
private final long raw;
public Vnt(Config config, CallBack callBack) throws Exception{
public Vnt(Config config, CallBack callBack) throws Exception {
this.raw = new0(config, callBack);
if (this.raw == 0) {
throw new RuntimeException();
@@ -26,6 +26,10 @@ public class Vnt implements Closeable {
wait0(raw);
}
public boolean awaitTimeout(long ms) {
return waitTimeout0(raw, ms);
}
public PeerRouteInfo[] list() {
return list0(raw);
}
@@ -36,6 +40,8 @@ public class Vnt implements Closeable {
private native void wait0(long raw);
private native boolean waitTimeout0(long raw, long ms);
private native void drop0(long raw);
private native PeerRouteInfo[] list0(long raw);
+5 -3
View File
@@ -12,7 +12,7 @@ use vnt::core::Config;
use crate::utils::*;
pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
let tap = env.get_field(&config, "tap", "Z")?.z()?;
let token = to_string_not_null(env, &config, "token")?;
let name = to_string_not_null(env, &config, "name")?;
@@ -21,6 +21,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
let server_address_str = to_string_not_null(env, &config, "server")?;
let stun_server = to_string_array_not_null(env, &config, "stunServer")?;
let dns = to_string_array(env, &config, "dns")?.unwrap_or_else(|| vec![]);
let port_mapping = to_string_array(env, &config, "portMapping")?.unwrap_or_else(|| vec![]);
let cipher_model = to_string_not_null(env, &config, "cipherModel")?;
let punch_model = to_string(env, &config, "punchModel")?;
let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32);
@@ -89,7 +90,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
#[cfg(not(target_os = "android"))]
let device_name = to_string(env, &config, "deviceName")?;
let config = match Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
tap,
token,
device_id,
@@ -116,12 +117,13 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(),
packet_loss_rate,
packet_delay,
port_mapping,
) {
Ok(config) => config,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
format!("vnt start error {:?}", e),
)
.expect("throw");
return Err(Error::JavaException);
+1
View File
@@ -2,3 +2,4 @@ pub mod callback;
pub mod config;
pub mod utils;
pub mod vnt;
pub(crate) mod vnt_logger;
+13 -2
View File
@@ -1,8 +1,9 @@
use std::ptr;
use std::time::Duration;
use jni::errors::Error;
use jni::objects::{JClass, JObject, JValue};
use jni::sys::{jint, jlong, jobject, jobjectArray, jsize};
use jni::sys::{jboolean, jint, jlong, jobject, jobjectArray, jsize};
use jni::JNIEnv;
use vnt::channel::Route;
@@ -10,7 +11,6 @@ use vnt::core::Vnt;
use vnt::handle::PeerDeviceInfo;
use crate::callback::CallBack;
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0(
mut env: JNIEnv<'static>,
@@ -18,6 +18,7 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0(
config: JObject,
call_back: JObject<'static>,
) -> jlong {
crate::vnt_logger::init_log();
let jvm = if let Ok(jvm) = env.get_java_vm() {
jvm
} else {
@@ -74,6 +75,16 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0(
let vnt = raw_vnt as *mut Vnt;
let _ = (&*vnt).wait();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitTimeout0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
time: jlong,
) -> jboolean {
let vnt = raw_vnt as *mut Vnt;
(&*vnt).wait_timeout(Duration::from_millis(time as _)) as _
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0(
+12
View File
@@ -0,0 +1,12 @@
#[cfg(target_os = "android")]
pub fn init_log() {
use android_logger::Config;
use log::LevelFilter;
android_logger::init_once(
Config::default()
.with_max_level(LevelFilter::Info) // limit log level
.with_tag("vnt_jni"), // logs will show under mytag tag
);
}
#[cfg(not(target_os = "android"))]
pub fn init_log() {}
+20 -16
View File
@@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tun= {path = "tun"}
tun = { path = "tun" }
packet = { path = "./packet" }
bytes = "1.5.0"
log = "0.4.17"
@@ -19,22 +19,25 @@ sha2 = { version = "0.10.6", features = ["oid"] }
thiserror = "1.0.37"
protobuf = "3.2.0"
socket2 = { version = "0.5.2", features = ["all"] }
aes-gcm = { version = "0.10.2",optional = true }
aes-gcm = { version = "0.10.2", optional = true }
ring = { version = "0.17.0", optional = true }
cbc = {version = "0.1.2",optional = true}
ecb = {version = "0.1.2",optional = true}
cbc = { version = "0.1.2", optional = true }
ecb = { version = "0.1.2", optional = true }
aes = "0.8.3"
stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] }
rsa = { version = "0.9.2", features = [] ,optional = true}
spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64"] ,optional = true}
openssl-sys = { git = "https://github.com/lbl8603/rust-openssl" ,optional = true}
libsm = {git="https://github.com/lbl8603/libsm" ,optional = true}
rsa = { version = "0.9.2", features = [], optional = true }
spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optional = true }
openssl-sys = { git = "https://github.com/lbl8603/rust-openssl", optional = true }
libsm = { git = "https://github.com/lbl8603/libsm", optional = true }
mio = {version = "0.8.10",features = ["os-poll","net"]}
mio = { version = "0.8.10", features = ["os-poll", "net"] }
crossbeam-queue = "0.3.11"
anyhow = "1.0.82"
dns-parser = "0.8.0"
tokio = { version = "1.37.0", features = ["full"], optional = true }
[target.'cfg(target_os = "windows")'.dependencies]
libloading = "0.8.0"
@@ -44,14 +47,15 @@ protobuf-codegen = "3.2.0"
protoc-bin-vendored = "3.0.0"
[features]
default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc","ip_proxy"]
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping"]
openssl = ["openssl-sys"]
# 从源码编译
openssl-vendored = ["openssl-sys/vendored"]
ring-cipher = ["ring"]
aes_cbc=["cbc"]
aes_ecb=["ecb"]
sm4_cbc=["libsm"]
aes_gcm=["aes-gcm"]
server_encrypt =["aes-gcm","rsa","spki"]
ip_proxy=[]
aes_cbc = ["cbc"]
aes_ecb = ["ecb"]
sm4_cbc = ["libsm"]
aes_gcm = ["aes-gcm"]
server_encrypt = ["aes-gcm", "rsa", "spki"]
ip_proxy = ["tokio"]
port_mapping = ["tokio"]
+3
View File
@@ -81,6 +81,9 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> IpV4Packet<B> {
pub fn set_flags(&mut self, flags: u8) {
self.buffer.as_mut()[6] = (self.buffer.as_ref()[6] & 0b11100000) | (flags << 5)
}
pub fn set_ttl(&mut self, ttl: u8) {
self.buffer.as_mut()[8] = ttl
}
fn set_checksum(&mut self, value: u16) {
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
}
+23 -24
View File
@@ -1,4 +1,4 @@
use std::io;
use anyhow::Context;
use std::net::{SocketAddr, UdpSocket};
use std::str::FromStr;
@@ -7,7 +7,7 @@ use crate::channel::handler::RecvChannelHandler;
use crate::channel::sender::AcceptSocketSender;
use crate::channel::tcp_channel::tcp_listen;
use crate::channel::udp_channel::udp_listen;
use crate::util::{io_convert, StopManager};
use crate::util::StopManager;
pub mod context;
pub mod handler;
@@ -145,7 +145,7 @@ pub fn init_context(
is_tcp: bool,
packet_loss_rate: Option<f64>,
packet_delay: u32,
) -> io::Result<(ChannelContext, mio::net::TcpListener)> {
) -> anyhow::Result<(ChannelContext, mio::net::TcpListener)> {
assert!(!ports.is_empty(), "not channel");
let mut udps = Vec::with_capacity(ports.len());
//检查系统是否支持ipv6
@@ -161,9 +161,9 @@ pub fn init_context(
let (socket, address) = if use_ipv6 {
let address: SocketAddr = format!("[::]:{}", port).parse().unwrap();
let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::DGRAM, None)?;
io_convert(socket.set_only_v6(false), |_| {
format!("set_only_v6 failed: {}", &address)
})?;
socket
.set_only_v6(false)
.with_context(|| format!("set_only_v6 failed: {}", &address))?;
(socket, address)
} else {
let address: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
@@ -172,16 +172,15 @@ pub fn init_context(
address,
)
};
io_convert(socket.set_send_buffer_size(2 * 1024 * 1024), |_| {
format!("set_send_buffer_size failed: {}", &address)
})?;
io_convert(socket.set_recv_buffer_size(2 * 1024 * 1024), |_| {
format!("set_recv_buffer_size failed: {}", &address)
})?;
io_convert(socket.bind(&address.into()), |_| {
format!("bind failed: {}", &address)
})?;
if let Err(e) = socket.set_send_buffer_size(2 * 1024 * 1024) {
log::warn!("set_send_buffer_size {:?}", e);
}
if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) {
log::warn!("set_send_buffer_size {:?}", e);
}
socket
.bind(&address.into())
.with_context(|| format!("bind failed: {}", &address))?;
let main_channel: UdpSocket = socket.into();
udps.push(main_channel);
}
@@ -200,9 +199,9 @@ pub fn init_context(
let (socket, address) = if use_ipv6 {
let address: SocketAddr = format!("[::]:{}", port).parse().unwrap();
let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?;
io_convert(socket.set_only_v6(false), |_| {
format!("set_only_v6 failed: {}", &address)
})?;
socket
.set_only_v6(false)
.with_context(|| format!("set_only_v6 failed: {}", &address))?;
(socket, address)
} else {
let address: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
@@ -219,12 +218,12 @@ pub fn init_context(
} else {
format!("0.0.0.0:{}", port).parse().unwrap()
};
io_convert(socket.bind(&address.into()), |_| {
format!("bind failed: {}", &address)
})?;
socket
.bind(&address.into())
.with_context(|| format!("bind failed: {}", &address))?;
} else {
//手动指定的ip,直接报错
io_convert(Err(e), |_| format!("bind failed: {}", &address))?;
Err(anyhow::anyhow!("{:?},bind failed: {}", e, address))?;
}
}
socket.listen(128)?;
@@ -239,7 +238,7 @@ pub fn init_channel<H>(
context: ChannelContext,
stop_manager: StopManager,
recv_handler: H,
) -> io::Result<(
) -> anyhow::Result<(
AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
AcceptSocketSender<(mio::net::TcpStream, SocketAddr, Option<Vec<u8>>)>,
)>
+1 -1
View File
@@ -103,7 +103,7 @@ impl NatInfo {
if port != 0 {
if let Some(public_port) = self.public_ports.get_mut(index) {
if *public_port != port {
log::info!("端口变化={}:{}", ip, port)
log::info!("端口变化={}:{} index={}", ip, port, index)
}
*public_port = port;
}
+32 -17
View File
@@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::Duration;
@@ -48,7 +47,7 @@ pub struct Vnt {
}
impl Vnt {
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> io::Result<Self> {
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
log::info!("config:{:?}", config);
//服务端非对称加密
#[cfg(feature = "server_encrypt")]
@@ -94,13 +93,27 @@ impl Vnt {
config.server_address_str.clone(),
config.name_servers.clone(),
);
let ports = config.ports.as_ref().map_or(vec![0, 0], |v| {
// 服务停止管理器
let stop_manager = {
let callback = callback.clone();
StopManager::new(move || callback.stop())
};
#[cfg(feature = "port_mapping")]
crate::port_mapping::start_port_mapping(
stop_manager.clone(),
config.port_mapping_list.clone(),
)?;
let mut ports = config.ports.as_ref().map_or(vec![0, 0], |v| {
if v.is_empty() {
vec![0, 0]
} else {
v.clone()
}
});
if config.use_channel_type.is_only_relay() {
//中继模式下只监听一个端口就够了
ports.truncate(1);
}
//通道上下文
let (context, tcp_listener) = init_context(
ports,
@@ -132,11 +145,6 @@ impl Vnt {
callback.create_tun(tun_info);
device
};
// 服务停止管理器
let stop_manager = {
let callback = callback.clone();
StopManager::new(move || callback.stop())
};
// 定时器
let scheduler = Scheduler::new(stop_manager.clone())?;
let external_route = ExternalRoute::new(config.in_ips.clone());
@@ -146,7 +154,6 @@ impl Vnt {
let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy {
Some(crate::ip_proxy::init_proxy(
context.clone(),
scheduler.clone(),
stop_manager.clone(),
current_device.clone(),
client_cipher.clone(),
@@ -324,15 +331,17 @@ pub fn start<Call: VntCallback>(
client_cipher.clone(),
);
}
// 定时地址探测
maintain::addr_request(
&scheduler,
context.clone(),
current_device.clone(),
server_cipher.clone(),
config_info.clone(),
);
if !context.use_channel_type().is_only_relay() {
// 定时地址探测
maintain::addr_request(
&scheduler,
context.clone(),
current_device.clone(),
server_cipher.clone(),
nat_test.clone(),
config_info.clone(),
);
// 定时打洞
maintain::punch(
&scheduler,
@@ -409,4 +418,10 @@ impl Vnt {
pub fn wait(&self) {
self.stop_manager.wait()
}
pub fn wait_timeout(&self, dur: Duration) -> bool {
self.stop_manager.wait_timeout(dur)
}
pub fn config(&self) -> &Config {
&self.config
}
}
+18 -4
View File
@@ -13,7 +13,7 @@ mod conn;
#[derive(Clone, Debug)]
pub struct Config {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
pub tap: bool,
pub token: String,
pub device_id: String,
@@ -43,18 +43,21 @@ pub struct Config {
//控制丢包率
pub packet_loss_rate: Option<f64>,
pub packet_delay: u32,
// 端口映射
#[cfg(feature = "port_mapping")]
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
}
impl Config {
pub fn new(
#[cfg(any(target_os = "windows", target_os = "linux"))] tap: bool,
#[cfg(target_os = "windows")] tap: bool,
token: String,
device_id: String,
name: String,
server_address_str: String,
mut name_servers: Vec<String>,
mut stun_server: Vec<String>,
in_ips: Vec<(u32, u32, Ipv4Addr)>,
mut in_ips: Vec<(u32, u32, Ipv4Addr)>,
out_ips: Vec<(u32, u32)>,
password: Option<String>,
mtu: Option<u32>,
@@ -72,6 +75,8 @@ impl Config {
use_channel_type: UseChannelType,
packet_loss_rate: Option<f64>,
packet_delay: u32,
// 例如 [udp:127.0.0.1:80->10.26.0.10:8080,tcp:127.0.0.1:80->10.26.0.10:8080]
#[cfg(feature = "port_mapping")] port_mapping_list: Vec<String>,
) -> anyhow::Result<Self> {
for x in stun_server.iter_mut() {
if !x.contains(":") {
@@ -96,8 +101,15 @@ impl Config {
}
let server_address =
address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?;
#[cfg(feature = "port_mapping")]
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;
for (dest, mask, _) in &mut in_ips {
*dest = *mask & *dest;
}
in_ips.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1));
Ok(Self {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
tap,
token,
device_id,
@@ -126,6 +138,8 @@ impl Config {
use_channel_type,
packet_loss_rate,
packet_delay,
#[cfg(feature = "port_mapping")]
port_mapping_list,
})
}
}
+53 -13
View File
@@ -4,8 +4,10 @@ use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use crate::channel::context::ChannelContext;
use crate::channel::punch::NatType;
use crate::cipher::Cipher;
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo};
use crate::nat::NatTest;
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::{control_packet, NetPacket, Protocol, MAX_TTL};
use crate::util::Scheduler;
@@ -15,6 +17,7 @@ pub fn addr_request(
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
server_cipher: Cipher,
nat_test: NatTest,
_config: BaseConfigInfo,
) {
pub_address_request(
@@ -22,31 +25,67 @@ pub fn addr_request(
context,
current_device_info.clone(),
server_cipher,
nat_test,
0,
);
}
pub fn pub_address_request(
fn pub_address_request(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
server_cipher: Cipher,
nat_test: NatTest,
count: usize,
) {
addr_request0(&context, &current_device_info, &server_cipher);
// 9秒发送一次
let rs = scheduler.timeout(Duration::from_secs(9), |s| {
pub_address_request(s, context, current_device_info, server_cipher)
let channel_num = context.channel_num();
let index = count % channel_num;
let mut time = if index == channel_num - 1 { 19 } else { 1 };
if let Err(e) = addr_request0(
&context,
&current_device_info,
&server_cipher,
&nat_test,
index,
) {
log::warn!("{:?}", e);
}
let nat_info = nat_test.nat_info();
if nat_info.nat_type == NatType::Symmetric {
//对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改)
if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
time = 600;
}
}
let rs = scheduler.timeout(Duration::from_secs(time), move |s| {
pub_address_request(
s,
context,
current_device_info,
server_cipher,
nat_test,
index + 1,
)
});
if !rs {
log::info!("定时任务停止");
}
}
pub fn addr_request0(
fn addr_request0(
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
server_cipher: &Cipher,
) {
nat_test: &NatTest,
index: usize,
) -> anyhow::Result<()> {
let current_dev = current_device.load();
if current_dev.connect_server.is_ipv4() && current_dev.status.online() {
if current_dev.status.offline() {
return Ok(());
}
if current_dev.connect_server.is_ipv4() && !context.is_main_tcp() {
// 如果连接的是ipv4服务,则探测公网端口
let gateway_ip = current_dev.virtual_gateway;
let src_ip = current_dev.virtual_ip;
@@ -58,10 +97,11 @@ pub fn addr_request0(
packet.first_set_ttl(MAX_TTL);
packet.set_source(src_ip);
packet.set_destination(gateway_ip);
if let Err(e) = server_cipher.encrypt_ipv4(&mut packet) {
log::warn!("AddrRequest err={:?}", e)
} else {
context.try_send_all_main(packet.buffer(), current_dev.connect_server);
}
server_cipher.encrypt_ipv4(&mut packet)?;
context.send_main_udp(index, packet.buffer(), current_dev.connect_server)?;
} else {
let (data, addr) = nat_test.send_data()?;
context.send_main_udp(index, &data, addr)?;
}
Ok(())
}
+1 -1
View File
@@ -6,7 +6,7 @@ mod re_nat_type;
pub use re_nat_type::retrieve_nat_type;
mod addr_request;
pub use addr_request::addr_request;
pub use addr_request::*;
mod punch;
pub use punch::*;
+14 -1
View File
@@ -39,10 +39,22 @@ pub struct RecvDataHandler<Call> {
client: ClientPacketHandler,
server: ServerPacketHandler<Call>,
counter: U64Adder,
nat_test: NatTest,
}
impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
fn handle(&mut self, buf: &mut [u8], route_key: RouteKey, context: &ChannelContext) {
//判断stun响应包
if !route_key.is_tcp() {
if let Ok(rs) = self
.nat_test
.recv_data(route_key.index(), route_key.addr, buf)
{
if rs {
return;
}
}
}
if let Err(e) = self.handle0(buf, route_key, context) {
log::error!("[{}]-{:?}", thread::current().name().unwrap_or(""), e);
}
@@ -86,7 +98,7 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
client_cipher,
punch_sender,
peer_nat_info_map,
nat_test,
nat_test.clone(),
route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
@@ -98,6 +110,7 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
client,
server,
counter,
nat_test,
}
}
fn handle0(
+1 -2
View File
@@ -320,8 +320,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
"device_fd == 0".into(),
));
} else {
let device = Arc::new(tun::Device::new(device_fd as _)?);
if let Err(e) = self.device.start(device) {
if let Err(e) = self.device.start(device_fd as _) {
self.callback.error(ErrorInfo::new_msg(
ErrorType::Unknown,
format!("{:?}", e),
+8 -184
View File
@@ -1,187 +1,11 @@
use std::io;
use std::net::Ipv4Addr;
use parking_lot::Mutex;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::ip::ipv4::protocol::Protocol;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::external_route::ExternalRoute;
use crate::handle::{check_dest, CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::{IpProxyMap, ProxyHandler};
use crate::protocol;
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::ip_turn_packet::BroadcastPacket;
use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL};
mod channel_group;
pub mod tun_handler;
fn broadcast(
server_cipher: &Cipher,
sender: &ChannelContext,
net_packet: &mut NetPacket<&mut [u8]>,
current_device: &CurrentDeviceInfo,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
) -> io::Result<()> {
let list: Vec<Ipv4Addr> = device_list
.lock()
.1
.iter()
.filter(|info| info.status.is_online())
.map(|info| info.virtual_ip)
.collect();
const MAX_COUNT: usize = 8;
let mut p2p_ips = Vec::with_capacity(8);
let mut relay_ips = Vec::with_capacity(8);
let mut overflow = false;
for (index, peer_ip) in list.into_iter().enumerate() {
if index > MAX_COUNT {
overflow = true;
break;
}
if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) {
if sender
.send_by_key(net_packet.buffer(), route.route_key())
.is_ok()
{
p2p_ips.push(peer_ip);
continue;
}
}
relay_ips.push(peer_ip);
}
if !overflow && relay_ips.is_empty() {
//全部p2p,不需要服务器中转
return Ok(());
}
if p2p_ips.is_empty() {
//都没有p2p则直接由服务器转发
if current_device.status.online() {
sender.send_default(net_packet.buffer(), current_device.connect_server)?;
}
return Ok(());
}
if !overflow && relay_ips.len() == 2 {
// 如果转发的ip数不多就直接发
for peer_ip in relay_ips {
//非直连的广播要改变目的地址,不然服务端收到了会再次广播
net_packet.set_destination(peer_ip);
sender.send_ipv4_by_id(
net_packet.buffer(),
&peer_ip,
current_device.connect_server,
current_device.status.online(),
)?;
}
return Ok(());
}
if current_device.status.offline() {
//离线的不再转发
return Ok(());
}
let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED];
//剩余的发送到服务端,需要告知哪些已发送过
let mut server_packet = NetPacket::new_encrypt(buf)?;
server_packet.set_default_version();
server_packet.set_gateway_flag(true);
server_packet.first_set_ttl(MAX_TTL);
server_packet.set_source(net_packet.source());
//使用对应的目的地址
server_packet.set_destination(net_packet.destination());
server_packet.set_protocol(protocol::Protocol::IpTurn);
server_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into());
let mut broadcast = BroadcastPacket::unchecked(server_packet.payload_mut());
broadcast.set_address(&p2p_ips)?;
broadcast.set_data(net_packet.buffer())?;
server_cipher.encrypt_ipv4(&mut server_packet)?;
sender.send_default(server_packet.buffer(), current_device.connect_server)
}
/// 实现一个原地发送,必须保证是如下结构
/// |12字节开头|ip报文|至少1024字节结尾|
///
#[inline]
pub fn base_handle(
context: &ChannelContext,
buf: &mut [u8],
data_len: usize, //数据总长度=12+ip包长度
current_device: CurrentDeviceInfo,
ip_route: &ExternalRoute,
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
client_cipher: &Cipher,
server_cipher: &Cipher,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
) -> io::Result<()> {
let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?;
let protocol = ipv4_packet.protocol();
let src_ip = ipv4_packet.source_ip();
let mut dest_ip = ipv4_packet.destination_ip();
let mut net_packet = NetPacket::new0(data_len, buf)?;
net_packet.set_default_version();
net_packet.set_protocol(protocol::Protocol::IpTurn);
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
net_packet.first_set_ttl(6);
net_packet.set_source(src_ip);
net_packet.set_destination(dest_ip);
if dest_ip == current_device.virtual_gateway {
// 发到网关的加密方式不一样,要单独处理
if protocol == Protocol::Icmp {
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_default(net_packet.buffer(), current_device.connect_server)?;
}
return Ok(());
}
if dest_ip.is_multicast() {
//当作广播处理
dest_ip = Ipv4Addr::BROADCAST;
net_packet.set_destination(Ipv4Addr::BROADCAST);
}
if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip {
// 广播 发送到直连目标
client_cipher.encrypt_ipv4(&mut net_packet)?;
broadcast(
server_cipher,
context,
&mut net_packet,
&current_device,
device_list,
)?;
return Ok(());
}
if !check_dest(
dest_ip,
current_device.virtual_netmask,
current_device.virtual_network,
) {
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
//路由的目标不能是自己
if r_dest_ip == src_ip {
return Ok(());
}
//需要修改目的地址
dest_ip = r_dest_ip;
net_packet.set_destination(r_dest_ip);
} else {
return Ok(());
}
}
#[cfg(feature = "ip_proxy")]
if let Some(proxy_map) = proxy_map {
let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?;
proxy_map.send_handle(&mut ipv4_packet)?;
}
client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_ipv4_by_id(
net_packet.buffer(),
&dest_ip,
current_device.connect_server,
current_device.status.online(),
)
}
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub(crate) use unix::*;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
pub(crate) use windows::*;
+171 -78
View File
@@ -1,3 +1,4 @@
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
@@ -6,22 +7,27 @@ use parking_lot::Mutex;
use packet::icmp::icmp::IcmpPacket;
use packet::icmp::Kind;
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::ip::ipv4::protocol::Protocol;
use tun::device::IFace;
use tun::Device;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::channel_group::{channel_group, GroupSyncSender};
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::handle::tun_tap::channel_group::channel_group;
use crate::handle::{check_dest, CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::ip_proxy::ProxyHandler;
use crate::protocol;
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::ip_turn_packet::BroadcastPacket;
use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL};
use crate::util::{SingleU64Adder, StopManager};
fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> io::Result<()> {
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
if ipv4_packet.protocol() == Protocol::Icmp {
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
if icmp.kind() == Kind::EchoRequest {
icmp.set_kind(Kind::EchoReply);
@@ -37,7 +43,7 @@ fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> io::R
}
/// 接收tun数据,并且转发到udp上
fn handle(
pub(crate) fn handle(
context: &ChannelContext,
data: &mut [u8],
len: usize,
@@ -59,7 +65,7 @@ fn handle(
if src_ip == dest_ip {
return icmp(&device_writer, ipv4_packet);
}
return crate::handle::tun_tap::base_handle(
return base_handle(
context,
data,
len,
@@ -86,23 +92,6 @@ pub fn start(
mut up_counter: SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
) -> io::Result<()> {
let worker = {
#[cfg(any(target_os = "macos", target_os = "android"))]
let current_device = current_device.clone();
let device = device.clone();
stop_manager.add_listener("tun_device".into(), move || {
if let Err(e) = device.shutdown() {
log::warn!("{:?}", e);
}
#[cfg(any(target_os = "macos", target_os = "android"))]
{
let ip = current_device.load().virtual_ip;
if let Ok(udp) = std::net::UdpSocket::bind("0.0.0.0:0") {
let _ = udp.send_to(b"stop", format!("{:?}:1234", ip));
}
}
})?
};
if parallel > 1 {
let (sender, receivers) = channel_group::<(Vec<u8>, usize)>(parallel, 16);
for (index, receiver) in receivers.into_iter().enumerate() {
@@ -147,16 +136,20 @@ pub fn start(
thread::Builder::new()
.name("tunHandlerM".into())
.spawn(move || {
if let Err(e) = start_multi(stop_manager, device, sender, &mut up_counter) {
if let Err(e) = crate::handle::tun_tap::start_multi(
stop_manager,
device,
sender,
&mut up_counter,
) {
log::warn!("stop:{}", e);
}
worker.stop_all();
})?;
} else {
thread::Builder::new()
.name("tunHandlerS".into())
.spawn(move || {
if let Err(e) = start_simple(
if let Err(e) = crate::handle::tun_tap::start_simple(
stop_manager,
&context,
device,
@@ -171,73 +164,173 @@ pub fn start(
) {
log::warn!("stop:{}", e);
}
worker.stop_all();
})?;
}
Ok(())
}
fn start_simple(
stop_manager: StopManager,
context: &ChannelContext,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
up_counter: &mut SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
fn broadcast(
server_cipher: &Cipher,
sender: &ChannelContext,
net_packet: &mut NetPacket<&mut [u8]>,
current_device: &CurrentDeviceInfo,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
) -> io::Result<()> {
let mut buf = [0; 1024 * 16];
loop {
if stop_manager.is_stop() {
return Ok(());
let list: Vec<Ipv4Addr> = device_list
.lock()
.1
.iter()
.filter(|info| info.status.is_online())
.map(|info| info.virtual_ip)
.collect();
const MAX_COUNT: usize = 8;
let mut p2p_ips = Vec::with_capacity(8);
let mut relay_ips = Vec::with_capacity(8);
let mut overflow = false;
for (index, peer_ip) in list.into_iter().enumerate() {
if index > MAX_COUNT {
overflow = true;
break;
}
let len = device.read(&mut buf[12..])? + 12;
//单线程的
up_counter.add(len as u64);
#[cfg(any(target_os = "macos"))]
let mut buf = &mut buf[4..];
// buf是重复利用的,需要重置头部
buf[..12].fill(0);
match handle(
context,
&mut buf,
len,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
&device_list,
) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) {
if sender
.send_by_key(net_packet.buffer(), route.route_key())
.is_ok()
{
p2p_ips.push(peer_ip);
continue;
}
}
relay_ips.push(peer_ip);
}
if !overflow && relay_ips.is_empty() {
//全部p2p,不需要服务器中转
return Ok(());
}
if p2p_ips.is_empty() {
//都没有p2p则直接由服务器转发
if current_device.status.online() {
sender.send_default(net_packet.buffer(), current_device.connect_server)?;
}
return Ok(());
}
if !overflow && relay_ips.len() == 2 {
// 如果转发的ip数不多就直接发
for peer_ip in relay_ips {
//非直连的广播要改变目的地址,不然服务端收到了会再次广播
net_packet.set_destination(peer_ip);
sender.send_ipv4_by_id(
net_packet.buffer(),
&peer_ip,
current_device.connect_server,
current_device.status.online(),
)?;
}
return Ok(());
}
if current_device.status.offline() {
//离线的不再转发
return Ok(());
}
let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED];
//剩余的发送到服务端,需要告知哪些已发送过
let mut server_packet = NetPacket::new_encrypt(buf)?;
server_packet.set_default_version();
server_packet.set_gateway_flag(true);
server_packet.first_set_ttl(MAX_TTL);
server_packet.set_source(net_packet.source());
//使用对应的目的地址
server_packet.set_destination(net_packet.destination());
server_packet.set_protocol(protocol::Protocol::IpTurn);
server_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into());
let mut broadcast = BroadcastPacket::unchecked(server_packet.payload_mut());
broadcast.set_address(&p2p_ips)?;
broadcast.set_data(net_packet.buffer())?;
server_cipher.encrypt_ipv4(&mut server_packet)?;
sender.send_default(server_packet.buffer(), current_device.connect_server)
}
fn start_multi(
stop_manager: StopManager,
device: Arc<Device>,
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
up_counter: &mut SingleU64Adder,
/// 实现一个原地发送,必须保证是如下结构
/// |12字节开头|ip报文|至少1024字节结尾|
///
#[inline]
fn base_handle(
context: &ChannelContext,
buf: &mut [u8],
data_len: usize, //数据总长度=12+ip包长度
current_device: CurrentDeviceInfo,
ip_route: &ExternalRoute,
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
client_cipher: &Cipher,
server_cipher: &Cipher,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
) -> io::Result<()> {
loop {
if stop_manager.is_stop() {
return Ok(());
let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?;
let protocol = ipv4_packet.protocol();
let src_ip = ipv4_packet.source_ip();
let mut dest_ip = ipv4_packet.destination_ip();
let mut net_packet = NetPacket::new0(data_len, buf)?;
net_packet.set_default_version();
net_packet.set_protocol(protocol::Protocol::IpTurn);
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
net_packet.first_set_ttl(6);
net_packet.set_source(src_ip);
net_packet.set_destination(dest_ip);
if dest_ip == current_device.virtual_gateway {
// 发到网关的加密方式不一样,要单独处理
if protocol == Protocol::Icmp {
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_default(net_packet.buffer(), current_device.connect_server)?;
}
let mut buf = vec![0; 1024 * 16];
let len = device.read(&mut buf[12..])? + 12;
//单线程的
up_counter.add(len as u64);
if group_sync_sender.send((buf, len)).is_err() {
return Ok(());
}
if dest_ip.is_multicast() {
//当作广播处理
dest_ip = Ipv4Addr::BROADCAST;
net_packet.set_destination(Ipv4Addr::BROADCAST);
}
if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip {
// 广播 发送到直连目标
client_cipher.encrypt_ipv4(&mut net_packet)?;
broadcast(
server_cipher,
context,
&mut net_packet,
&current_device,
device_list,
)?;
return Ok(());
}
if !check_dest(
dest_ip,
current_device.virtual_netmask,
current_device.virtual_network,
) {
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
//路由的目标不能是自己
if r_dest_ip == src_ip {
return Ok(());
}
//需要修改目的地址
dest_ip = r_dest_ip;
net_packet.set_destination(r_dest_ip);
} else {
return Ok(());
}
}
#[cfg(feature = "ip_proxy")]
if let Some(proxy_map) = proxy_map {
let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?;
proxy_map.send_handle(&mut ipv4_packet)?;
}
client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_ipv4_by_id(
net_packet.buffer(),
&dest_ip,
current_device.connect_server,
current_device.status.online(),
)
}
+183
View File
@@ -0,0 +1,183 @@
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::channel_group::GroupSyncSender;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::ip_proxy::IpProxyMap;
use crate::util::{SingleU64Adder, StopManager};
use crossbeam_utils::atomic::AtomicCell;
use mio::event::Source;
use mio::unix::SourceFd;
use mio::{Events, Interest, Poll, Token, Waker};
use parking_lot::Mutex;
use std::io;
use std::os::fd::AsRawFd;
use std::sync::Arc;
use tun::Device;
const STOP: Token = Token(0);
const FD: Token = Token(1);
pub(crate) fn start_simple(
stop_manager: StopManager,
context: &ChannelContext,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
up_counter: &mut SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
) -> io::Result<()> {
let poll = Poll::new()?;
let waker = Arc::new(Waker::new(poll.registry(), STOP)?);
let _waker = waker.clone();
let worker = stop_manager.add_listener("tun_device".into(), move || {
let _ = waker.wake();
})?;
if let Err(e) = start_simple0(
poll,
context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
up_counter,
device_list,
) {
log::error!("{:?}", e);
};
worker.stop_all();
drop(_waker);
Ok(())
}
fn start_simple0(
mut poll: Poll,
context: &ChannelContext,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
up_counter: &mut SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
) -> io::Result<()> {
let mut buf = [0; 1024 * 16];
let fd = device.as_tun_fd();
fd.set_nonblock()?;
SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?;
let mut evnets = Events::with_capacity(4);
#[cfg(not(target_os = "macos"))]
let start = 12;
#[cfg(target_os = "macos")]
let start = 12 - 4;
loop {
poll.poll(&mut evnets, None)?;
for event in evnets.iter() {
if event.token() == STOP {
return Ok(());
}
loop {
let len = match fd.read(&mut buf[start..]) {
Ok(len) => len + start,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
Err(e)?
}
};
//单线程的
up_counter.add(len as u64);
// buf是重复利用的,需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(
context,
&mut buf,
len,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
&device_list,
) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
}
}
}
}
}
}
pub(crate) fn start_multi(
stop_manager: StopManager,
device: Arc<Device>,
group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
up_counter: &mut SingleU64Adder,
) -> io::Result<()> {
let poll = Poll::new()?;
let waker = Arc::new(Waker::new(poll.registry(), STOP)?);
let _waker = waker.clone();
let worker = stop_manager.add_listener("tun_device".into(), move || {
let _ = waker.wake();
})?;
if let Err(e) = start_multi0(poll, device, group_sync_sender, up_counter) {
log::error!("{:?}", e);
};
worker.stop_all();
drop(_waker);
Ok(())
}
fn start_multi0(
mut poll: Poll,
device: Arc<Device>,
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
up_counter: &mut SingleU64Adder,
) -> io::Result<()> {
let fd = device.as_tun_fd();
fd.set_nonblock()?;
SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?;
let mut evnets = Events::with_capacity(4);
let mut buf = vec![0; 1024 * 16];
#[cfg(not(target_os = "macos"))]
let start = 12;
#[cfg(target_os = "macos")]
let start = 12 - 4;
loop {
poll.poll(&mut evnets, None)?;
for event in evnets.iter() {
if event.token() == STOP {
return Ok(());
}
loop {
let len = match fd.read(&mut buf[start..]) {
Ok(len) => len + start,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
Err(e)?
}
};
//单线程的
up_counter.add(len as u64);
if group_sync_sender.send((buf, len)).is_err() {
return Ok(());
}
buf = vec![0; 1024 * 16];
}
}
}
}
+124
View File
@@ -0,0 +1,124 @@
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::channel_group::GroupSyncSender;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::ip_proxy::IpProxyMap;
use crate::util::{SingleU64Adder, StopManager};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::io;
use std::sync::Arc;
use tun::device::IFace;
use tun::Device;
pub(crate) fn start_simple(
stop_manager: StopManager,
context: &ChannelContext,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
up_counter: &mut SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
) -> io::Result<()> {
let worker = {
let device = device.clone();
stop_manager.add_listener("tun_device".into(), move || {
if let Err(e) = device.shutdown() {
log::warn!("{:?}", e);
}
})?
};
if let Err(e) = start_simple0(
context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
up_counter,
device_list,
) {
log::error!("{:?}", e);
}
worker.stop_all();
Ok(())
}
fn start_simple0(
context: &ChannelContext,
device: Arc<Device>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
up_counter: &mut SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
) -> io::Result<()> {
let mut buf = [0; 1024 * 16];
loop {
let len = device.read(&mut buf[12..])? + 12;
//单线程的
up_counter.add(len as u64);
// buf是重复利用的,需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(
context,
&mut buf,
len,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
&device_list,
) {
Ok(_) => {}
Err(e) => {
log::warn!("tun/tap {:?}", e)
}
}
}
}
pub(crate) fn start_multi(
stop_manager: StopManager,
device: Arc<Device>,
group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
up_counter: &mut SingleU64Adder,
) -> io::Result<()> {
let worker = {
let device = device.clone();
stop_manager.add_listener("tun_device_multi".into(), move || {
if let Err(e) = device.shutdown() {
log::warn!("{:?}", e);
}
})?
};
if let Err(e) = start_multi0(device, group_sync_sender, up_counter) {
log::error!("{:?}", e);
};
worker.stop_all();
Ok(())
}
fn start_multi0(
device: Arc<Device>,
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
up_counter: &mut SingleU64Adder,
) -> io::Result<()> {
loop {
let mut buf = vec![0; 1024 * 16];
let len = device.read(&mut buf[12..])? + 12;
//单线程的
up_counter.add(len as u64);
if group_sync_sender.send((buf, len)).is_err() {
return Ok(());
}
}
}
+63 -110
View File
@@ -1,12 +1,12 @@
use anyhow::Context;
use std::collections::HashMap;
use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use mio::net::UdpSocket;
use mio::{Events, Interest, Poll, Token, Waker};
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use packet::icmp::icmp;
use packet::icmp::icmp::HeaderOther;
@@ -18,7 +18,6 @@ use crate::handle::CurrentDeviceInfo;
use crate::ip_proxy::ProxyHandler;
use crate::protocol;
use crate::protocol::{NetPacket, MAX_TTL};
use crate::util::StopManager;
#[derive(Clone)]
pub struct IcmpProxy {
icmp_socket: Arc<std::net::UdpSocket>,
@@ -27,48 +26,50 @@ pub struct IcmpProxy {
}
impl IcmpProxy {
pub fn new(
pub async fn new(
context: ChannelContext,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<Self> {
) -> anyhow::Result<Self> {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let icmp_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::RAW,
Some(socket2::Protocol::ICMPV4),
)?;
)
.context("new Socket RAW ICMPV4 failed")?;
#[cfg(target_os = "android")]
let icmp_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::DGRAM,
Some(socket2::Protocol::ICMPV4),
)?;
)
.context("new Socket DGRAM ICMPV4 failed")?;
let addr: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0);
icmp_socket.bind(&socket2::SockAddr::from(addr))?;
icmp_socket
.bind(&socket2::SockAddr::from(addr))
.context("bind Socket ICMPV4 failed")?;
icmp_socket.set_nonblocking(true)?;
let std_socket: std::net::UdpSocket = icmp_socket.into();
let mio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?);
let tokio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?)?;
let nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("icmpProxy".into())
.spawn(move || {
if let Err(e) = icmp_proxy(
mio_icmp_socket,
nat_map,
context,
stop_manager,
current_device,
client_cipher,
) {
log::warn!("icmp_proxy:{:?}", e);
}
})
.expect("icmpProxy");
tokio::spawn(async {
if let Err(e) = icmp_proxy(
tokio_icmp_socket,
nat_map,
context,
current_device,
client_cipher,
)
.await
{
log::warn!("icmp_proxy:{:?}", e);
}
});
}
Ok(Self {
icmp_socket: Arc::new(std_socket),
@@ -77,105 +78,51 @@ impl IcmpProxy {
}
}
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
fn icmp_proxy(
mut icmp_socket: UdpSocket,
async fn icmp_proxy(
icmp_socket: UdpSocket,
// 对端-> 真实来源
nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>>,
context: ChannelContext,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<()> {
let mut poll = Poll::new()?;
poll.registry()
.register(&mut icmp_socket, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let stop = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let _stop = stop.clone();
let _worker = stop_manager.add_listener("icmp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop icmp_proxy:{:?}", e);
}
})?;
let mut buf = [0u8; 65535 - 20 - 8];
loop {
poll.poll(&mut events, None)?;
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => readable_handle(
&icmp_socket,
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let start = 12;
#[cfg(target_os = "android")]
let start = 12 + 20;
loop {
let (len, addr) = icmp_socket.recv_from(&mut buf[start..]).await?;
if let IpAddr::V4(peer_ip) = addr.ip() {
#[cfg(target_os = "android")]
{
let buf = &mut buf[12..];
// ipv4 头部20字节
buf[0] = 0b0100_0110;
//写入总长度
buf[2..4].copy_from_slice(&((20 + len) as u16).to_be_bytes());
let mut ipv4 = IpV4Packet::unchecked(buf);
ipv4.set_flags(2);
ipv4.set_ttl(1);
ipv4.set_protocol(packet::ip::ipv4::protocol::Protocol::Icmp);
ipv4.set_source_ip(peer_ip);
}
recv_handle(
&mut buf,
start + len,
peer_ip,
&nat_map,
&context,
&current_device,
&client_cipher,
),
NOTIFY => {
return Ok(());
}
_ => {}
);
}
}
}
}
fn readable_handle(
icmp_socket: &UdpSocket,
buf: &mut [u8],
nat_map: &Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
client_cipher: &Cipher,
) {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let start = 12;
#[cfg(target_os = "android")]
let start = 12 + 20;
loop {
let (len, addr) = match icmp_socket.recv_from(&mut buf[start..]) {
Ok(rs) => rs,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::warn!("icmp_socket {:?}", e);
return;
}
};
if let IpAddr::V4(peer_ip) = addr.ip() {
#[cfg(target_os = "android")]
{
let buf = &mut buf[12..];
// ipv4 头部20字节
buf[0] = 0b0100_0110;
//写入总长度
buf[2..4].copy_from_slice(&((20 + len) as u16).to_be_bytes());
let mut ipv4 = IpV4Packet::unchecked(buf);
ipv4.set_flags(2);
ipv4.set_ttl(1);
ipv4.set_protocol(packet::ip::ipv4::protocol::Protocol::Icmp);
ipv4.set_source_ip(peer_ip);
}
recv_handle(
buf,
start + len,
peer_ip,
&nat_map,
&context,
&current_device,
&client_cipher,
);
}
}
}
fn recv_handle(
buf: &mut [u8],
data_len: usize,
@@ -219,11 +166,17 @@ fn recv_handle(
}
}
}
_ => {}
h => {
log::warn!("不支持的icmp代理 {:?},{:?}", peer_ip, h)
}
},
Err(_) => {}
Err(e) => {
log::warn!("icmp {:?}", e)
}
},
Err(_) => {}
Err(e) => {
log::warn!("icmp {:?}", e)
}
}
}
+33 -7
View File
@@ -1,6 +1,6 @@
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
@@ -13,7 +13,7 @@ use crate::handle::CurrentDeviceInfo;
use crate::ip_proxy::icmp_proxy::IcmpProxy;
use crate::ip_proxy::tcp_proxy::TcpProxy;
use crate::ip_proxy::udp_proxy::UdpProxy;
use crate::util::{Scheduler, StopManager};
use crate::util::StopManager;
pub mod icmp_proxy;
pub mod tcp_proxy;
@@ -38,14 +38,40 @@ pub struct IpProxyMap {
pub fn init_proxy(
context: ChannelContext,
scheduler: Scheduler,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<IpProxyMap> {
let icmp_proxy = IcmpProxy::new(context, stop_manager.clone(), current_device, client_cipher)?;
let tcp_proxy = TcpProxy::new(stop_manager.clone())?;
let udp_proxy = UdpProxy::new(scheduler, stop_manager)?;
) -> anyhow::Result<IpProxyMap> {
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_name("ipProxy")
.build()?;
let proxy_map = runtime.block_on(init_proxy0(context, current_device, client_cipher))?;
let (sender, receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("ipProxy".into(), move || {
let _ = sender.send(());
})?;
thread::Builder::new()
.name("ipProxy".into())
.spawn(move || {
runtime.block_on(async {
let _ = receiver.await;
});
runtime.shutdown_background();
drop(worker);
})?;
return Ok(proxy_map);
}
async fn init_proxy0(
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> anyhow::Result<IpProxyMap> {
let icmp_proxy = IcmpProxy::new(context, current_device, client_cipher).await?;
let tcp_proxy = TcpProxy::new().await?;
let udp_proxy = UdpProxy::new().await?;
Ok(IpProxyMap {
icmp_proxy,
+60 -368
View File
@@ -1,28 +1,16 @@
use std::io::{Read, Write};
use std::net::{Ipv4Addr, Shutdown, SocketAddrV4};
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use anyhow::Context;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::Arc;
use std::time::Duration;
use std::{collections::HashMap, io, net::SocketAddr, thread};
use std::{collections::HashMap, io, net::SocketAddr};
use bytes::{BufMut, BytesMut};
use mio::net::TcpStream;
use mio::{net::TcpListener, Events, Interest, Poll, Registry, Token, Waker};
use parking_lot::Mutex;
use tokio::net::{TcpListener, TcpSocket, TcpStream};
use packet::ip::ipv4::packet::IpV4Packet;
use packet::tcp::tcp::TcpPacket;
use crate::ip_proxy::ProxyHandler;
use crate::util::StopManager;
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
#[derive(Clone)]
pub struct TcpProxy {
@@ -31,21 +19,16 @@ pub struct TcpProxy {
}
impl TcpProxy {
pub fn new(stop_manager: StopManager) -> io::Result<Self> {
pub async fn new() -> anyhow::Result<Self> {
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0).parse().unwrap())?;
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0))
.await
.context("TcpProxy bind failed")?;
let port = tcp_listener.local_addr()?.port();
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("tcpProxy".into())
.spawn(move || {
if let Err(e) = tcp_proxy(tcp_listener, nat_map, stop_manager) {
log::warn!("tcp_proxy:{:?}", e);
}
})
.expect("tcpProxy");
tokio::spawn(tcp_proxy(tcp_listener, nat_map));
}
Ok(Self { port, nat_map })
}
@@ -93,365 +76,74 @@ impl ProxyHandler for TcpProxy {
}
}
fn tcp_proxy(
mut tcp_listener: TcpListener,
async fn tcp_proxy(
tcp_listener: TcpListener,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
stop_manager: StopManager,
) -> io::Result<()> {
let mut poll = Poll::new()?;
poll.registry()
.register(&mut tcp_listener, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let mut tcp_map: HashMap<usize, ProxyValue> = HashMap::with_capacity(16);
let mut mapping: HashMap<usize, usize> = HashMap::with_capacity(16);
let stop = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let _stop = stop.clone();
let _worker = stop_manager.add_listener("tcp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop tcp_proxy:{:?}", e);
}
})?;
loop {
poll.poll(&mut events, None)?;
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => {
accept_handle(
poll.registry(),
&tcp_listener,
&nat_map,
&mut tcp_map,
&mut mapping,
);
}
NOTIFY => {
return Ok(());
}
Token(index) => {
let (val, src_index) = if let Some(v) = tcp_map.get_mut(&index) {
(v, index)
} else {
if let Some(dest_index) = mapping.get(&index) {
if let Some(v) = tcp_map.get_mut(dest_index) {
(v, *dest_index)
} else {
continue;
}
} else {
continue;
}
};
let (stream1, stream2, buf1, buf2, state1, state2) = val.as_mut(index);
if event.is_readable() {
if let Err(_) = readable_handle(stream1, stream2, buf1, state2) {
*state1 |= READ_CLOSED;
}
}
if event.is_writable() {
let read = buf2.len() >= BUF_LEN;
if let Err(_) = writable_handle(stream1, buf2) {
*state1 |= WRITE_CLOSED;
} else if read {
if readable_handle(stream2, stream1, buf2, state1).is_err() {
*state2 |= READ_CLOSED;
}
}
}
if event.is_read_closed() || event.is_error() {
*state1 |= READ_CLOSED;
}
if event.is_write_closed() || event.is_error() {
*state1 |= WRITE_CLOSED;
}
if is_write_closed(*state1) {
let _ = stream1.shutdown(Shutdown::Write);
let _ = stream2.shutdown(Shutdown::Read);
}
if is_read_closed(*state1) {
let _ = stream1.shutdown(Shutdown::Read);
if buf1.is_empty() {
let _ = stream2.shutdown(Shutdown::Write);
}
}
if (is_both_closed(*state1) && buf1.is_empty())
|| (is_both_closed(*state2) && buf2.is_empty())
|| (is_write_closed(*state1) && is_write_closed(*state2)
|| (is_read_closed(*state1)
&& is_read_closed(*state2)
&& buf1.is_empty()
&& buf2.is_empty()))
{
close(src_index, &mut tcp_map, &mut mapping);
}
}
}
}
}
}
fn accept_handle(
registry: &Registry,
tcp_listener: &TcpListener,
nat_map: &Mutex<HashMap<SocketAddrV4, SocketAddrV4>>,
tcp_map: &mut HashMap<usize, ProxyValue>,
mapping: &mut HashMap<usize, usize>,
) {
loop {
match tcp_listener.accept() {
Ok((mut src_stream, addr)) => {
#[cfg(windows)]
let src_fd = src_stream.as_raw_socket() as usize;
#[cfg(unix)]
let src_fd = src_stream.as_raw_fd() as usize;
if src_fd == SERVER_VAL || src_fd == NOTIFY_VAL {
log::error!("fd错误:{:?}", src_fd);
continue;
}
let addr = match addr {
SocketAddr::V4(addr) => addr,
SocketAddr::V6(_) => {
// 忽略ipv6
continue;
}
};
let _ = src_stream.set_nodelay(false);
if let Some(dest_addr) = nat_map.lock().get(&addr).cloned() {
match tcp_connect(addr.port(), dest_addr.into()) {
Ok(mut dest_stream) => {
#[cfg(windows)]
let dest_fd = dest_stream.as_raw_socket() as usize;
#[cfg(unix)]
let dest_fd = dest_stream.as_raw_fd() as usize;
if dest_fd == SERVER_VAL || dest_fd == NOTIFY_VAL {
log::error!("fd错误:{:?}", dest_fd);
continue;
}
if let Err(e) = registry.register(
&mut src_stream,
Token(src_fd),
Interest::READABLE.add(Interest::WRITABLE),
) {
log::error!("register src_stream:{:?}", e);
continue;
}
if let Err(e) = registry.register(
&mut dest_stream,
Token(dest_fd),
Interest::READABLE.add(Interest::WRITABLE),
) {
log::error!("register dest_stream:{:?}", e);
continue;
}
tcp_map.insert(
src_fd,
ProxyValue::new(src_stream, dest_stream, src_fd, dest_fd),
);
mapping.insert(dest_fd, src_fd);
}
Err(e) => {
log::error!("connect:{:?} {}->{}", e, addr, dest_addr);
}
match tcp_listener.accept().await {
Ok((tcp_stream, sender_addr)) => match sender_addr {
SocketAddr::V4(sender_addr) => {
if let Some(dest_addr) = nat_map.lock().get(&sender_addr).cloned() {
tokio::spawn(async move {
let peer_tcp_stream =
match tcp_connect(sender_addr.port(), dest_addr.into()).await {
Ok(peer_tcp_stream) => peer_tcp_stream,
Err(e) => {
log::warn!(
"tcp代理异常:{:?},来源:{},目标:{}",
e,
sender_addr,
dest_addr
);
return;
}
};
proxy(sender_addr, dest_addr, tcp_stream, peer_tcp_stream).await
});
} else {
log::warn!("tcp代理异常: 来源:{},未找到目标", sender_addr);
}
}
}
SocketAddr::V6(_) => {}
},
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("accept:{:?}", e);
log::warn!("tcp代理监听:{:?}", e);
}
}
}
}
fn tcp_connect(src_port: u16, addr: SocketAddr) -> io::Result<TcpStream> {
let socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::STREAM,
Some(socket2::Protocol::TCP),
)?;
/// 优先使用来源端口建立tcp连接
async fn tcp_connect(src_port: u16, addr: SocketAddr) -> anyhow::Result<TcpStream> {
let socket = TcpSocket::new_v4()?;
if socket
.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
.is_err()
{
socket.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
}
if let Err(e) = socket.set_tcp_keepalive(
&socket2::TcpKeepalive::new()
.with_time(Duration::from_secs(120))
.with_interval(Duration::from_secs(10)),
) {
log::warn!("set_tcp_keepalive err {:?}", e);
socket.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
}
let _ = socket.set_nodelay(false);
socket.connect_timeout(&addr.into(), Duration::from_secs(3))?;
socket.set_nonblocking(true)?;
Ok(TcpStream::from_std(socket.into()))
let tcp_stream = tokio::time::timeout(Duration::from_secs(5), socket.connect(addr))
.await
.with_context(|| format!("TCP connection timeout {}", addr))?
.with_context(|| format!("TCP connection target failed {}", addr))?;
Ok(tcp_stream)
}
#[derive(Debug)]
struct ProxyValue {
src_stream: TcpStream,
dest_stream: TcpStream,
src_fd: usize,
dest_fd: usize,
src_buf: BytesMut,
dest_buf: BytesMut,
src_state: u8,
dest_state: u8,
}
const BUF_LEN: usize = 65536;
impl ProxyValue {
fn new(src_stream: TcpStream, dest_stream: TcpStream, src_fd: usize, dest_fd: usize) -> Self {
Self {
src_stream,
dest_stream,
src_fd,
dest_fd,
src_buf: BytesMut::with_capacity(BUF_LEN),
dest_buf: BytesMut::with_capacity(BUF_LEN),
src_state: NORMAL,
dest_state: NORMAL,
}
}
fn as_mut(
&mut self,
index: usize,
) -> (
&mut TcpStream,
&mut TcpStream,
&mut BytesMut,
&mut BytesMut,
&mut u8,
&mut u8,
) {
if index == self.src_fd {
(
&mut self.src_stream,
&mut self.dest_stream,
&mut self.src_buf,
&mut self.dest_buf,
&mut self.src_state,
&mut self.dest_state,
)
} else {
(
&mut self.dest_stream,
&mut self.src_stream,
&mut self.dest_buf,
&mut self.src_buf,
&mut self.dest_state,
&mut self.src_state,
)
}
}
}
fn readable_handle(
stream1: &mut TcpStream,
stream2: &mut TcpStream,
mid_buf: &mut BytesMut,
state2: &mut u8,
) -> io::Result<()> {
let mut buf = [0; BUF_LEN];
loop {
if mid_buf.len() >= BUF_LEN {
// 达到上限不再继续读取
return Ok(());
}
match stream1.read(&mut buf) {
Ok(len) => {
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
let mut buf = &buf[..len];
if mid_buf.is_empty() {
// 直接写入,避免在buf中过渡
while !buf.is_empty() {
match stream2.write(buf) {
Ok(end) => {
if end == 0 {
*state2 |= WRITE_CLOSED;
return Err(io::Error::from(io::ErrorKind::WriteZero));
}
buf = &buf[end..];
}
Err(e) => {
if e.kind() != io::ErrorKind::WouldBlock {
*state2 |= WRITE_CLOSED;
return Err(e);
}
break;
}
}
}
if buf.is_empty() {
continue;
}
}
mid_buf.reserve(buf.len());
mid_buf.put_slice(buf);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
Ok(())
}
fn writable_handle(stream: &mut TcpStream, mid_buf: &mut BytesMut) -> io::Result<()> {
while !mid_buf.is_empty() {
match stream.write(&mid_buf) {
Ok(len) => {
let _ = mid_buf.split_to(len);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
Ok(())
}
fn close(
index: usize,
tcp_map: &mut HashMap<usize, ProxyValue>,
mapping: &mut HashMap<usize, usize>,
async fn proxy(
sender_addr: SocketAddrV4,
dest_addr: SocketAddrV4,
client: TcpStream,
server: TcpStream,
) {
if let Some(val) = tcp_map.remove(&index) {
let _ = val.src_stream.shutdown(Shutdown::Both);
let _ = val.dest_stream.shutdown(Shutdown::Both);
mapping.remove(&val.src_fd);
mapping.remove(&val.dest_fd);
let (mut client_read, mut client_write) = client.into_split();
let (mut server_read, mut server_write) = server.into_split();
tokio::spawn(async move {
if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await {
log::warn!("client tcp proxy {}->{},{:?}", sender_addr, dest_addr, e);
}
});
if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await {
log::warn!("server tcp proxy {}->{},{:?}", sender_addr, dest_addr, e);
}
}
const NORMAL: u8 = 0b00;
const READ_CLOSED: u8 = 0b01;
const WRITE_CLOSED: u8 = 0b10;
const BOTH_CLOSED: u8 = 0b11;
fn is_read_closed(state: u8) -> bool {
(state & READ_CLOSED == READ_CLOSED) || is_both_closed(state)
}
fn is_write_closed(state: u8) -> bool {
(state & WRITE_CLOSED == WRITE_CLOSED) || is_both_closed(state)
}
fn is_both_closed(state: u8) -> bool {
state & BOTH_CLOSED == BOTH_CLOSED
}
+97 -240
View File
@@ -1,30 +1,17 @@
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use std::net::{Ipv4Addr, SocketAddrV4};
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{collections::HashMap, io, net::SocketAddr, rc::Rc, thread};
use std::{collections::HashMap, io, net::SocketAddr};
use mio::{net::UdpSocket, Events, Interest, Poll, Token};
use mio::{Registry, Waker};
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::udp::udp::UdpPacket;
use crate::ip_proxy::ProxyHandler;
use crate::util::{Scheduler, StopManager};
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
// 开了ip代理后使用mstsc,mstsc会误以为在真实局域网,从而不维护udp心跳,导致断连,所以这里尽量长一点过期时间
const NAT_TIMEOUT: Duration = Duration::from_secs(20 * 60);
const NAT_FAST_TIMEOUT: Duration = Duration::from_secs(5 * 60);
const NAT_MAX: usize = 5_000;
#[derive(Clone)]
pub struct UdpProxy {
@@ -33,21 +20,20 @@ pub struct UdpProxy {
}
impl UdpProxy {
pub fn new(scheduler: Scheduler, stop_manager: StopManager) -> io::Result<Self> {
pub async fn new() -> anyhow::Result<Self> {
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0).parse().unwrap())?;
let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0))
.await
.context("UdpProxy bind failed")?;
let port = udp.local_addr()?.port();
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("udpProxy".into())
.spawn(move || {
if let Err(e) = udp_proxy(udp, nat_map, scheduler, stop_manager) {
log::warn!("udp_proxy:{:?}", e);
}
})
.expect("udpProxy");
tokio::spawn(async {
if let Err(e) = udp_proxy(udp, nat_map).await {
log::warn!("udp_proxy:{:?}", e);
}
});
}
Ok(Self { port, nat_map })
}
@@ -95,230 +81,101 @@ impl ProxyHandler for UdpProxy {
}
}
fn udp_proxy(
mut udp: UdpSocket,
async fn udp_proxy(
udp: UdpSocket,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
scheduler: Scheduler,
stop_manager: StopManager,
) -> io::Result<()> {
let mut poll = Poll::new()?;
let mut buf = [0u8; 65536];
poll.registry()
.register(&mut udp, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let mut buf = [0; 65536];
let mut token_map: HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)> =
HashMap::with_capacity(64);
let mut udp_map: HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)> = HashMap::with_capacity(64);
let mut timeout = false;
let waker = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let stop = waker.clone();
let _worker = stop_manager.add_listener("udp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop udp_proxy:{:?}", e);
}
})?;
let inner_map: Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
Arc::new(Mutex::new(HashMap::with_capacity(64)));
let udp_socket = Arc::new(udp);
loop {
let mut check = false;
if token_map.is_empty() {
poll.poll(&mut events, None)?;
} else {
//所有事件 50分钟超时
if let Err(e) = poll.poll(&mut events, Some(Duration::from_secs(50 * 60))) {
if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock {
log::warn!(
"超时清理所有udp映射 {},token_map={},udp_map={}",
e,
token_map.len(),
udp_map.len()
);
token_map.clear();
udp_map.clear();
continue;
match udp_socket.recv_from(&mut buf).await {
Ok((len, sender_addr)) => match sender_addr {
SocketAddr::V4(sender_addr) => {
if let Err(e) =
udp_proxy0(&buf[..len], sender_addr, &inner_map, &nat_map, &udp_socket)
.await
{
log::warn!("udp proxy {} {:?}", sender_addr, e);
}
}
return Err(e);
SocketAddr::V6(_) => {}
},
Err(e) => {
log::warn!("udp代理异常:{:?}", e);
}
}
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => server_handle(
poll.registry(),
&udp,
&nat_map,
&mut token_map,
&mut udp_map,
&mut buf,
),
NOTIFY => {
check = true;
}
token => {
if let Err(e) = readable_handle(&udp, &mut token_map, &token, &mut buf) {
log::error!("发送目标失败:{:?}", e);
if let Some((_, src_addr, _)) = token_map.remove(&token) {
udp_map.remove(&src_addr);
};
}
}
async fn udp_proxy0(
buf: &[u8],
sender_addr: SocketAddrV4,
inner_map: &Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
map: &Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
udp_socket: &Arc<UdpSocket>,
) -> io::Result<()> {
let option = inner_map.lock().get(&sender_addr).cloned();
if let Some((udp, time)) = option {
time.store(Instant::now());
udp.send(buf).await?;
} else {
let option = map.lock().get(&sender_addr).cloned();
if let Some(dest_addr) = option {
//先使用相同的端口,冲突了再随机端口
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.send(buf).await?;
let peer_udp_socket = Arc::new(peer_udp_socket);
let inner_map = inner_map.clone();
let time = Arc::new(AtomicCell::new(Instant::now()));
inner_map
.lock()
.insert(sender_addr, (peer_udp_socket.clone(), time.clone()));
let udp_socket = udp_socket.clone();
let map = map.clone();
tokio::spawn(async move {
let mut buf = [0u8; 65536];
loop {
match tokio::time::timeout(
Duration::from_secs(600),
peer_udp_socket.recv(&mut buf),
)
.await
{
Ok(rs) => match rs {
Ok(len) => match udp_socket.send_to(&buf[..len], sender_addr).await {
Ok(_) => {}
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e);
break;
}
},
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!("udp proxy timeout {}->{}", sender_addr, dest_addr);
break;
}
}
}
}
}
}
if check {
//超时校验
if token_map.len() > NAT_MAX / 2 {
check_handle(&mut token_map, &mut udp_map, NAT_FAST_TIMEOUT)
} else {
check_handle(&mut token_map, &mut udp_map, NAT_TIMEOUT)
}
timeout = false;
}
if !token_map.is_empty() && !timeout {
//注册超时监听
timeout = true;
let waker = waker.clone();
scheduler.timeout(NAT_FAST_TIMEOUT, move |_| {
let _ = waker.wake();
inner_map.lock().remove(&sender_addr);
map.lock().remove(&sender_addr);
});
}
}
}
fn check_handle(
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
udp_map: &mut HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)>,
timeout: Duration,
) {
let mut remove_list = Vec::new();
for (token, (_, addr, time)) in token_map.iter() {
if time.elapsed() > timeout {
if let Some((_, time)) = udp_map.get(addr) {
if time.elapsed() > timeout {
//映射超时,需要移除
remove_list.push(*token);
}
}
}
}
for token in remove_list {
if let Some((_, src_addr, _)) = token_map.remove(&token) {
udp_map.remove(&src_addr);
log::warn!(
"超时清理udp映射 {},token_map={},udp_map={}",
src_addr,
token_map.len(),
udp_map.len()
);
}
}
}
fn server_handle(
registry: &Registry,
udp: &UdpSocket,
nat_map: &Mutex<HashMap<SocketAddrV4, SocketAddrV4>>,
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
udp_map: &mut HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)>,
buf: &mut [u8],
) {
loop {
let (len, src_addr) = match udp.recv_from(buf) {
Ok((len, src_addr)) => match src_addr {
SocketAddr::V4(addr) => (len, addr),
SocketAddr::V6(_) => {
continue;
}
},
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("接收数据失败:{:?}", e);
break;
}
};
if let Some((dest_udp, time)) = udp_map.get_mut(&src_addr) {
//发送失败就当丢包了
let _ = dest_udp.send(&buf[..len]);
*time = Instant::now();
} else if let Some(dest_addr) = nat_map.lock().get(&src_addr).cloned() {
if token_map.len() >= NAT_MAX {
log::error!(
"UDP NAT_MAX:src_addr={:?},dest_addr={:?}",
src_addr,
dest_addr
);
continue;
}
match udp_connect(src_addr.port(), dest_addr.into()) {
Ok((token_val, mut dest_udp)) => {
let token = Token(token_val);
if let Err(e) = registry.register(&mut dest_udp, token, Interest::READABLE) {
log::error!("register失败:{:?},addr={:?}", e, dest_addr);
continue;
}
let _ = dest_udp.send(&buf[..len]);
let dest_udp = Rc::new(dest_udp);
token_map.insert(token, (dest_udp.clone(), src_addr, Instant::now()));
udp_map.insert(src_addr, (dest_udp, Instant::now()));
}
Err(e) => {
log::error!("绑定目标地址失败:{:?}", e);
continue;
}
};
}
}
}
/// 得到一个 fd不为SERVER_VAL或者NOTYFY_VAL的socket
fn udp_connect(src_port: u16, addr: SocketAddr) -> io::Result<(usize, UdpSocket)> {
loop {
let udp = if let Ok(udp) =
UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
{
udp
} else {
UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?
};
#[cfg(windows)]
let fd = udp.as_raw_socket() as usize;
#[cfg(unix)]
let fd = udp.as_raw_fd() as usize;
if fd == SERVER_VAL || fd == NOTIFY_VAL {
continue;
}
// 只接收目标的数据
udp.connect(addr)?;
return Ok((fd, udp));
}
}
fn readable_handle(
udp: &UdpSocket,
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
token: &Token,
buf: &mut [u8],
) -> io::Result<()> {
if let Some((dest_udp, src_addr, time)) = token_map.get_mut(&token) {
loop {
let len = match dest_udp.recv(buf) {
Ok(rs) => rs,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
};
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
let _ = udp.send_to(&buf[..len], (*src_addr).into());
}
*time = Instant::now();
}
Ok(())
}
+2
View File
@@ -8,6 +8,8 @@ pub mod handle;
#[cfg(feature = "ip_proxy")]
pub mod ip_proxy;
pub mod nat;
#[cfg(feature = "port_mapping")]
pub mod port_mapping;
pub mod proto;
pub mod protocol;
pub mod tun_tap_device;
+68 -3
View File
@@ -1,5 +1,6 @@
use anyhow::Context;
use std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
use std::net::{SocketAddr, UdpSocket};
use std::ops::Sub;
use std::sync::Arc;
@@ -7,6 +8,7 @@ use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use rand::Rng;
use crate::channel::punch::{NatInfo, NatType};
use crate::proto::message::PunchNatType;
@@ -89,8 +91,9 @@ impl NatTest {
udp_ports: Vec<u16>,
tcp_port: u16,
) -> NatTest {
let server = stun_server[0].clone();
stun_server.resize(3, server);
if stun_server.len() > 5 {
stun_server.truncate(5);
}
let ports = vec![0; udp_ports.len()];
let nat_info = NatInfo::new(
Vec::new(),
@@ -201,4 +204,66 @@ impl NatTest {
Ok(guard.clone())
}
pub fn send_data(&self) -> anyhow::Result<(Vec<u8>, SocketAddr)> {
let len = self.stun_server.len();
let stun_server = if len == 1 {
&self.stun_server[0]
} else {
let index = rand::thread_rng().gen_range(0..self.stun_server.len());
&self.stun_server[index]
};
let addr = stun_server
.to_socket_addrs()?
.next()
.with_context(|| format!("stun error {:?}", stun_server))?;
Ok((stun::send_stun_request(), addr))
}
pub fn recv_data(
&self,
index: usize,
source_addr: SocketAddr,
buf: &[u8],
) -> anyhow::Result<bool> {
if let Some(addr) = stun::recv_stun_response(buf) {
if let SocketAddr::V4(addr) = addr {
let mut check_fail = true;
let source_ip = match source_addr.ip() {
IpAddr::V4(ip) => ip,
IpAddr::V6(ip) => {
if let Some(ip) = ip.to_ipv4_mapped() {
ip
} else {
return Ok(false);
}
}
};
'a: for stun_server in &self.stun_server {
for x in stun_server.to_socket_addrs()? {
if source_addr.port() == x.port() {
if let IpAddr::V4(ip) = x.ip() {
if ip == source_ip {
check_fail = false;
break 'a;
}
};
}
}
}
if check_fail {
return Ok(false);
}
let ip = addr.ip();
if !ip.is_multicast()
&& !ip.is_broadcast()
&& !ip.is_unspecified()
&& !ip.is_loopback()
&& !ip.is_private()
{
self.update_addr(index, *addr.ip(), addr.port());
return Ok(true);
}
}
}
return Ok(false);
}
}
+93 -63
View File
@@ -1,11 +1,13 @@
use std::collections::HashSet;
use std::io;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::Duration;
use crate::channel::punch::NatType;
use rand::RngCore;
use std::net::UdpSocket;
use stun_format::Attr;
pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
let mut th = Vec::new();
for _ in 0..2 {
@@ -36,26 +38,19 @@ pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4
}
Ok((nat_type, hash_set.into_iter().collect(), port_range))
}
pub fn stun_test_nat0(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
let udp = UdpSocket::bind("0.0.0.0:0")?;
udp.set_read_timeout(Some(Duration::from_millis(500)))?;
let mut nat_type = NatType::Cone;
let mut port_range = 0;
let mut min_port = u16::MAX;
let mut max_port = 0;
let mut hash_set = HashSet::new();
let mut pub_addrs = HashSet::new();
for x in &stun_servers {
match test_nat(&udp, x) {
Ok((addr, nat_type_t, ip_list_t, port_range_t)) => {
if nat_type_t == NatType::Symmetric {
nat_type = NatType::Symmetric;
}
for x in ip_list_t {
hash_set.insert(x);
}
if port_range < port_range_t {
port_range = port_range_t;
}
pub_addrs.insert(addr);
Ok(addr) => {
pub_addrs.extend(addr);
}
Err(e) => {
log::warn!("stun {} error {:?} ", x, e);
@@ -65,75 +60,71 @@ pub fn stun_test_nat0(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv
if pub_addrs.len() > 1 {
nat_type = NatType::Symmetric;
}
Ok((nat_type, hash_set.into_iter().collect(), port_range))
}
fn test_nat(
udp: &UdpSocket,
stun_server: &String,
) -> io::Result<(SocketAddr, NatType, Vec<Ipv4Addr>, u16)> {
udp.connect(stun_server)?;
let mut port_range = 0;
let mut hash_set = HashSet::new();
let mut nat_type = NatType::Cone;
// 随便搞个当id
let tid = stun_server.as_ptr() as u128;
let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?;
match mapped_addr1.ip() {
IpAddr::V4(ip) => {
hash_set.insert(ip);
}
IpAddr::V6(_) => {}
}
if udp.connect(changed_addr1).is_ok() {
match test_nat_(&udp, false, false, tid + 1) {
Ok((mapped_addr2, _)) => {
match mapped_addr2.ip() {
IpAddr::V4(ip) => {
hash_set.insert(ip);
if mapped_addr1 != mapped_addr2 {
nat_type = NatType::Symmetric;
}
}
IpAddr::V6(_) => {}
}
port_range = mapped_addr2.port().abs_diff(mapped_addr1.port());
for addr in &pub_addrs {
if let SocketAddr::V4(addr) = addr {
hash_set.insert(*addr.ip());
if min_port > addr.port() {
min_port = addr.port()
}
Err(e) => {
log::warn!("stun {} error {:?} ", stun_server, e);
if max_port < addr.port() {
max_port = addr.port()
}
}
}
log::warn!(
"stun {} mapped_addr {:?} nat_type {:?}",
stun_server,
mapped_addr1,
nat_type
);
Ok((
mapped_addr1,
nat_type,
hash_set.into_iter().collect(),
port_range,
max_port - min_port,
))
}
fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketAddr>> {
udp.connect(stun_server)?;
let tid = rand::thread_rng().next_u64() as u128;
let mut addr = HashSet::new();
let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?;
if mapped_addr1.is_ipv4() {
addr.insert(mapped_addr1);
}
if let Some(changed_addr1) = changed_addr1 {
if udp.connect(changed_addr1).is_ok() {
match test_nat_(&udp, false, false, tid + 1) {
Ok((mapped_addr2, _)) => {
if mapped_addr2.is_ipv4() {
addr.insert(mapped_addr1);
}
}
Err(e) => {
log::warn!("stun {} error {:?} ", stun_server, e);
}
}
}
}
log::info!(
"stun {} mapped_addr {:?} changed_addr {:?}",
stun_server,
addr,
changed_addr1,
);
Ok(addr)
}
fn test_nat_(
udp: &UdpSocket,
change_ip: bool,
change_port: bool,
tid: u128,
) -> io::Result<(SocketAddr, SocketAddr)> {
) -> io::Result<(SocketAddr, Option<SocketAddr>)> {
for _ in 0..2 {
let mut buf = [0u8; 28];
let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice());
msg.typ(stun_format::MsgType::BindingRequest).unwrap();
msg.tid(tid).unwrap();
msg.typ(stun_format::MsgType::BindingRequest);
msg.tid(tid);
msg.add_attr(Attr::ChangeRequest {
change_ip,
change_port,
})
.unwrap();
});
udp.send(msg.as_bytes())?;
let mut buf = [0; 10240];
let (len, _addr) = match udp.recv_from(&mut buf) {
@@ -166,11 +157,11 @@ fn test_nat_(
_ => {}
}
if changed_addr.is_some() && mapped_addr.is_some() {
return Ok((mapped_addr.unwrap(), changed_addr.unwrap()));
return Ok((mapped_addr.unwrap(), changed_addr));
}
}
if let Some(addr) = mapped_addr {
return Ok((addr, changed_addr.unwrap_or(addr)));
return Ok((addr, changed_addr));
}
}
Err(io::Error::new(io::ErrorKind::Other, "stun response err"))
@@ -186,3 +177,42 @@ fn stun_addr(addr: stun_format::SocketAddr) -> SocketAddr {
}
}
}
const TAG: u128 = 1827549368 << 64;
pub fn send_stun_request() -> Vec<u8> {
let mut buf = [0u8; 28];
let mut msg = stun_format::MsgBuilder::from(buf.as_mut_slice());
msg.typ(stun_format::MsgType::BindingRequest);
let id = rand::thread_rng().next_u64() as u128;
msg.tid(id | TAG);
msg.add_attr(Attr::ChangeRequest {
change_ip: false,
change_port: false,
});
msg.as_bytes().to_vec()
}
pub fn recv_stun_response(buf: &[u8]) -> Option<SocketAddr> {
if buf[0] != 0x01 && buf[1] != 0x01 {
return None;
}
let msg = stun_format::Msg::from(buf);
if let Some(tid) = msg.tid() {
if tid & TAG != TAG {
return None;
}
}
for x in msg.attrs_iter() {
match x {
Attr::MappedAddress(addr) => {
return Some(stun_addr(addr));
}
Attr::XorMappedAddress(addr) => {
return Some(stun_addr(addr));
}
_ => {}
}
}
None
}
+100
View File
@@ -0,0 +1,100 @@
use std::net::SocketAddr;
use std::str::FromStr;
use std::thread;
use anyhow::Context;
use crate::util::StopManager;
mod tcp_mapping;
mod udp_mapping;
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String)>> {
let mut rs = Vec::with_capacity(vec.len());
for x in vec {
let string = x.trim().to_lowercase();
if let Some(udp_mapping) = string.strip_prefix("udp:") {
let mut split = udp_mapping.split("->");
let bind_addr = split.next().with_context(|| {
format!(
"udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080",
x
)
})?;
let bind_addr = SocketAddr::from_str(bind_addr)
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
let dest = split.next().with_context(|| {
format!(
"udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080",
x
)
})?;
rs.push((false, bind_addr, dest.to_string()));
continue;
}
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
let mut split = tcp_mapping.split("->");
let bind_addr = split.next().with_context(|| {
format!(
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
x
)
})?;
let bind_addr = SocketAddr::from_str(bind_addr)
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
let dest = split.next().with_context(|| {
format!(
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
x
)
})?;
rs.push((true, bind_addr, dest.to_string()));
continue;
}
Err(anyhow::anyhow!(
"port_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
x
))?;
}
Ok(rs)
}
pub fn start_port_mapping(
stop_manager: StopManager,
vec: Vec<(bool, SocketAddr, String)>,
) -> anyhow::Result<()> {
if vec.is_empty() {
return Ok(());
}
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_name("portMapping")
.build()?;
runtime.block_on(start_port_mapping0(vec))?;
let (sender, receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("portMapping".into(), move || {
let _ = sender.send(());
})?;
thread::Builder::new()
.name("portMapping".into())
.spawn(move || {
runtime.block_on(async {
let _ = receiver.await;
});
runtime.shutdown_background();
drop(worker);
})?;
Ok(())
}
async fn start_port_mapping0(vec: Vec<(bool, SocketAddr, String)>) -> anyhow::Result<()> {
for (is_tcp, bind_addr, destination) in vec {
if is_tcp {
tcp_mapping::tcp_mapping(bind_addr, destination).await?;
} else {
udp_mapping::udp_mapping(bind_addr, destination).await?;
}
}
Ok(())
}
+49
View File
@@ -0,0 +1,49 @@
use anyhow::Context;
use std::net::SocketAddr;
use tokio::net::{TcpListener, TcpStream};
pub async fn tcp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> {
let tcp_listener = TcpListener::bind(bind_addr)
.await
.with_context(|| format!("TCP binding {:?} failed", bind_addr))?;
tokio::spawn(tcp_mapping_(bind_addr, tcp_listener, destination));
Ok(())
}
async fn tcp_mapping_(
bind_addr: SocketAddr,
tcp_listener: TcpListener,
destination: String,
) -> anyhow::Result<()> {
loop {
let (tcp_stream, _) = tcp_listener.accept().await?;
let destination = destination.clone();
tokio::spawn(async move {
if let Err(e) = copy(tcp_stream, &destination).await {
log::warn!("tcp port mapping {}->{} {:?}", bind_addr, destination, e);
}
});
}
}
async fn copy(source_tcp: TcpStream, destination: &String) -> anyhow::Result<()> {
let dest_tcp = TcpStream::connect(destination)
.await
.with_context(|| format!("TCP connection target failed {:?}", destination))?;
let _ = source_tcp.set_nodelay(true);
let _ = dest_tcp.set_nodelay(true);
let destination = dest_tcp.peer_addr()?;
let (mut client_read, mut client_write) = source_tcp.into_split();
let (mut server_read, mut server_write) = dest_tcp.into_split();
tokio::spawn(async move {
if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await {
log::warn!("client tcp proxy ->{:},{:?}", destination, e);
}
});
if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await {
log::warn!("server tcp proxy ->{:?},{:?}", destination, e);
}
Ok(())
}
+107
View File
@@ -0,0 +1,107 @@
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::UdpSocket;
pub async fn udp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> {
let udp = UdpSocket::bind(bind_addr)
.await
.with_context(|| format!("port proxy UDP binding {:?} failed", bind_addr))?;
let udp = Arc::new(udp);
let inner_map: Arc<Mutex<HashMap<SocketAddr, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
Arc::new(Mutex::new(HashMap::with_capacity(64)));
tokio::spawn(async move {
let mut buf = [0; 65536];
loop {
match udp.recv_from(&mut buf).await {
Ok((len, src_addr)) => {
if let Err(e) =
udp_mapping0(&buf[..len], src_addr, &inner_map, &udp, &destination).await
{
log::warn!("udp port mapping {}->{} {:?}", src_addr, destination, e);
}
}
Err(e) => {
log::warn!("port proxy UDP {:?}", e);
}
}
}
});
Ok(())
}
async fn udp_mapping0(
buf: &[u8],
src_addr: SocketAddr,
inner_map: &Arc<Mutex<HashMap<SocketAddr, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
udp_socket: &Arc<UdpSocket>,
destination: &String,
) -> anyhow::Result<()> {
let option = inner_map.lock().get(&src_addr).cloned();
if let Some((udp, time)) = option {
time.store(Instant::now());
udp.send(buf).await?;
} else {
let dest_udp = UdpSocket::bind("0.0.0.0:0").await?;
dest_udp.connect(destination).await?;
dest_udp.send(buf).await?;
let destination_addr = dest_udp.peer_addr()?;
let udp_socket = udp_socket.clone();
let inner_map = inner_map.clone();
let dest_udp = Arc::new(dest_udp);
let time = Arc::new(AtomicCell::new(Instant::now()));
inner_map
.lock()
.insert(src_addr, (dest_udp.clone(), time.clone()));
tokio::spawn(async move {
let mut buf = [0u8; 65536];
loop {
match tokio::time::timeout(Duration::from_secs(600), dest_udp.recv(&mut buf)).await
{
Ok(rs) => match rs {
Ok(len) => match udp_socket.send_to(&buf[..len], src_addr).await {
Ok(_) => {}
Err(e) => {
log::warn!(
"udp port mapping {}->{} {:?}",
src_addr,
destination_addr,
e
);
break;
}
},
Err(e) => {
log::warn!(
"udp port mapping {}->{} {:?}",
src_addr,
destination_addr,
e
);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!(
"udp port mapping timeout {}->{} ",
src_addr,
destination_addr
);
break;
}
}
}
}
inner_map.lock().remove(&src_addr);
});
}
Ok(())
}
+6 -6
View File
@@ -5,12 +5,12 @@ use tun::Device;
#[cfg(any(target_os = "windows", target_os = "linux"))]
const DEFAULT_TUN_NAME: &str = "vnt-tun";
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
const DEFAULT_TAP_NAME: &str = "vnt-tap";
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub fn create_device(config: &crate::core::Config) -> io::Result<Arc<Device>> {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
let default_name: &str = if config.tap {
DEFAULT_TAP_NAME
} else {
@@ -21,11 +21,11 @@ pub fn create_device(config: &crate::core::Config) -> io::Result<Arc<Device>> {
let device_name = config
.device_name
.clone()
.unwrap_or(default_name.to_string());
if &device_name == default_name {
delete_device(default_name);
.unwrap_or(DEFAULT_TUN_NAME.to_string());
if &device_name == DEFAULT_TUN_NAME {
delete_device(DEFAULT_TUN_NAME);
}
Arc::new(Device::new(Some(device_name), config.tap)?)
Arc::new(Device::new(Some(device_name))?)
};
#[cfg(target_os = "macos")]
let device = Arc::new(Device::new(config.device_name.clone())?);
+8 -11
View File
@@ -26,7 +26,7 @@ impl DeviceAdapter {
#[cfg(target_os = "android")]
pub fn new(tun_device_helper: TunDeviceHelper) -> Self {
Self {
tun: Arc::new(Mutex::new(None)),
tun: Arc::new(AtomicCell::new(-1 as _)),
tun_device_helper,
}
}
@@ -43,22 +43,19 @@ impl std::ops::Deref for DeviceAdapter {
#[cfg(target_os = "android")]
#[derive(Clone)]
pub struct DeviceAdapter {
tun: Arc<Mutex<Option<Arc<Device>>>>,
tun: Arc<AtomicCell<std::os::fd::RawFd>>,
tun_device_helper: TunDeviceHelper,
}
#[cfg(target_os = "android")]
impl DeviceAdapter {
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
if let Some(device) = self.tun.lock().as_ref() {
use tun::device::IFace;
device.write(buf)
} else {
Err(io::Error::new(io::ErrorKind::Other, "not tun device"))
}
let fd = self.tun.load();
tun::Fd(fd).write(buf)
}
pub fn start(&self, device: Arc<Device>) -> io::Result<()> {
self.tun_device_helper.start(device.clone())?;
self.tun.lock().replace(device);
pub fn start(&self, fd: std::os::fd::RawFd) -> io::Result<()> {
//安卓端fd是由外部释放的,所以这里这么搞免得加锁
self.tun_device_helper.start(Arc::new(Device::new(fd)?))?;
self.tun.store(fd);
Ok(())
}
}
+15 -1
View File
@@ -102,7 +102,21 @@ pub fn dns_query_all(
let mut err: Option<anyhow::Error> = None;
for name_server in name_servers {
if let Some(domain) = txt_domain.as_ref() {
return txt_dns(domain, name_server);
match txt_dns(domain, name_server) {
Ok(addr) => {
if !addr.is_empty() {
return Ok(addr);
}
}
Err(e) => {
if let Some(err) = &mut err {
*err = anyhow::anyhow!("{} {}", err, e);
} else {
err.replace(anyhow::anyhow!("{}", e));
}
}
}
continue;
}
let end_index = domain
.rfind(":")
-2
View File
@@ -1,6 +1,4 @@
mod notify;
mod result_convert;
pub use result_convert::io_convert;
mod scheduler;
pub use notify::StopManager;
pub use scheduler::Scheduler;
+16
View File
@@ -1,6 +1,7 @@
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread::Thread;
use std::time::Duration;
use std::{io, thread};
use parking_lot::Mutex;
@@ -31,6 +32,9 @@ impl StopManager {
pub fn wait(&self) {
self.inner.wait();
}
pub fn wait_timeout(&self, dur: Duration) -> bool {
self.inner.wait_timeout(dur)
}
pub fn is_stop(&self) -> bool {
self.inner.state.load(Ordering::Acquire)
}
@@ -103,6 +107,18 @@ impl StopManagerInner {
thread::park()
}
}
fn wait_timeout(&self, dur: Duration) -> bool {
{
let mut guard = self.park_threads.lock();
guard.push(thread::current());
drop(guard);
}
if self.worker_num.load(Ordering::Acquire) == 0 {
return true;
}
thread::park_timeout(dur);
self.worker_num.load(Ordering::Acquire) == 0
}
fn stop_call(&self) {
if let Some(call) = self.stop_call.lock().take() {
call();
-10
View File
@@ -1,10 +0,0 @@
use std::fmt::Display;
use std::io;
#[inline]
pub fn io_convert<T, R: Display, F: FnOnce(&io::Error) -> R>(
rs: io::Result<T>,
f: F,
) -> io::Result<T> {
rs.map_err(|e| io::Error::new(e.kind(), format!("{},internal error:{:?}", f(&e), e)))
}
+9 -4
View File
@@ -13,6 +13,11 @@ impl Device {
Ok(Self { fd: Fd::new(fd)? })
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.fd
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
@@ -26,7 +31,7 @@ impl IFace for Device {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
fn set_ip(&self, _address: Ipv4Addr, _mask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
@@ -34,15 +39,15 @@ impl IFace for Device {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
fn set_mtu(&self, _value: u32) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
fn add_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
fn delete_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
+3 -1
View File
@@ -3,7 +3,6 @@
/// https://github.com/Tazdevil971/tap-windows
/// https://github.com/nulldotblack/wintun
pub mod device;
mod packet;
#[cfg(target_os = "linux")]
mod linux;
@@ -29,3 +28,6 @@ mod windows;
#[cfg(windows)]
pub use windows::Device;
#[cfg(windows)]
mod packet;
+16 -42
View File
@@ -1,29 +1,27 @@
#![allow(dead_code)]
use std::ffi::{CStr, CString};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::process::Command;
use std::{io, mem, ptr};
use libc::{
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TAP, IFF_TUN,
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TUN,
IFF_UP, IFNAMSIZ, O_RDWR, SOCK_DGRAM,
};
use crate::device::IFace;
use crate::linux::route;
use crate::linux::sys::*;
use crate::packet;
use crate::unix::{exe_cmd, Fd, SockAddr};
pub struct Device {
name: String,
ctl: Fd,
tun: Fd,
mac: Option<[u8; 6]>,
}
impl Device {
pub fn new(name: Option<String>, tap: bool) -> io::Result<Self> {
pub fn new(name: Option<String>) -> io::Result<Self> {
let device = unsafe {
let dev = match name {
Some(name) => {
@@ -50,7 +48,7 @@ impl Device {
);
}
let device_type: c_short = if tap { IFF_TAP } else { IFF_TUN } as c_short;
let device_type: c_short = IFF_TUN as c_short; //if tap { IFF_TAP } else { IFF_TUN } as c_short;
let queues_num = 1;
@@ -73,29 +71,11 @@ impl Device {
let name = CStr::from_ptr(req.ifr_name.as_ptr())
.to_string_lossy()
.to_string();
let mac = if tap {
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
let mac_out = exe_cmd(&get_mac_cmd)?;
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
let mut mac = [0; 6];
let mut split = mac_str.split(":");
for i in 0..6 {
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
}
Some(mac)
} else {
None
};
let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name);
if let Err(e) = exe_cmd(&set_txqueuelen){
log::warn!("{:?}",e);
}
Device {
name,
tun,
ctl,
mac,
let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name);
if let Err(e) = exe_cmd(&set_txqueuelen) {
log::warn!("{:?}", e);
}
Device { name, tun, ctl }
};
device.enabled(true)?;
Ok(device)
@@ -234,6 +214,12 @@ impl Device {
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.tun
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
@@ -286,22 +272,10 @@ impl IFace for Device {
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
if self.mac.is_some() {
packet::read_tap(
buf,
|eth_buf| self.tun.read(eth_buf),
|eth_buf| self.tun.write(eth_buf),
)
} else {
self.tun.read(buf)
}
self.tun.read(buf)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
if let Some(mac) = &self.mac {
packet::write_tap(buf, |eth_buf| self.tun.write(eth_buf), mac)
} else {
self.tun.write(buf)
}
self.tun.write(buf)
}
}
+6
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use std::ffi::{c_void, CStr};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
@@ -224,6 +225,11 @@ impl Device {
}
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.tun
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
+1
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use std::{fmt, io};
/// 地址解析协议,由IP地址找到MAC地址
+4 -1
View File
@@ -21,7 +21,10 @@ impl<B: AsRef<[u8]>> EthernetPacket<B> {
let packet = EthernetPacket::unchecked(buffer);
//头部固定14位
if packet.buffer.as_ref().len() < 14 {
Err(io::Error::new(io::ErrorKind::InvalidData,format!("len={}", packet.buffer.as_ref().len())))?;
Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("len={}", packet.buffer.as_ref().len()),
))?;
}
Ok(packet)
+1 -1
View File
@@ -13,7 +13,7 @@ where
let mut eth_buf = [0; 65536];
loop {
let len = read_fn(&mut eth_buf)?;
if len == 0{
if len == 0 {
return Ok(len);
}
//处理arp包
+8
View File
@@ -1,3 +1,4 @@
use libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
use std::io;
use std::os::fd::{AsRawFd, IntoRawFd, RawFd};
@@ -10,6 +11,12 @@ impl Fd {
}
Ok(Fd(value))
}
pub fn set_nonblock(&self) -> io::Result<()> {
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
0 => Ok(()),
_ => Err(io::Error::last_os_error()),
}
}
}
impl Fd {
@@ -51,6 +58,7 @@ impl IntoRawFd for Fd {
}
}
#[cfg(not(target_os = "android"))]
impl Drop for Fd {
fn drop(&mut self) {
unsafe {
+1
View File
@@ -1,6 +1,7 @@
mod fd;
pub use fd::Fd;
#[cfg(any(target_os = "macos", target_os = "linux"))]
use std::process::Output;
#[cfg(any(target_os = "macos", target_os = "linux"))]
mod sockaddr;
+2 -1
View File
@@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::windows::exe_cmd;
use std::io;
use std::net::Ipv4Addr;
use std::{io, process};
/// 设置网卡名称
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
+2 -5
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use std::io;
use std::net::Ipv4Addr;
use winapi::shared::ifdef::NET_LUID;
@@ -11,8 +12,6 @@ use winapi::um::winnt::{
use crate::device::IFace;
use crate::packet;
use crate::packet::ethernet::protocol::Protocol;
use crate::packet::{arp, ethernet};
use crate::windows::{ctl_code, decode_utf16, encode_utf16, ffi, netsh, route};
/* Present in 8.1 */
@@ -97,7 +96,7 @@ impl Device {
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
// 设置网卡跃点
if let Err(e) = netsh::set_interface_metric(index, 0) {
log::warn!("{:?}",e);
log::warn!("{:?}", e);
}
let device = Self {
handle,
@@ -122,8 +121,6 @@ impl Device {
}
}
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
impl IFace for Device {
fn version(&self) -> io::Result<String> {
let mut version = [0u32; 3];
+4 -3
View File
@@ -1,4 +1,5 @@
use libloading::{Error, Library};
#![allow(dead_code)]
use libloading::Library;
use std::io;
use std::net::Ipv4Addr;
@@ -84,7 +85,7 @@ impl Device {
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(guid) };
let guid_struct: wintun_raw::GUID = std::mem::transmute(guid);
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
@@ -118,7 +119,7 @@ impl Device {
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
// 设置网卡跃点
if let Err(e) = netsh::set_interface_metric(index, 0) {
log::warn!("{:?}",e);
log::warn!("{:?}", e);
}
Ok(Self {
luid: std::mem::transmute(luid),
+1
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use log::*;
use crate::windows::tun::wintun_raw;
+2
View File
@@ -1,3 +1,5 @@
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
/* automatically generated by rust-bindgen 0.59.1 */
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]