@@ -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
@@ -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",
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
@@ -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
@@ -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-tun,tap模式使用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
|
||||
在后台运行时,查看其他设备列表
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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!(
|
||||
|
||||
@@ -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"]
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,3 +2,4 @@ pub mod callback;
|
||||
pub mod config;
|
||||
pub mod utils;
|
||||
pub mod vnt;
|
||||
pub(crate) mod vnt_logger;
|
||||
|
||||
+13
-2
@@ -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(
|
||||
|
||||
@@ -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
@@ -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"]
|
||||
|
||||
@@ -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
@@ -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>>)>,
|
||||
)>
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, ¤t_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,
|
||||
¤t_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(())
|
||||
}
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
¤t_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::*;
|
||||
|
||||
@@ -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,
|
||||
¤t_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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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,
|
||||
¤t_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,
|
||||
¤t_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
@@ -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
@@ -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
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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())?);
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(":")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,3 +1,4 @@
|
||||
#![allow(dead_code)]
|
||||
use std::{fmt, io};
|
||||
|
||||
/// 地址解析协议,由IP地址找到MAC地址
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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包
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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<()> {
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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,3 +1,4 @@
|
||||
#![allow(dead_code)]
|
||||
use log::*;
|
||||
|
||||
use crate::windows::tun::wintun_raw;
|
||||
|
||||
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user