Compare commits

...
137 Commits
Author SHA1 Message Date
vnt-dev 13b7b1761d Merge pull request #63 from vnt-dev/1.2.x
1.2.x
2024-07-25 10:28:28 +08:00
lbl8603 352f322f61 生成guid 2024-07-24 22:11:50 +08:00
lbl8603 be966c4f83 简化广播 2024-07-23 22:25:55 +08:00
lbl8603 b8cbf2cdac 不在线的可以不转发 2024-07-20 23:26:11 +08:00
lbl8603 05cf0e1a6f 修改版本 2024-07-20 14:48:56 +08:00
lbl8603 f90ef96a5d 增加sys-locale 2024-07-20 11:12:45 +08:00
lbl8603 81c6c8c1fc Merge branch 'refs/heads/1.2.x' into 1.2.x-2024-07-20-1
# Conflicts:
#	common/src/cli.rs
2024-07-20 11:10:15 +08:00
lbl8603 7ebdffcdd3 支持wg 2024-07-20 10:38:18 +08:00
lbl8603 1abe33cb16 Merge pull request #61 from jslyrd/main
添加英文帮助信息
2024-07-16 23:11:44 +08:00
jslyrd 965cbfbb7e 添加英文帮助信息 2024-07-16 22:32:48 +08:00
lbl8603 aa332b4f4d Merge pull request #60 from lbl8603/1.2.x
1.2.x
2024-07-13 15:53:53 +08:00
lbl8603 14ee9c4632 Merge branch 'refs/heads/1.2.x' into 1.2.x-2024-07-04 2024-07-13 12:11:24 +08:00
lbl8603 ddfa89167d 修改地址探测和转发路径 2024-07-13 12:09:15 +08:00
lbl8603 1f9ed7b314 修改features 2024-07-13 12:01:41 +08:00
lbl8603 dc45602661 Merge pull request #58 from lbl8603/1.2.x
调整添加转发路径的逻辑
2024-07-10 23:09:49 +08:00
lbl8603 27c0f389ee 调整添加转发路径的逻辑 2024-07-10 22:54:13 +08:00
lbl8603 59d6bfd957 Merge pull request #56 from lbl8603/1.2.x
1.2.x
2024-07-07 23:29:16 +08:00
lbl8603 31b8661b7d 设置证书 2024-07-07 22:38:01 +08:00
lbl8603 8ae20497c6 避免除0 2024-07-07 13:05:31 +08:00
lbl8603 a70b4f30b5 增加统计模块 2024-07-06 17:18:44 +08:00
lbl8603 df4795c9c4 加入少量轮询 2024-07-06 17:13:32 +08:00
lbl8603 c21a73f950 忽略初次错误 2024-07-06 16:45:55 +08:00
lbl8603 29cd111a49 fmt 2024-07-06 16:44:30 +08:00
lbl8603 367a56d346 Merge branch 'refs/heads/1.2.x' into 1.2.x-2024-07-04 2024-07-06 16:28:14 +08:00
lbl8603 d81ac6368e 增加流量统计 2024-07-06 16:27:08 +08:00
lbl8603 a228b62d23 Merge pull request #55 from Iron-Yang-Go/1.2.x
Try to execute 'dmidecode' command to get the system identifier first
2024-07-03 22:58:24 +08:00
Iron-Yang 995ff9b059 Try to execute 'dmidecode' command to get the system identifier first 2024-07-03 22:46:59 +08:00
lbl8603 7dc78cc170 修复时间相差导致的异常 2024-07-03 22:34:29 +08:00
lbl8603 7e218355f2 编译websocket 2024-07-02 21:18:08 +08:00
lbl8603 98c394c993 修改错误输出 2024-07-02 21:17:08 +08:00
lbl8603 31b06cd713 去除缓冲区设置 2024-07-01 23:04:08 +08:00
lbl8603 d7266926d8 增加Sync 2024-07-01 23:03:52 +08:00
lbl8603 1df5a1cfb1 去除不安全的计数器 2024-06-30 23:02:50 +08:00
lbl8603 8658bd3601 去除println 2024-06-30 22:19:05 +08:00
lbl8603 17d1ad3716 支持websocket协议 2024-06-30 22:16:30 +08:00
lbl8603 728598ba8e 处理遗留问题 2024-06-29 18:44:36 +08:00
lbl8603 218483f431 支持upnp 2024-06-29 17:29:37 +08:00
lbl8603 1f80e06d9d 服务端流量过滤 2024-06-29 17:28:30 +08:00
lbl8603 5e56064ec6 ipv6转ipv4判断 2024-06-29 17:26:52 +08:00
lbl8603 31f0213fc5 优化停止逻辑 2024-06-27 22:09:25 +08:00
lbl8603 54b1fef164 增加日志 2024-06-27 22:09:13 +08:00
lbl8603 7c18df0a6f 参考std判断公网IP 2024-06-27 21:59:57 +08:00
lbl8603 916fd8254b 修改stun 2024-06-27 21:58:17 +08:00
lbl8603 9e249862dc 排除虚拟网段 2024-06-26 21:53:59 +08:00
lbl8603 3773c09f57 调整任务停止逻辑 2024-06-25 22:48:06 +08:00
lbl8603 6798c652f9 减少socket数目,降低网络压力 2024-06-25 22:47:38 +08:00
lbl8603 382d5b61ba 调整退避速度 2024-06-25 22:47:19 +08:00
lbl8603 ac162eba66 调整打洞频率 2024-06-20 22:22:01 +08:00
lbl8603 05a60b3cb7 增加包长度上限 2024-06-17 23:46:34 +08:00
lbl8603 7f210e9319 调整获取地址频率 2024-06-17 23:44:11 +08:00
lbl8603 481c00629a 更新地址成功则返回true 2024-06-17 23:43:54 +08:00
lbl8603 bf55ec9512 修改文件名 2024-06-17 22:41:08 +08:00
lbl8603 073fa6ac6b 修改tun占用内存的大小 2024-06-15 22:18:51 +08:00
lbl8603 51315efb52 修改依赖 2024-06-15 21:16:04 +08:00
lbl8603 30cbf39e7f 排除生成的文件 2024-06-15 21:15:52 +08:00
lbl8603 2973d88df3 修改描述 2024-06-15 21:03:41 +08:00
lbl8603 8b2d7293fe 增加程序说明 2024-06-15 20:55:14 +08:00
lbl8603 215d9aa362 编译vn-link-cli 2024-06-15 20:55:05 +08:00
lbl8603 c3f27e8727 调整依赖 2024-06-15 20:54:49 +08:00
lbl8603 755339189d 去除重复代码 2024-06-15 20:54:35 +08:00
lbl8603 71cf0aa66d 初始化无tun的命令行程序 2024-06-15 20:54:18 +08:00
lbl8603 d695efd787 抽离公共逻辑 2024-06-15 20:53:32 +08:00
lbl8603 66129c2a24 支持无tun模式 2024-06-15 20:52:35 +08:00
lbl8603 0bc7115102 支持外置网卡 2024-06-15 20:51:00 +08:00
lbl8603 dca33a3ec1 fmt 2024-06-15 20:50:35 +08:00
lbl8603 9acbae2554 调整模块 2024-06-15 20:49:53 +08:00
lbl8603 ccfff7b1f6 调整参数格式 2024-06-15 20:49:34 +08:00
lbl8603 39ae4c5dd6 inline 2024-06-15 20:48:20 +08:00
lbl8603 350357076d 抽离发送IP包的逻辑 2024-06-15 20:47:37 +08:00
lbl8603 1e5e15f1f5 不再需要jni 2024-06-15 20:44:20 +08:00
lbl8603 1a385a777e 修改feature名称 2024-06-09 00:16:48 +08:00
lbl8603 16278dae62 优化代码结构 2024-06-09 00:11:33 +08:00
lbl8603 8294e46003 去除多余参数 2024-06-09 00:03:47 +08:00
lbl8603 dedc66875b 支持排除tun 2024-06-09 00:03:28 +08:00
lbl8603 3045e239ff Merge branch 'refs/heads/1.2.x' into 2024-05-31 2024-06-07 22:42:29 +08:00
lbl8603 5363558118 忽略io interrupted 2024-06-06 21:42:14 +08:00
lbl8603 13ba7cf0b8 优化提示 2024-06-06 21:41:56 +08:00
lbl8603 a5a43e762d 修改命令处理 2024-06-06 21:39:46 +08:00
lbl8603 cb6101a835 修改tap模式说明 2024-06-05 23:11:56 +08:00
lbl8603 255f84c969 提示创建tun失败的信息 2024-06-05 22:58:56 +08:00
lbl8603 7617d6c409 修改加密描述 2024-06-05 22:39:02 +08:00
lbl8603 f75691b483 过滤非vnt包 2024-06-05 22:38:51 +08:00
lbl8603 c5dbb79ed2 完善代码说明 2024-06-04 23:41:56 +08:00
lbl8603 60ba3c64b2 调整加密逻辑 2024-06-04 23:12:51 +08:00
lbl8603 080e58eeb7 调整代码 2024-06-04 23:00:27 +08:00
lbl8603 5d228b9c27 使用fnv 2024-06-04 22:58:35 +08:00
lbl8603 e36e45054c Merge pull request #49 from lbl8603/1.2.x
1.2.x
2024-06-01 17:00:51 +08:00
lbl8603 ba87a2780d Update README.md 2024-06-01 16:59:54 +08:00
lbl8603 fccc3478c8 增加GUI程序 2024-06-01 16:38:17 +08:00
lbl8603 a76280c53b 调整代码结构 2024-05-29 22:47:48 +08:00
lbl8603 90ff03e27c 计算密码hash 2024-05-28 23:21:43 +08:00
lbl8603 5eed05989f 增加ChaCah20和signal-hook 2024-05-28 22:49:06 +08:00
lbl8603 ac939746bd 增加ChaCah20 2024-05-28 22:48:46 +08:00
lbl8603 b7532e89c2 简化条件编译 2024-05-28 22:48:09 +08:00
lbl8603 74f44d6961 增加ChaCah20 2024-05-28 22:47:50 +08:00
lbl8603 86fc27c233 使用anyhow调整错误处理 2024-05-28 22:45:15 +08:00
lbl8603 4b6bb0e5f7 调整加密 2024-05-28 22:42:58 +08:00
lbl8603 215337fd8a 支持数据压缩 2024-05-25 17:30:27 +08:00
lbl8603 e54341567a 去除安卓上的icmp代理 2024-05-23 22:35:37 +08:00
lbl8603 1ce3e9ff2e 停止时回收连接通道 2024-05-23 22:35:24 +08:00
lbl8603 ffdb5ceb6b 去除无用状态 2024-05-23 22:35:06 +08:00
lbl8603 faa78445b1 返回具体错误信息 2024-05-21 20:37:55 +08:00
lbl8603 39170b74ca Merge pull request #43 from lbl8603/1.2.x
调整条件编译
2024-05-15 20:32:05 +08:00
lbl8603 440a832ace 调整条件编译 2024-05-15 20:30:42 +08:00
lbl8603 0e3f06429b Merge pull request #42 from lbl8603/1.2.x
处理unix去掉所有模块的编译问题
2024-05-14 09:25:52 +08:00
lubeilin 01cf8806e2 处理unix去掉所有模块的编译问题 2024-05-14 09:25:16 +08:00
lbl8603 ee7c597bd8 Merge pull request #41 from lbl8603/1.2.x
1.2.x
2024-05-13 22:53:51 +08:00
lbl8603 a85e0c6d06 修改图片地址 2024-05-13 22:53:22 +08:00
lbl8603 fee3b24df4 减少无用日志 2024-05-13 22:07:05 +08:00
lbl8603 7f500d72c7 Merge pull request #39 from lbl8603/1.2.x
支持--no-default-features编译
2024-05-11 13:31:04 +08:00
lubeilin d8a9ec5732 支持--no-default-features编译 2024-05-11 13:30:16 +08:00
lbl8603 4dca4c4f22 Merge pull request #38 from lbl8603/1.2.x
1.2.x
2024-05-11 09:21:57 +08:00
lbl8603 0e4294415e 增加日志输出内容 2024-05-10 23:19:52 +08:00
lbl8603 9df324f402 增加输出端口映射和ip代理内容 2024-05-10 23:18:45 +08:00
lbl8603 3b1236cfd0 通过stun探测端口,解决使用ipv6或tcp服务时端口错误的问题 2024-05-10 23:18:24 +08:00
lbl8603 699262d79e rustup set auto-self-update disable 2024-05-10 23:16:37 +08:00
lbl8603 f6cfa1b84c 调整安卓端tun逻辑 2024-05-09 22:51:27 +08:00
lbl8603 1338bcbbc5 消除代码警告 2024-05-09 21:25:55 +08:00
lbl8603 4215488cb6 调整中继模式的逻辑 2024-05-09 20:16:02 +08:00
lbl8603 ccd6e44c2b 使用异步tun 2024-05-09 20:14:01 +08:00
lbl8603 b12b0b95a0 去除linux上的tap 2024-05-09 20:13:44 +08:00
lbl8603 948f3d5d24 遍历txt记录值 2024-05-09 20:12:26 +08:00
lbl8603 cf4fc54dfd 端口映射列表为空时不启动 2024-05-09 20:11:43 +08:00
lbl8603 5a9e31bded 支持异步tun 2024-05-09 20:11:08 +08:00
lbl8603 b61c140c24 去除linux上tap的支持 2024-05-09 20:10:17 +08:00
lbl8603 035ae46ee5 过滤/etc/machine-id为空的情况 2024-05-09 20:07:46 +08:00
lbl8603 b57a38e81e 增加超时方法 2024-05-08 23:58:38 +08:00
lbl8603 be767ae300 增加提示 2024-05-08 23:58:03 +08:00
lbl8603 607c8c2e9f 增加端口映射功能 2024-05-08 21:31:21 +08:00
lbl8603 d3dce7a3cc 调整stun处理 2024-05-08 20:20:09 +08:00
lbl8603 ff2bbdd837 改回用tokio处理代理,简化代码 2024-05-08 20:19:33 +08:00
lbl8603 b771b6c074 增加set_ttl方法 2024-05-08 20:16:36 +08:00
lubeilin ff389647c0 修改帮助描述 2024-05-06 21:00:12 +08:00
lubeilin 49bec2d6aa 使用anyhow替换部分处理 2024-05-06 20:02:40 +08:00
lbl8603 ee359dc0d8 调整子网路由逻辑 2024-05-01 15:30:31 +08:00
lbl8603 d4fc28dca3 收到PunchRequest时不添加路由 2024-05-01 15:21:25 +08:00
lbl8603 1130f69a82 修改默认rt 2024-05-01 14:50:00 +08:00
160 changed files with 8461 additions and 5662 deletions
+34 -19
View File
@@ -44,40 +44,40 @@ jobs:
FEATURES: default
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
OS: ubuntu-latest
FEATURES: openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested
OS: ubuntu-latest
FEATURES: openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested
OS: ubuntu-latest
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
OS: macos-latest
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
OS: macos-latest
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: i686-pc-windows-msvc # tested on a windows machine
OS: windows-2019
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
OS: windows-latest
FEATURES: ring-cipher,openssl-vendored
FEATURES: ring-cipher,wss
- TARGET: mipsel-unknown-linux-musl # openwrt
OS: ubuntu-latest
FEATURES: openssl-vendored,ring-cipher
FEATURES: ring-cipher,wss
- TARGET: mips-unknown-linux-musl # openwrt
OS: ubuntu-latest
FEATURES: openssl-vendored
FEATURES: ring-cipher,wss
# needs: test
runs-on: ${{ matrix.OS }}
env:
@@ -105,8 +105,10 @@ 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
sudo apt-get update && sudo apt-get install clang llvm libc6-dev-i386 crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools libboost-all-dev libc6-dev -y
# curl -s musl.cc | grep mipsel
case $TARGET in
mipsel-unknown-linux-musl)
@@ -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
@@ -185,7 +193,9 @@ jobs:
EOF
- name: Install rust target
run: rustup target add $TARGET
- name: Run build
- name: Run build vn-link-cli
run: cargo build --package vn-link-cli --release --verbose --target $TARGET --features $FEATURES
- name: Run build vnt-cli
run: cargo build --package vnt-cli --release --verbose --target $TARGET --features $FEATURES
- name: List target
run: find ./target
@@ -194,17 +204,22 @@ jobs:
mkdir -p ./artifacts
# windows is the only OS using a different convention for executable file name
if [[ $OS =~ ^windows.*$ ]]; then
EXEC=$NAME.exe
EXEC_VNT_CLI=vnt-cli.exe
EXEC_VN_LINK_CLI=vn-link-cli.exe
else
EXEC=$NAME
EXEC_VNT_CLI=vnt-cli
EXEC_VN_LINK_CLI=vn-link-cli
fi
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
TAG=$GITHUB_REF_NAME
else
TAG=$GITHUB_SHA
fi
mv ./target/$TARGET/release/$EXEC ./artifacts/$EXEC
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz -C ./artifacts $EXEC
mv ./target/$TARGET/release/$EXEC_VNT_CLI ./artifacts/$EXEC_VNT_CLI
mv ./target/$TARGET/release/$EXEC_VN_LINK_CLI ./artifacts/$EXEC_VN_LINK_CLI
mv ./README ./artifacts/README.txt
cd ./artifacts
tar -czf vnt-$TARGET-$TAG.tar.gz *
- name: Archive artifact
uses: actions/upload-artifact@v2
with:
+4 -1
View File
@@ -1,3 +1,6 @@
target/*
vnt/src/proto/*
vnt-cli/src/generated_serial_number.rs
common/src/generated_serial_number.rs
# RustRover
.idea
Generated
+827 -169
View File
@@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aead"
version = "0.5.2"
@@ -73,18 +88,74 @@ version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
[[package]]
name = "attohttpc"
version = "0.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb8867f378f33f78a811a8eb9bf108ad99430d7aad43315dd9319c827ef6247"
dependencies = [
"http 0.2.12",
"log",
"url",
"wildmatch",
]
[[package]]
name = "autocfg"
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 = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bindgen"
version = "0.69.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
dependencies = [
"bitflags 2.5.0",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.60",
"which",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -144,15 +215,23 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.94"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
dependencies = [
"jobserver",
"libc",
"once_cell",
]
[[package]]
name = "cesu8"
version = "1.1.0"
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
@@ -160,6 +239,36 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chacha20"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "chacha20poly1305"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead",
"chacha20",
"cipher",
"poly1305",
"zeroize",
]
[[package]]
name = "chrono"
version = "0.4.38"
@@ -182,21 +291,38 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
"zeroize",
]
[[package]]
name = "combine"
version = "4.6.7"
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"bytes",
"memchr",
"glob",
"libc",
"libloading",
]
[[package]]
name = "common"
version = "1.2.9"
version = "1.2.12"
dependencies = [
"anyhow",
"chrono",
"console",
"gethostname",
"getopts",
"log",
"log4rs",
"rand",
"serde",
"serde_yaml",
"sys-locale",
"uuid",
"vnt",
]
[[package]]
name = "console"
@@ -217,6 +343,16 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
@@ -232,6 +368,38 @@ dependencies = [
"libc",
]
[[package]]
name = "crossbeam"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
@@ -276,6 +444,12 @@ dependencies = [
"cipher",
]
[[package]]
name = "data-encoding"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
[[package]]
name = "der"
version = "0.7.9"
@@ -340,12 +514,6 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
[[package]]
name = "embed-manifest"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cd446c890d6bed1d8b53acef5f240069ebef91d6fae7c5f52efe61fe8b5eae"
[[package]]
name = "encode_unicode"
version = "0.3.6"
@@ -380,6 +548,59 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
dependencies = [
"percent-encoding",
]
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
]
[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-core",
"futures-macro",
"futures-sink",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -390,6 +611,16 @@ dependencies = [
"version_check",
]
[[package]]
name = "gethostname"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
dependencies = [
"libc",
"windows-targets 0.48.5",
]
[[package]]
name = "getopts"
version = "0.2.21"
@@ -422,6 +653,18 @@ dependencies = [
"polyval",
]
[[package]]
name = "gimli"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -434,6 +677,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"
@@ -443,6 +692,34 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "httparse"
version = "1.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
[[package]]
name = "humantime"
version = "2.1.0"
@@ -472,6 +749,29 @@ dependencies = [
"cc",
]
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "igd"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556b5a75cd4adb7c4ea21c64af1c48cefb2ce7d43dc4352c720a1fe47c21f355"
dependencies = [
"attohttpc",
"log",
"rand",
"url",
"xmltree",
]
[[package]]
name = "indexmap"
version = "1.9.3"
@@ -508,6 +808,15 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
@@ -515,27 +824,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jni"
version = "0.21.1"
name = "jobserver"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
dependencies = [
"cesu8",
"cfg-if",
"combine",
"jni-sys",
"log",
"thiserror",
"walkdir",
"windows-sys 0.45.0",
"libc",
]
[[package]]
name = "jni-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "js-sys"
version = "0.3.69"
@@ -554,6 +850,12 @@ dependencies = [
"spin 0.5.2",
]
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.153"
@@ -579,7 +881,7 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "libsm"
version = "0.5.1"
source = "git+https://github.com/lbl8603/libsm#f9e1b8cf20d0829efb4934a940d0ba4f3ee0ac14"
source = "git+https://github.com/vnt-dev/libsm#f9e1b8cf20d0829efb4934a940d0ba4f3ee0ac14"
dependencies = [
"byteorder",
"getrandom",
@@ -650,12 +952,47 @@ dependencies = [
"winapi",
]
[[package]]
name = "lwip-rs"
version = "0.1.0"
source = "git+https://github.com/vnt-dev/lwip-rs#3133f0c3bde55333a27641182ae3550e7acc2a39"
dependencies = [
"bindgen",
"cc",
"crossbeam",
"lazy_static",
"log",
"parking_lot",
"tokio",
]
[[package]]
name = "lz4_flex"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
[[package]]
name = "memchr"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[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"
@@ -668,6 +1005,16 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-bigint"
version = "0.4.4"
@@ -726,6 +1073,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"
@@ -738,6 +1104,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
version = "300.1.3+3.1.2"
@@ -749,7 +1121,7 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.93"
source = "git+https://github.com/lbl8603/rust-openssl#e8b3d2c02d2d07a0e4a82ff4e4bef210f4bc71c8"
source = "git+https://github.com/vnt-dev/rust-openssl#e8b3d2c02d2d07a0e4a82ff4e4bef210f4bc71c8"
dependencies = [
"cc",
"libc",
@@ -767,17 +1139,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "os_info"
version = "3.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
dependencies = [
"log",
"serde",
"windows-sys 0.52.0",
]
[[package]]
name = "packet"
version = "0.1.0"
@@ -817,6 +1178,24 @@ dependencies = [
"base64ct",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkcs1"
version = "0.7.5"
@@ -844,6 +1223,17 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "polyval"
version = "0.6.2"
@@ -862,6 +1252,16 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "prettyplease"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
dependencies = [
"proc-macro2",
"syn 2.0.60",
]
[[package]]
name = "proc-macro2"
version = "1.0.81"
@@ -873,9 +1273,9 @@ dependencies = [
[[package]]
name = "protobuf"
version = "3.4.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58678a64de2fced2bdec6bca052a6716a0efe692d6e3f53d1bda6a1def64cfc0"
checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e"
dependencies = [
"once_cell",
"protobuf-support",
@@ -884,9 +1284,9 @@ dependencies = [
[[package]]
name = "protobuf-codegen"
version = "3.4.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32777b0b3f6538d9d2e012b3fad85c7e4b9244b5958d04a6415f4333782b7a77"
checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901"
dependencies = [
"anyhow",
"once_cell",
@@ -899,9 +1299,9 @@ dependencies = [
[[package]]
name = "protobuf-parse"
version = "3.4.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96cb37955261126624a25b5e6bda40ae34cf3989d52a783087ca6091b29b5642"
checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49"
dependencies = [
"anyhow",
"indexmap 1.9.3",
@@ -915,9 +1315,9 @@ dependencies = [
[[package]]
name = "protobuf-support"
version = "3.4.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1ed294a835b0f30810e13616b1cd34943c6d1e84a8f3b0dcfe466d256c3e7e7"
checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372"
dependencies = [
"thiserror",
]
@@ -1096,6 +1496,18 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.32"
@@ -1109,6 +1521,60 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rustls"
version = "0.23.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
dependencies = [
"once_cell",
"ring",
"rustls-pki-types",
"rustls-webpki",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba"
dependencies = [
"openssl-probe",
"rustls-pemfile",
"rustls-pki-types",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
dependencies = [
"base64",
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
[[package]]
name = "rustls-webpki"
version = "0.102.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e"
dependencies = [
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "ryu"
version = "1.0.17"
@@ -1116,12 +1582,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "same-file"
version = "1.0.6"
name = "schannel"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
dependencies = [
"winapi-util",
"windows-sys 0.52.0",
]
[[package]]
@@ -1130,6 +1596,29 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
dependencies = [
"bitflags 2.5.0",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "serde"
version = "1.0.198"
@@ -1184,6 +1673,17 @@ dependencies = [
"unsafe-libyaml",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.8"
@@ -1195,6 +1695,31 @@ dependencies = [
"digest",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [
"libc",
"signal-hook-registry",
]
[[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"
@@ -1205,6 +1730,15 @@ dependencies = [
"rand_core",
]
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
]
[[package]]
name = "smallvec"
version = "1.13.2"
@@ -1301,6 +1835,15 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sys-locale"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0"
dependencies = [
"libc",
]
[[package]]
name = "tempfile"
version = "3.10.1"
@@ -1343,6 +1886,79 @@ dependencies = [
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[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 = "tokio-rustls"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
dependencies = [
"rustls",
"rustls-pki-types",
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd"
dependencies = [
"futures-util",
"log",
"rustls",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
"tokio-rustls",
"tungstenite",
"webpki-roots",
]
[[package]]
name = "tun"
version = "0.1.0"
@@ -1352,10 +1968,31 @@ dependencies = [
"libloading",
"log",
"rand",
"sha2",
"widestring",
"winapi",
]
[[package]]
name = "tungstenite"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8"
dependencies = [
"byteorder",
"bytes",
"data-encoding",
"http 1.1.0",
"httparse",
"log",
"rand",
"rustls",
"rustls-pki-types",
"sha1",
"thiserror",
"utf-8",
]
[[package]]
name = "typemap-ors"
version = "1.0.0"
@@ -1371,6 +2008,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-bidi"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-ident"
version = "1.0.12"
@@ -1378,10 +2021,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
version = "0.1.11"
name = "unicode-normalization"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
[[package]]
name = "universal-hash"
@@ -1414,6 +2066,23 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uuid"
version = "1.8.0"
@@ -1435,24 +2104,54 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vn-link"
version = "1.2.12"
dependencies = [
"anyhow",
"crossbeam-utils",
"log",
"lwip-rs",
"parking_lot",
"tokio",
"vnt",
]
[[package]]
name = "vn-link-cli"
version = "1.2.12"
dependencies = [
"common",
"log",
"tokio",
"vn-link",
]
[[package]]
name = "vnt"
version = "1.2.9"
version = "1.2.12"
dependencies = [
"aes",
"aes-gcm",
"anyhow",
"bytes",
"cbc",
"cfg_aliases",
"chacha20",
"chacha20poly1305",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
"dns-parser",
"ecb",
"fnv",
"futures-util",
"igd",
"libc",
"libloading",
"libsm",
"log",
"lz4_flex",
"mio",
"openssl-sys",
"packet",
@@ -1463,57 +2162,33 @@ dependencies = [
"rand",
"ring",
"rsa",
"rustls",
"sha2",
"socket2",
"spki",
"stun-format",
"thiserror",
"tokio",
"tokio-tungstenite",
"tun",
"zstd",
]
[[package]]
name = "vnt-cli"
version = "1.2.9"
version = "1.2.12"
dependencies = [
"anyhow",
"chrono",
"common",
"console",
"embed-manifest",
"getopts",
"log",
"log4rs",
"os_info",
"rand",
"serde",
"serde_yaml",
"signal-hook",
"sudo",
"uuid",
"vnt",
"winapi",
]
[[package]]
name = "vnt-jni"
version = "1.2.9"
dependencies = [
"common",
"jni",
"log",
"parking_lot",
"spki",
"vnt",
]
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@@ -1574,6 +2249,15 @@ version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "webpki-roots"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "which"
version = "4.4.2"
@@ -1592,6 +2276,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
[[package]]
name = "wildmatch"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
[[package]]
name = "winapi"
version = "0.3.9"
@@ -1608,15 +2298,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
@@ -1632,15 +2313,6 @@ dependencies = [
"windows-targets 0.52.5",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@@ -1659,21 +2331,6 @@ dependencies = [
"windows-targets 0.52.5",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
@@ -1705,12 +2362,6 @@ dependencies = [
"windows_x86_64_msvc 0.52.5",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
@@ -1723,12 +2374,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
@@ -1741,12 +2386,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
@@ -1765,12 +2404,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
@@ -1783,12 +2416,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
@@ -1801,12 +2428,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
@@ -1819,12 +2440,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
@@ -1837,6 +2452,21 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "xml-rs"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193"
[[package]]
name = "xmltree"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb"
dependencies = [
"xml-rs",
]
[[package]]
name = "yasna"
version = "0.5.2"
@@ -1851,3 +2481,31 @@ name = "zeroize"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
[[package]]
name = "zstd"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.10+zstd.1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
dependencies = [
"cc",
"pkg-config",
]
+2 -2
View File
@@ -1,11 +1,11 @@
[workspace]
members = ["vnt","common","vnt-cli","vnt-jni"]
members = ["vnt", "common", "vnt-cli", "vn-link", "vn-link-cli"]
[profile.release]
opt-level = 'z'
debug = 0
debug-assertions = false
strip= "debuginfo"
strip = "debuginfo"
lto = true
panic = 'abort'
incremental = false
+14
View File
@@ -0,0 +1,14 @@
一、程序说明
1. vnt-cli vnt的命令行程序
2. vn-link-cli 功能和vnt-cli基本一致,但是不依赖tun、不改变本地路由、不需要管理员/root权限
二、使用说明
使用-k参数构建虚拟网络
1. Program Description
a. vnt-cli: Command-line program for VNT.
b. vn-link-cli: Functions similarly to vnt-cli, but does not depend on TUN, does not change local routing, and does not require administrator/root permissions.
2. Instructions for Use
Use the -k parameter to create a virtual network.
+47 -18
View File
@@ -4,7 +4,7 @@ A virtual network tool (VPN)
将不同网络下的多个设备虚拟到一个局域网下
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
### vnt-cli参数详解 [参数说明](https://github.com/vnt-dev/vnt/blob/main/vnt-cli/README.md)
### 快速使用:
@@ -39,7 +39,7 @@ A virtual network tool (VPN)
```
4. 最后可以用虚拟ip实现设备间相互访问
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/vnt/dev/documents/img/ssh.jpg">
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/vnt-dev/vnt/main/documents/img/ssh.jpg">
5. 帮助,使用-h命令查看
### 更多玩法
@@ -56,7 +56,7 @@ A virtual network tool (VPN)
- 需要root/管理员权限
- vnt-cli需要使用命令行运行
- Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli)
- 可以自己搭注册和中继服务器([server](https://github.com/lbl8603/vnts))
- 可以自己搭注册和中继服务器([server](https://github.com/vnt-dev/vnts))
- vnt使用stun服务器探测网络NAT类型,默认使用谷歌和腾讯的stun服务器,也可自己搭建(-e参数指定)
### 编译
@@ -73,35 +73,48 @@ cargo build -p vnt-cli --no-default-features
features说明
| feature | 说明 | 是否默认 |
|------------------|----------------------|------|
| openssl | 使用openssl中的aes_ecb算法 | 否 |
| openssl-vendored | 从源码编译openssl | 否 |
| ring-cipher | 使用ring中的aes_gcm算法 | 否 |
| aes_cbc | 支持aes_cbc加密 | 是 |
| aes_ecb | 支持aes_ecb加密 | 是 |
| aes_gcm | 支持aes_gcm加密 | 是 |
| sm4_cbc | 支持sm4_cbc加密 | 是 |
| server_encrypt | 支持服务端加密 | 是 |
| ip_proxy | 内置ip代理 | 是 |
| feature | 说明 | 是否默认 |
|-------------------|--------------------------------|------|
| openssl | 使用openssl中的加密算法 | 否 |
| openssl-vendored | 从源码编译openssl | 否 |
| ring-cipher | 使用ring中的加密算法 | 否 |
| aes_cbc | 支持aes_cbc加密 | 是 |
| aes_ecb | 支持aes_ecb加密 | 是 |
| aes_gcm | 支持aes_gcm加密 | 是 |
| sm4_cbc | 支持sm4_cbc加密 | 是 |
| chacha20_poly1305 | 支持chacha20和chacha20_poly1305加密 | 是 |
| server_encrypt | 支持服务端加密 | 是 |
| ip_proxy | 内置ip代理 | 是 |
| port_mapping | 端口映射 | 是 |
| log | 日志 | 是 |
| command | list、route等命令 | 是 |
| file_config | yaml配置文件 | 是 |
| lz4 | lz4压缩 | 是 |
| zstd | zstd压缩 | 否 |
### ip转发/代理
如果编译时去除了内置的ip代理(或使用--no-proxy关闭了代理),则可以使用网卡NAT转发来实现点对网,
一般来说使用网卡NAT转发会比内置的ip代理性能更好
<details> <summary>NAT配置可参考如下示例,点击展开</summary>
### 在出口一端做如下配置
注意原有的-i(入口)和-o(出口)的参数不能少
### windows
参考 https://learn.microsoft.com/zh-cn/virtualization/hyper-v-on-windows/user-guide/setup-nat-network
```shell
#设置nat,名字可以自己取,网段是vnt的网段
New-NetNat -Name vntnat -InternalIPInterfaceAddressPrefix 10.26.0.0/24
#查看设置
Get-NetNat
```
### linux
```shell
# 开启ip转发
sudo sysctl -w net.ipv4.ip_forward=1
@@ -144,6 +157,7 @@ sudo iptables-restore iptables.rules
```
### macos
```shell
# 开启ip转发
sudo sysctl -w net.ipv4.ip_forward=1
@@ -153,18 +167,21 @@ nat on en0 from 10.26.0.0/24 to any -> (en0)
# 加载规则
sudo pfctl -f /etc/pf.conf -e
```
</details>
### 支持平台
- Mac
- Linux
- Arch Linux `yay -Syu vnt`
- Windows
- 默认使用tun网卡 依赖wintun.dll([win-tun](https://www.wintun.net/))(将dll放到同目录下,建议使用版本0.14.1)
- 使用tap网卡 依赖tap-windows([win-tap](https://build.openvpn.net/downloads/releases/))(建议使用版本9.24.7)
- Android
- [VntApp](https://github.com/lbl8603/VntApp)
### GUI
支持安卓和Windows [下载](https://github.com/vnt-dev/VntApp/releases/)
### 特性
@@ -255,24 +272,36 @@ vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
2. 如果p2p后效果很差,可以选择禁用p2pvnt-cli增加--use-channel relay 参数)
#### 问题4:重启后虚拟IP发生变化,或指定了IP不能启动
##### 可能原因:
设备重启后程序自动获取的id值改变,导致注册时重新分配了新的IP,或是IP冲突
##### 解决方法:
1. 命令行启动增加-d参数(使用配置文件启动则在配置文件中增加device_id参数),要保证每个设备的值都不一样,取值可以任意64位以内字符串
</details>
### 交流群
对VNT有任何问题均可以加群联系作者
QQ: 1034868233
### 赞助
如果VNT对你有帮助,欢迎打赏作者
<img width="300" alt="" src="https://github.com/vnt-dev/vnt/assets/49143209/0d3a7311-43fc-4ed7-9507-863b5d69b6b2">
### 其他
可使用社区小伙伴搭建的中继服务器
1. -s vnt.8443.eu.org:29871
2. -s vnt.wherewego.top:29872
### 参与贡献
<a href="https://github.com/lbl8603/vnt/graphs/contributors">
<img src="https://contrib.rocks/image?repo=lbl8603/vnt" />
<a href="https://github.com/vnt-dev/vnt/graphs/contributors">
<img src="https://contrib.rocks/image?repo=vnt-dev/vnt" />
</a>
+39 -1
View File
@@ -1,8 +1,46 @@
[package]
name = "common"
version = "1.2.9"
version = "1.2.12"
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 }
anyhow = "1.0.82"
console = "0.15.2"
log = "0.4.17"
log4rs = { version = "1.3.0", optional = true }
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9.32"
getopts = "0.2.21"
gethostname = "0.4.3"
uuid = { version = "1.8.0", features = ["v4"] }
sys-locale = "0.3.1"
[features]
default = []
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"]
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
server_encrypt = ["vnt/server_encrypt"]
ip_proxy = ["vnt/ip_proxy"]
port_mapping = ["vnt/port_mapping"]
lz4 = ["vnt/lz4_compress"]
zstd = ["vnt/zstd_compress"]
upnp = ["vnt/upnp"]
ws = ["vnt/ws"]
wss = ["vnt/wss"]
command = []
file_config = []
log = ["log4rs"]
integrated_tun = ["vnt/integrated_tun"]
[build-dependencies]
rand = "0.8.5"
chrono = "0.4.23"
+9 -9
View File
@@ -7,33 +7,33 @@ pub fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, String>
let net = if let Some(net) = split.next() {
net
} else {
return Err("ipv4/mask,ipv4".to_string());
return Err(format!("ipv4/mask,ipv4 {:?}", x));
};
let ip = if let Some(ip) = split.next() {
ip
} else {
return Err("ipv4/mask,ipv4".to_string());
return Err(format!("ipv4/mask,ipv4 {:?}", x));
};
let ip = if let Ok(ip) = ip.parse::<Ipv4Addr>() {
ip
} else {
return Err("not ipv4".to_string());
return Err(format!("not ipv4 {:?}", ip));
};
let mut split = net.split("/");
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err("no ipv4/mask".to_string());
return Err(format!("no ipv4/mask {:?}", net));
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err("no netmask".to_string());
return Err(format!("no netmask {:?}", net));
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err("not ipv4".to_string());
return Err(format!("not ipv4 {:?}", dest));
};
let mask = to_ip(mask)?;
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
@@ -48,17 +48,17 @@ pub fn out_ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32)>, String> {
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err("no ipv4/mask".to_string());
return Err(format!("no ipv4/mask {:?}", x));
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err("no netmask".to_string());
return Err(format!("no netmask {:?}", x));
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err("not ipv4".to_string());
return Err(format!("not ipv4 {:?}", dest));
};
let mask = to_ip(mask)?;
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask));
@@ -1,9 +1,7 @@
use std::process;
use console::style;
use vnt::handle::callback::{ConnectInfo, ErrorType};
use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
use vnt::{ConnectInfo, ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo, VntCallback};
#[derive(Clone)]
pub struct VntHandler {}
@@ -12,7 +10,8 @@ impl VntCallback for VntHandler {
fn success(&self) {
println!(" {} ", style("====== Connect Successfully ======").green())
}
fn create_tun(&self, info: DeviceInfo) {
#[cfg(feature = "vnt-model")]
fn create_tun(&self, info: vnt::DeviceInfo) {
println!("create_tun {}", info)
}
+619
View File
@@ -0,0 +1,619 @@
use crate::args_parse::{ips_parse, out_ips_parse};
#[cfg(feature = "command")]
use crate::command;
use crate::{config, generated_serial_number};
use anyhow::anyhow;
use console::style;
use getopts::Options;
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::str::FromStr;
use sys_locale::get_locale;
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::compression::Compressor;
use vnt::core::Config;
pub fn app_home() -> io::Result<PathBuf> {
let root_path = match std::env::current_exe() {
Ok(path) => {
if let Some(v) = path.as_path().parent() {
v.to_path_buf()
} else {
log::warn!("current_exe parent none:{:?}", path);
PathBuf::new()
}
}
Err(e) => {
log::warn!("current_exe err:{:?}", e);
PathBuf::new()
}
};
let path = root_path.join("env");
if !path.exists() {
std::fs::create_dir_all(&path)?;
}
Ok(path)
}
pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>> {
#[cfg(feature = "log")]
let _ = log4rs::init_file("log4rs.yaml", Default::default());
let args: Vec<String> = std::env::args().collect();
let program = args[0].clone();
let mut opts = Options::new();
opts.optopt("k", "", "组网标识", "<token>");
opts.optopt("n", "", "设备名称", "<name>");
opts.optopt("d", "", "设备标识", "<id>");
opts.optflag("c", "", "关闭交互式命令");
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
opts.optmulti("e", "", "stun服务器", "<stun-server>");
opts.optflag("a", "", "使用tap模式");
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
opts.optopt("w", "", "客户端加密", "<password>");
opts.optflag("W", "", "服务端加密");
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
opts.optflag("", "relay", "仅使用服务器转发");
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
opts.optopt("", "model", "加密模式", "<model>");
opts.optflag("", "finger", "指纹校验");
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
opts.optopt("", "ports", "监听的端口", "<port,port>");
opts.optflag("", "cmd", "开启窗口输入");
opts.optflag("", "no-proxy", "关闭内置代理");
opts.optflag("", "first-latency", "优先延迟");
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
opts.optmulti("", "dns", "dns", "<dns>");
opts.optmulti("", "mapping", "mapping", "<mapping>");
opts.optmulti("", "vnt-mapping", "vnt-mapping", "<mapping>");
opts.optopt("f", "", "配置文件", "<conf>");
opts.optopt("", "compressor", "压缩算法", "<lz4>");
opts.optflag("", "disable-stats", "关闭流量统计");
opts.optflag("", "allow-wg", "允许接入WireGuard");
//"后台运行时,查看其他设备列表"
opts.optflag("", "add", "后台运行时,添加地址");
opts.optflag("", "list", "后台运行时,查看其他设备列表");
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
opts.optflag("", "info", "后台运行时,查看当前设备信息");
opts.optflag("", "route", "后台运行时,查看数据转发路径");
opts.optflag("", "chart_a", "后台运行时,查看流量统计");
opts.optopt("", "chart_b", "后台运行时,查看流量统计", "<IP>");
opts.optflag("", "stop", "停止后台运行");
opts.optflag("h", "help", "帮助");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
print_usage(&program, opts);
return Err(anyhow::anyhow!("{}", f.to_string()));
}
};
if matches.opt_present("h") || args.len() == 1 {
print_usage(&program, opts);
return Ok(None);
}
#[cfg(feature = "command")]
if matches.opt_present("list") {
command::command(command::CommandEnum::List);
return Ok(None);
} else if matches.opt_present("info") {
command::command(command::CommandEnum::Info);
return Ok(None);
} else if matches.opt_present("stop") {
command::command(command::CommandEnum::Stop);
return Ok(None);
} else if matches.opt_present("route") {
command::command(command::CommandEnum::Route);
return Ok(None);
} else if matches.opt_present("all") {
command::command(command::CommandEnum::All);
return Ok(None);
}
#[cfg(feature = "command")]
if matches.opt_present("chart_a") {
command::command(command::CommandEnum::ChartA);
return Ok(None);
}
#[cfg(feature = "command")]
if let Some(v) = matches.opt_str("chart_b") {
command::command(command::CommandEnum::ChartB(v));
return Ok(None);
}
let conf = matches.opt_str("f");
let (config, vnt_link_config, cmd) = if conf.is_some() {
match config::read_config(&conf.unwrap()) {
Ok(c) => c,
Err(e) => {
return Err(anyhow::anyhow!("conf err {}", e));
}
}
} else {
if !matches.opt_present("k") {
print_usage(&program, opts);
return Err(anyhow::anyhow!("parameter -k not found ."));
}
#[cfg(target_os = "windows")]
#[cfg(feature = "integrated_tun")]
let tap = matches.opt_present("a");
#[cfg(feature = "integrated_tun")]
let device_name = matches.opt_str("nic");
let token: String = matches.opt_get("k").unwrap().unwrap();
let device_id = matches.opt_get_default("d", String::new()).unwrap();
let device_id = if device_id.is_empty() {
config::get_device_id()
} else {
device_id
};
if device_id.is_empty() {
print_usage(&program, opts);
return Err(anyhow::anyhow!("parameter -d not found ."));
}
let name = matches
.opt_get_default(
"n",
gethostname::gethostname()
.to_str()
.unwrap_or("UnknownName")
.to_string(),
)
.unwrap();
let server_address_str = matches
.opt_get_default("s", "vnt.wherewego.top:29872".to_string())
.unwrap();
let mut stun_server = matches.opt_strs("e");
if stun_server.is_empty() {
for x in config::PUB_STUN {
stun_server.push(x.to_string());
}
}
let dns = matches.opt_strs("dns");
let in_ip = matches.opt_strs("i");
let in_ip = match ips_parse(&in_ip) {
Ok(in_ip) => in_ip,
Err(e) => {
print_usage(&program, opts);
println!();
println!("-i: {:?} {}", in_ip, e);
return Err(anyhow::anyhow!("example: -i 192.168.0.0/24,10.26.0.3"));
}
};
let out_ip = matches.opt_strs("o");
let out_ip = match out_ips_parse(&out_ip) {
Ok(out_ip) => out_ip,
Err(e) => {
print_usage(&program, opts);
println!();
println!("-o: {:?} {}", out_ip, e);
return Err(anyhow::anyhow!("example: -o 0.0.0.0/0"));
}
};
let password: Option<String> = matches.opt_get("w").unwrap();
let server_encrypt = matches.opt_present("W");
#[cfg(not(feature = "server_encrypt"))]
{
if server_encrypt {
println!("Server encryption not supported");
return Err(anyhow::anyhow!("Server encryption not supported"));
}
}
let mtu: Option<String> = matches.opt_get("u").unwrap();
let mtu = if let Some(mtu) = mtu {
match u32::from_str(&mtu) {
Ok(mtu) => Some(mtu),
Err(e) => {
print_usage(&program, opts);
println!();
println!("'-u {}' {}", mtu, e);
return Err(anyhow::anyhow!("'-u {}' {}", mtu, e));
}
}
} else {
None
};
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
let virtual_ip =
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
if let Some(virtual_ip) = virtual_ip {
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
{
return Err(anyhow::anyhow!("'--ip {}' invalid", virtual_ip));
}
}
let relay = matches.opt_present("relay");
let cipher_model = match matches.opt_get::<CipherModel>("model") {
Ok(model) => {
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
{
if password.is_some() && model.is_none() {
return Err(anyhow::anyhow!("'--model ' undefined"));
}
model.unwrap_or(CipherModel::None)
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
model.unwrap_or(CipherModel::AesGcm)
}
Err(e) => {
return Err(anyhow::anyhow!("'--model ' invalid,{}", e));
}
};
let finger = matches.opt_present("finger");
let punch_model = matches
.opt_get::<PunchModel>("punch")
.unwrap()
.unwrap_or(PunchModel::All);
let use_channel_type = matches
.opt_get::<UseChannelType>("use-channel")
.unwrap()
.unwrap_or_else(|| {
if relay {
UseChannelType::Relay
} else {
UseChannelType::All
}
});
let ports = matches
.opt_get::<String>("ports")
.unwrap_or(None)
.map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect());
let cmd = matches.opt_present("cmd");
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
let no_proxy = matches.opt_present("no-proxy");
let first_latency = matches.opt_present("first-latency");
let packet_loss = matches
.opt_get::<f64>("packet-loss")
.expect("--packet-loss");
let packet_delay = matches
.opt_get::<u32>("packet-delay")
.expect("--packet-delay")
.unwrap_or(0);
#[cfg(feature = "port_mapping")]
let port_mapping_list = matches.opt_strs("mapping");
let vnt_mapping_list = matches.opt_strs("vnt-mapping");
let disable_stats = matches.opt_present("disable-stats");
let allow_wire_guard = matches.opt_present("allow-wg");
let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() {
Compressor::from_str(compressor)
.map_err(|e| anyhow!("{}", e))
.unwrap()
} else {
Compressor::None
};
let config = match Config::new(
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap,
token,
device_id,
name,
server_address_str,
dns,
stun_server,
in_ip,
out_ip,
password,
mtu,
virtual_ip,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
no_proxy,
server_encrypt,
cipher_model,
finger,
punch_model,
ports,
first_latency,
#[cfg(feature = "integrated_tun")]
device_name,
use_channel_type,
packet_loss,
packet_delay,
#[cfg(feature = "port_mapping")]
port_mapping_list,
compressor,
!disable_stats,
allow_wire_guard,
) {
Ok(config) => config,
Err(e) => {
println!("config error: {}", e);
std::process::exit(1);
}
};
(config, vnt_mapping_list, cmd)
};
println!("version {}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
log::info!(
"version:{},Serial:{}",
vnt::VNT_VERSION,
generated_serial_number::SERIAL_NUMBER
);
Ok(Some((config, vnt_link_config, cmd)))
}
fn get_description(key: &str, language: &str) -> String {
// 设置一个全局的映射来存储中英文对照
let descriptions: HashMap<&str, (&str, &str)> = [
("-k <token>", ("使用相同的token,就能组建一个局域网络", "Use the same token to form a local network")),
("-n <name>", ("给设备一个名字,便于区分不同设备,默认使用系统版本", "Give the device a name to distinguish it, defaults to system version")),
("-d <id>", ("设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复", "Device unique identifier, used by the server to allocate virtual IP when --ip parameter is not used, must be unique")),
("-s <server>", ("注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://", "Registration and relay server address, protocols support using tcp://, ws://, and wss://, default is udp://")),
("-e <stun-server>", ("stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com", "STUN server for detecting NAT type, can specify multiple addresses, e.g., -e stun.miwifi.com -e turn.cloudflare.com")),
("-a", ("使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡", "Use tap mode, default is tun mode, specify '--nic' parameter with tap network card")),
("-i <in-ip>", ("配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3,可指定多个网段", "Used when configuring point-to-point network (IP proxy), -i 192.168.0.0/24,10.26.0.3 allows receiving data from subnet 192.168.0.0/24 and forwarding to 10.26.0.3, specify multiple subnets")),
("-o <out-ip>", ("配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段", "Used when configuring point-to-point network, -o 192.168.0.0/24 allows forwarding data to 192.168.0.0/24, specify multiple subnets")),
("-w <password>", ("使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "Encrypt client data with keys generated by this password, server cannot decrypt, clients must use the same password to communicate")),
("-W", ("加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确", "Encrypt the data currently being communicated between the client and server, please pay attention to whether the server fingerprint is correct")),
("-u <mtu>", ("自定义mtu(不加密默认为1450,加密默认为1410", "Customize MTU (1450 by default without encryption, 1410 with encryption)")),
("-f <conf_file>", ("读取配置文件中的配置", "Read configuration from file")),
("--ip <ip>", ("指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配", "Specify virtual IP, must be unique and valid within server subnet, by default allocated by server")),
("--model <model>", ("加密模式(默认aes_gcm),可选值{}", "Encryption mode (default aes_gcm), options {}")),
("--finger", ("增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启", "Add data fingerprint verification for increased security, client must enable if server does")),
("--punch <punch>", ("取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞", "Values ipv4/ipv6/all, ipv4 for IPv4 hole punching only")),
("--ports <port,port>", ("取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担", "Values 0~65535, specify a group of local listening ports, defaults to two random ports, using many ports increases network load")),
("--cmd", ("开启交互式命令,使用此参数开启控制台输入", "Enable interactive command mode, use this parameter to enable console input")),
("--no-proxy", ("关闭内置代理,如需点对网则需要配置网卡NAT转发", "Disable built-in proxy, configure network card NAT forwarding for point-to-point networking")),
("--first-latency", ("优先低延迟的通道,默认情况优先使用p2p通道", "Prioritize low-latency channels, defaults to prioritizing p2p channel")),
("--use-channel <p2p>", ("使用通道 relay/p2p/all,默认两者都使用", "Use channel relay/p2p/all, defaults to using both")),
("--nic <tun0>", ("指定虚拟网卡名称", "Specify virtual network card name")),
("--packet-loss <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate packet loss, value between 0 and 1, program actively drops packets based on set probability, useful for simulating weak networks")),
("--packet-delay <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate latency, integer, in milliseconds (ms). The program will delay sending packets according to the set value and can be used to simulate weak networks")),
("--dns <host:port>", ("DNS服务器地址,可使用多个dns,不指定时使用系统解析", "DNS server address, can specify multiple DNS servers, defaults to system resolution if not specified")),
("--mapping <mapping>", ("端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备", "Port mapping, e.g., --mapping udp:0.0.0.0:80-domain:80 maps to a device accessible by local routing")),
("--compressor-all <lz4>", ("启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10", "Enable compression, options lz4/zstd<,level>, level is compression level, e.g., --compressor lz4 or --compressor zstd,10")),
("--compressor-lz4 <lz4>", ("启用压缩,可选值lz4,例如 --compressor lz4", "Enable compression, option lz4, e.g., --compressor lz4")),
("--compressor-zstd <zstd>", ("启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10", "Enable compression, options zstd<,level>, level is compression level, e.g., --compressor zstd,10")),
("--vnt-mapping <x>", ("vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备", "VNT address mapping, e.g., --vnt-mapping tcp:80-10.26.0.10:80 maps to a device in VNT network or its subnet")),
("--disable-stats", ("关闭流量统计", "Disable traffic statistics")),
("--list", ("后台运行时,查看其他设备列表", "View list of other devices when running in background")),
("--all", ("后台运行时,查看其他设备完整信息", "View complete information of other devices when running in background")),
("--info", ("后台运行时,查看当前设备信息", "View information of current device when running in background")),
("--route", ("后台运行时,查看数据转发路径", "View data forwarding path when running in background")),
("--chart_a", ("后台运行时,查看所有IP的流量统计", "View traffic statistics of all IPs when running in background")),
("--chart_b <IP>", ("后台运行时,查看单个IP的历史流量", "View historical traffic of a single IP when running in background")),
("--stop", ("停止后台运行", "Stop running in background"))
// ... 其他选项
]
.iter()
.cloned()
.collect();
if let Some(&(zh, en)) = descriptions.get(key) {
if language.starts_with("zh") {
return zh.to_string(); // 返回 String 类型
}
// 默认返回英文
return en.to_string(); // 返回 String 类型
}
// 如果没有找到对应的键,则返回空字符串
String::new()
}
fn print_usage(program: &str, _opts: Options) {
// 获取系统语言 Locale::user_default().unwrap_or_else(|_| Locale::default());
let language = get_locale().unwrap_or_else(|| String::from("en-US"));
println!("Usage: {} [options]", program);
println!("version:{}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
println!("Options:");
println!(
" -k <token> {}",
green(get_description("-k <token>", &language).to_string())
);
println!(
" -n <name> {}",
get_description("-n <name>", &language)
);
println!(
" -d <id> {}",
get_description("-d <id>", &language)
);
println!(
" -s <server> {}",
get_description("-s <server>", &language)
);
println!(
" -e <stun-server> {}",
get_description("-e <stun-server>", &language)
);
#[cfg(target_os = "windows")]
#[cfg(feature = "integrated_tun")]
println!(" -a {}", get_description("-a", &language));
println!(
" -i <in-ip> {}",
get_description("-i <in-ip>", &language)
);
println!(
" -o <out-ip> {}",
get_description("-o <out-ip>", &language)
);
println!(
" -w <password> {}",
get_description("-w <password>", &language)
);
#[cfg(feature = "server_encrypt")]
println!(" -W {}", get_description("-W", &language));
println!(
" -u <mtu> {}",
get_description("-u <mtu>", &language)
);
#[cfg(feature = "file_config")]
println!(
" -f <conf_file> {}",
get_description("-f <conf_file>", &language)
);
println!(
" --ip <ip> {}",
get_description("--ip <ip>", &language)
);
let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[cfg(feature = "chacha20_poly1305")]
enums.push_str("/chacha20_poly1305/chacha20");
#[cfg(feature = "aes_cbc")]
enums.push_str("/aes_cbc");
#[cfg(feature = "aes_ecb")]
enums.push_str("/aes_ecb");
#[cfg(feature = "sm4_cbc")]
enums.push_str("/sm4_cbc");
enums.push_str("/xor");
println!(
" --model <model> {}{}",
get_description("--model <model>", &language),
&enums[1..]
);
#[cfg(any(
feature = "aes_gcm",
feature = "chacha20_poly1305",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
println!(
" --finger {}",
get_description("--finger", &language)
);
println!(
" --punch <punch> {}",
get_description("--punch <punch>", &language)
);
println!(
" --ports <port,port> {}",
get_description("--ports <port,port>", &language)
);
#[cfg(feature = "command")]
println!(
" --cmd {}",
get_description("--cmd", &language)
);
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
println!(
" --no-proxy {}",
get_description("--no-proxy", &language)
);
println!(
" --first-latency {}",
get_description("--first-latency", &language)
);
println!(
" --use-channel <p2p> {}",
get_description("--use-channel <p2p>", &language)
);
#[cfg(not(feature = "vn-link-model"))]
println!(
" --nic <tun0> {}",
get_description("--nic <tun0>", &language)
);
println!(
" --packet-loss <0> {}",
get_description("--packet-loss <0>", &language)
);
println!(
" --packet-delay <0> {}",
get_description("--packet-delay <0>", &language)
);
println!(
" --dns <host:port> {}",
get_description("--dns <host:port>", &language)
);
#[cfg(feature = "port_mapping")]
println!(
" --mapping <mapping> {}",
get_description("--mapping <mapping>", &language)
);
#[cfg(all(feature = "lz4", feature = "zstd"))]
println!(
" --compressor <lz4> {}",
get_description("--compressor-all <lz4>", &language)
);
#[cfg(feature = "lz4")]
#[cfg(not(feature = "zstd"))]
println!(
" --compressor <lz4> {}",
get_description("--compressor-lz4 <lz4>", &language)
);
#[cfg(feature = "zstd")]
#[cfg(not(feature = "lz4"))]
println!(
" --compressor <zstd> {}",
get_description("--compressor-zstd <zstd>", &language)
);
#[cfg(not(feature = "integrated_tun"))]
println!(
" --vnt-mapping <x> {}",
green(get_description("--vnt-mapping <x>", &language).to_string())
);
println!(
" --disable-stats {}",
get_description("--disable-stats", &language)
);
println!(" --allow-wg 允许接入WireGuard客户端");
println!();
#[cfg(feature = "command")]
{
// #[cfg(not(feature = "integrated_tun"))]
// println!(
// " --add {}",
// yellow("后台运行时,添加VNT地址映射 用法同'--vnt-mapping'".to_string())
// );
println!(
" --list {}",
yellow(get_description("--list", &language).to_string())
);
println!(
" --all {}",
yellow(get_description("--all", &language).to_string())
);
println!(
" --info {}",
yellow(get_description("--info", &language).to_string())
);
println!(
" --route {}",
yellow(get_description("--route", &language).to_string())
);
println!(
" --chart_a {}",
yellow(get_description("--chart_a", &language).to_string())
);
println!(
" --chart_b <IP> {}",
yellow(get_description("--chart_b <IP>", &language).to_string())
);
println!(
" --stop {}",
yellow(get_description("--stop", &language).to_string())
);
}
println!(" -h, --help display help information(显示帮助信息)");
}
fn green(str: String) -> impl std::fmt::Display {
style(str).green()
}
#[cfg(feature = "command")]
fn yellow(str: String) -> impl std::fmt::Display {
style(str).yellow()
}
@@ -4,10 +4,10 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::str::FromStr;
use std::time::Duration;
use crate::command::entity::{DeviceItem, Info, RouteItem};
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
pub struct CommandClient {
buf: [u8; 10240],
buf: Vec<u8>,
udp: UdpSocket,
}
@@ -25,12 +25,12 @@ impl CommandClient {
)))?;
Ok(Self {
udp,
buf: [0; 10240],
buf: vec![0; 65536 * 8],
})
}
}
fn read_command_port() -> io::Result<u16> {
let path_buf = crate::app_home()?.join("command-port");
let path_buf = crate::cli::app_home()?.join("command-port");
let port = std::fs::read_to_string(path_buf)?;
match u16::from_str(&port) {
Ok(port) => Ok(port),
@@ -53,14 +53,33 @@ impl CommandClient {
pub fn info(&mut self) -> io::Result<Info> {
self.send_cmd(b"info")
}
pub fn chart_a(&mut self) -> io::Result<ChartA> {
self.send_cmd(b"chart_a")
}
pub fn chart_b(&mut self, input: &str) -> io::Result<ChartB> {
let cmd = if input.is_empty() {
"chart_b".to_string()
} else {
format!("chart_b:{}", input)
};
self.send_cmd(cmd.as_bytes())
}
fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result<V> {
self.udp.send(cmd)?;
let len = self.udp.recv(&mut self.buf)?;
match serde_yaml::from_slice::<V>(&self.buf[..len]) {
Ok(val) => Ok(val),
Err(e) => {
log::error!("{:?},{:?}", &self.buf[..len], e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
log::error!(
"send_cmd {:?} {:?},{:?}",
std::str::from_utf8(cmd),
std::str::from_utf8(&self.buf[..len]),
e
);
Err(io::Error::new(
io::ErrorKind::Other,
format!("data error {:?} buf_len={}", e, len),
))
}
}
}
@@ -1,4 +1,7 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::{Ipv4Addr, SocketAddr};
#[derive(Serialize, Deserialize, Debug)]
pub struct Info {
pub name: String,
@@ -11,8 +14,11 @@ pub struct Info {
pub public_ips: String,
pub local_addr: String,
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)>,
pub udp_listen_addr: Vec<String>,
pub tcp_listen_addr: String,
}
#[derive(Serialize, Deserialize, Debug)]
@@ -39,4 +45,24 @@ pub struct DeviceItem {
pub client_secret_hash: Vec<u8>,
pub current_client_secret: bool,
pub current_client_secret_hash: Vec<u8>,
pub wire_guard: bool,
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct ChartA {
pub disable_stats: bool,
pub up_total: u64,
pub down_total: u64,
pub up_map: HashMap<Ipv4Addr, u64>,
pub down_map: HashMap<Ipv4Addr, u64>,
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct ChartB {
pub disable_stats: bool,
pub ip: Option<Ipv4Addr>,
pub up_total: u64,
pub up_list: Vec<usize>,
pub down_total: u64,
pub down_list: Vec<usize>,
}
@@ -1,7 +1,10 @@
use std::collections::HashSet;
use std::io;
use std::net::Ipv4Addr;
use vnt::channel::ConnectProtocol;
use vnt::core::Vnt;
use crate::command::entity::{DeviceItem, Info, RouteItem};
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
use crate::console_out;
pub mod client;
@@ -13,9 +16,56 @@ pub enum CommandEnum {
List,
All,
Info,
ChartA,
ChartB(String),
Stop,
}
pub fn command_str(cmd: &str, vnt: &Vnt) -> bool {
if cmd.is_empty() {
return false;
}
let cmd = cmd.to_lowercase();
let cmd = cmd.trim();
match cmd {
"list" => {
let list = command_list(&vnt);
console_out::console_device_list(list);
}
"info" => {
let info = command_info(&vnt);
console_out::console_info(info);
}
"route" => {
let route = command_route(&vnt);
console_out::console_route_table(route);
}
"all" => {
let list = command_list(&vnt);
console_out::console_device_list_all(list);
}
"chart_a" => {
let chart = command_chart_a(&vnt);
console_out::console_chart_a(chart);
}
"stop" => {
let _ = vnt.stop();
return false;
}
_ => {}
}
if let Some(ip) = cmd.strip_prefix("chart_b") {
let chart = if ip.is_empty() {
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
} else {
command_chart_b(&vnt, &ip[1..])
};
console_out::console_chart_b(chart);
}
println!();
return true;
}
pub fn command(cmd: CommandEnum) {
if let Err(e) = command_(cmd) {
println!("cmd: {:?}", e);
@@ -41,6 +91,14 @@ fn command_(cmd: CommandEnum) -> io::Result<()> {
let info = command_client.info()?;
console_out::console_info(info);
}
CommandEnum::ChartA => {
let chart = command_client.chart_a()?;
console_out::console_chart_a(chart);
}
CommandEnum::ChartB(input) => {
let chart = command_client.chart_b(&input)?;
console_out::console_chart_b(chart);
}
CommandEnum::Stop => {
command_client.stop()?;
}
@@ -50,6 +108,7 @@ fn command_(cmd: CommandEnum) -> io::Result<()> {
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
let route_table = vnt.route_table();
let server_addr = vnt.config().server_address_str.clone();
let mut route_list = Vec::with_capacity(route_table.len());
for (destination, routes) in route_table {
for route in routes {
@@ -62,11 +121,14 @@ pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
} else {
route.rt.to_string()
};
let interface = if route.is_tcp {
format!("tcp@{}", route.addr)
} else {
route.addr.to_string()
let interface = match route.protocol {
ConnectProtocol::UDP => route.addr.to_string(),
ConnectProtocol::TCP => {
format!("tcp@{}", route.addr)
}
ConnectProtocol::WS | ConnectProtocol::WSS => server_addr.clone(),
};
let item = RouteItem {
destination: destination.to_string(),
next_hop,
@@ -114,7 +176,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
};
let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) {
let nat_traversal_type = if route.metric == 1 {
if route.is_tcp {
if route.protocol.is_base_tcp() {
"tcp-p2p"
} else {
"p2p"
@@ -157,6 +219,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
client_secret_hash: peer.client_secret_hash,
current_client_secret,
current_client_secret_hash: client_encrypt_hash.to_vec(),
wire_guard: peer.wireguard,
};
list.push(item);
}
@@ -164,6 +227,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
}
pub fn command_info(vnt: &Vnt) -> Info {
let config = vnt.config();
let current_device = vnt.current_device();
let nat_info = vnt.nat_info();
let name = vnt.name().to_string();
@@ -171,7 +235,11 @@ pub fn command_info(vnt: &Vnt) -> Info {
let virtual_gateway = current_device.virtual_gateway().to_string();
let virtual_netmask = current_device.virtual_netmask.to_string();
let connect_status = format!("{:?}", vnt.connection_status());
let relay_server = current_device.connect_server.to_string();
let relay_server = if current_device.connect_server.port() == 0 {
config.server_address_str.clone()
} else {
current_device.connect_server.to_string()
};
let nat_type = format!("{:?}", nat_info.nat_type);
let public_ips: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
let public_ips = public_ips.join(",");
@@ -183,8 +251,18 @@ pub fn command_info(vnt: &Vnt) -> Info {
.ipv6()
.map(|v| v.to_string())
.unwrap_or("None".to_string());
let up = vnt.up_stream();
let down = vnt.down_stream();
#[cfg(feature = "port_mapping")]
let port_mapping_list = vnt.config().port_mapping_list.clone();
#[cfg(not(feature = "port_mapping"))]
let port_mapping_list = vec![];
let in_ips = vnt.config().in_ips.clone();
let out_ips = vnt.config().out_ips.clone();
let udp_listen_addr = nat_info
.udp_ports
.iter()
.map(|port| format!("0.0.0.0:{}", port))
.collect();
let tcp_listen_addr = format!("0.0.0.0:{}", nat_info.tcp_port);
Info {
name,
virtual_ip,
@@ -196,7 +274,80 @@ pub fn command_info(vnt: &Vnt) -> Info {
public_ips,
local_addr,
ipv6_addr,
up,
down,
port_mapping_list,
in_ips,
out_ips,
udp_listen_addr,
tcp_listen_addr,
}
}
pub fn command_chart_a(vnt: &Vnt) -> ChartA {
let disable_stats = !vnt.config().enable_traffic;
if disable_stats {
let mut chart = ChartA::default();
chart.disable_stats = true;
return chart;
}
let (up_total, up_map) = vnt.up_stream_all().unwrap_or_default();
let (down_total, down_map) = vnt.down_stream_all().unwrap_or_default();
ChartA {
disable_stats,
up_total,
down_total,
up_map,
down_map,
}
}
pub fn command_chart_b(vnt: &Vnt, input_str: &str) -> ChartB {
let disable_stats = !vnt.config().enable_traffic;
if disable_stats {
let mut chart = ChartB::default();
chart.disable_stats = true;
return chart;
}
let (_, up_map) = vnt.up_stream_history().unwrap_or_default();
let (_, down_map) = vnt.down_stream_history().unwrap_or_default();
let up_keys: HashSet<_> = up_map.keys().cloned().collect();
let down_keys: HashSet<_> = down_map.keys().cloned().collect();
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
keys.sort();
if let Some(ip) = find_matching_ipv4_address(input_str, &keys) {
let (up_total, up_list) = up_map.get(&ip).cloned().unwrap_or_default();
let (down_total, down_list) = down_map.get(&ip).cloned().unwrap_or_default();
ChartB {
disable_stats,
ip: Some(ip),
up_total,
up_list,
down_total,
down_list,
}
} else {
ChartB::default()
}
}
fn match_from_end(input_str: &str, ip: &str) -> bool {
let mut input_chars = input_str.chars().rev();
let mut ip_chars = ip.chars().rev();
while let (Some(ic), Some(pc)) = (input_chars.next(), ip_chars.next()) {
if ic != pc {
return false;
}
}
input_chars.next().is_none() // Ensure all input characters matched
}
fn find_matching_ipv4_address(input_str: &str, ip_addresses: &[Ipv4Addr]) -> Option<Ipv4Addr> {
for &ip in ip_addresses {
let ip_str = ip.to_string();
if match_from_end(input_str, &ip_str) {
return Some(ip);
}
}
None
}
@@ -1,7 +1,7 @@
use crate::command::command_chart_b;
use std::io;
use std::io::Write;
use std::net::UdpSocket;
use vnt::core::Vnt;
pub struct CommandServer {}
@@ -48,7 +48,7 @@ impl CommandServer {
}
}
fn save_port(port: u16) -> io::Result<()> {
let path_buf = crate::app_home()?.join("command-port");
let path_buf = crate::cli::app_home()?.join("command-port");
let mut file = std::fs::File::create(path_buf)?;
file.write_all(port.to_string().as_bytes())?;
file.sync_all()
@@ -63,15 +63,26 @@ fn command(cmd: &str, vnt: &Vnt) -> io::Result<String> {
.unwrap_or_else(|e| format!("error {:?}", e)),
"info" => serde_yaml::to_string(&crate::command::command_info(vnt))
.unwrap_or_else(|e| format!("error {:?}", e)),
"chart_a" => serde_yaml::to_string(&crate::command::command_chart_a(vnt))
.unwrap_or_else(|e| format!("error {:?}", e)),
"stop" => {
vnt.stop();
"stopped".to_string()
}
_ => {
format!(
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
cmd
)
if let Some(ip) = cmd.strip_prefix("chart_b") {
let chart = if ip.is_empty() {
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
} else {
command_chart_b(&vnt, &ip[1..])
};
serde_yaml::to_string(&chart).unwrap_or_else(|e| format!("error {:?}", e))
} else {
format!(
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
cmd
)
}
}
};
Ok(out_str)
@@ -1,18 +1,20 @@
use std::io;
use anyhow::anyhow;
use std::net::Ipv4Addr;
use std::str::FromStr;
use crate::config::get_device_id;
use crate::{args_parse, config};
use serde::{Deserialize, Serialize};
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::compression::Compressor;
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,
@@ -30,8 +32,7 @@ pub struct FileConfig {
#[cfg(feature = "ip_proxy")]
pub no_proxy: bool,
pub server_encrypt: bool,
pub parallel: usize,
pub cipher_model: String,
pub cipher_model: Option<String>,
pub finger: bool,
pub punch_model: String,
pub ports: Option<Vec<u16>>,
@@ -40,22 +41,32 @@ 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>,
pub compressor: Option<String>,
pub vnt_mapping: Vec<String>,
pub disable_stats: bool,
// 允许传递wg流量
pub allow_wire_guard: bool,
}
impl Default for FileConfig {
fn default() -> Self {
let mut stun_server = Vec::new();
for x in config::PUB_STUN {
stun_server.push(x.to_string());
}
Self {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
tap: false,
token: "".to_string(),
device_id: get_device_id(),
name: os_info::get().to_string(),
name: gethostname::gethostname()
.to_str()
.unwrap_or("UnknownName")
.to_string(),
server_address: "nat1.wherewego.top:29872".to_string(),
stun_server: vec![
"stun1.l.google.com:19302".to_string(),
"stun2.l.google.com:19302".to_string(),
"stun.qq.com:3478".to_string(),
],
stun_server,
dns: vec![],
in_ips: vec![],
out_ips: vec![],
@@ -67,8 +78,7 @@ impl Default for FileConfig {
#[cfg(feature = "ip_proxy")]
no_proxy: false,
server_encrypt: false,
parallel: 1,
cipher_model: "aes_gcm".to_string(),
cipher_model: None,
finger: false,
punch_model: "all".to_string(),
ports: None,
@@ -77,60 +87,69 @@ impl Default for FileConfig {
device_name: None,
packet_loss: None,
packet_delay: 0,
#[cfg(feature = "port_mapping")]
mapping: vec![],
compressor: None,
vnt_mapping: vec![],
disable_stats: false,
allow_wire_guard: false,
}
}
}
pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
pub fn read_config(file_path: &str) -> anyhow::Result<(Config, Vec<String>, bool)> {
let conf = std::fs::read_to_string(file_path)?;
let file_conf = match serde_yaml::from_str::<FileConfig>(&conf) {
Ok(val) => val,
Err(e) => {
log::error!("{:?}", e);
return Err(io::Error::new(io::ErrorKind::Other, format!("{}", e)));
return Err(anyhow!("{}", e));
}
};
if file_conf.token.is_empty() {
return Err(io::Error::new(io::ErrorKind::Other, "token is_empty"));
return Err(anyhow!("token is_empty"));
}
let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
let in_ips = match args_parse::ips_parse(&file_conf.in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("in_ips {:?} error:{}", &file_conf.in_ips, e),
));
return Err(anyhow!("in_ips {:?} error:{}", &file_conf.in_ips, e));
}
};
let out_ips = match common::args_parse::out_ips_parse(&file_conf.out_ips) {
let out_ips = match args_parse::out_ips_parse(&file_conf.out_ips) {
Ok(out_ips) => out_ips,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("out_ips {:?} error:{}", &file_conf.out_ips, e),
));
return Err(anyhow!("out_ips {:?} error:{}", &file_conf.out_ips, e));
}
};
let virtual_ip = match file_conf.ip.clone().map(|v| Ipv4Addr::from_str(&v)) {
None => None,
Some(r) => Some(r.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("ip {:?} error:{}", &file_conf.ip, e),
)
})?),
Some(r) => Some(r.map_err(|e| anyhow!("ip {:?} error:{}", &file_conf.ip, e))?),
};
let cipher_model = {
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
if file_conf.password.is_some() && file_conf.cipher_model.is_none() {
Err(anyhow!("cipher_model undefined"))?
} else if let Some(v) = file_conf.cipher_model {
CipherModel::from_str(&v).map_err(|e| anyhow!("{}", e))?
} else {
CipherModel::None
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm
};
let cipher_model = CipherModel::from_str(&file_conf.cipher_model)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let punch_model = PunchModel::from_str(&file_conf.punch_model)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let use_channel_type = UseChannelType::from_str(&file_conf.use_channel)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let punch_model = PunchModel::from_str(&file_conf.punch_model).map_err(|e| anyhow!("{}", e))?;
let use_channel_type =
UseChannelType::from_str(&file_conf.use_channel).map_err(|e| anyhow!("{}", e))?;
let compressor = if let Some(compressor) = file_conf.compressor.as_ref() {
Compressor::from_str(compressor).map_err(|e| anyhow!("{}", e))?
} else {
Compressor::None
};
let config = Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(target_os = "windows")]
#[cfg(feature = "integrated_tun")]
file_conf.tap,
file_conf.token,
file_conf.device_id,
@@ -142,43 +161,27 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
out_ips,
file_conf.password,
file_conf.mtu,
file_conf.tcp,
virtual_ip,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
file_conf.no_proxy,
file_conf.server_encrypt,
file_conf.parallel,
cipher_model,
file_conf.finger,
punch_model,
file_conf.ports,
file_conf.first_latency,
#[cfg(feature = "integrated_tun")]
file_conf.device_name,
use_channel_type,
file_conf.packet_loss,
file_conf.packet_delay,
)
.unwrap();
Ok((config, file_conf.cmd))
}
#[cfg(feature = "port_mapping")]
file_conf.mapping,
compressor,
!file_conf.disable_stats,
file_conf.allow_wire_guard,
)?;
pub fn get_device_id() -> String {
if let Some(id) = common::identifier::get_unique_identifier() {
id
} else {
let path_buf = match crate::app_home() {
Ok(path_buf) => path_buf.join("device-id"),
Err(e) => {
log::warn!("{:?}", e);
return String::new();
}
};
if let Ok(id) = std::fs::read_to_string(path_buf.as_path()) {
id
} else {
let id = uuid::Uuid::new_v4().to_string();
let _ = std::fs::write(path_buf, &id);
id
}
}
Ok((config, file_conf.vnt_mapping, file_conf.cmd))
}
+38
View File
@@ -0,0 +1,38 @@
pub const PUB_STUN: [&'static str; 4] = [
"stun.miwifi.com",
"stun.chat.bilibili.com",
"stun.hitv.com",
"stun.cdnbye.com",
];
#[cfg(feature = "file_config")]
mod file_config;
use crate::identifier;
#[cfg(feature = "file_config")]
pub use file_config::read_config;
#[cfg(not(feature = "file_config"))]
pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, Vec<String>, bool)> {
unimplemented!()
}
pub fn get_device_id() -> String {
if let Some(id) = identifier::get_unique_identifier() {
id
} else {
let path_buf = match crate::cli::app_home() {
Ok(path_buf) => path_buf.join("device-id"),
Err(e) => {
log::warn!("{:?}", e);
return String::new();
}
};
if let Ok(id) = std::fs::read_to_string(path_buf.as_path()) {
id
} else {
let id = uuid::Uuid::new_v4().to_string();
let _ = std::fs::write(path_buf, &id);
id
}
}
}
@@ -1,6 +1,8 @@
use console::{style, Style};
use std::collections::HashSet;
use std::net::Ipv4Addr;
use crate::command::entity::{DeviceItem, Info, RouteItem};
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
pub mod table;
@@ -9,17 +11,57 @@ 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!(
"Udp listen: {}",
style(status.udp_listen_addr.join(", ")).green()
);
println!("Tcp listen: {}", style(status.tcp_listen_addr).green());
println!("Public ips: {}", style(status.public_ips).green());
println!("Local addr: {}", style(status.local_addr).green());
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 {
@@ -90,15 +132,21 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
("Rt".to_string(), Style::new()),
]);
for item in list {
let name = if item.wire_guard {
format!("{}(wg)", item.name)
} else {
item.name
};
if &item.status == "Online" {
if item.client_secret != item.current_client_secret
|| (!item.current_client_secret_hash.is_empty()
&& !item.client_secret_hash.is_empty()
&& item.current_client_secret_hash != item.client_secret_hash)
if !item.wire_guard
&& (item.client_secret != item.current_client_secret
|| (!item.current_client_secret_hash.is_empty()
&& !item.client_secret_hash.is_empty()
&& item.current_client_secret_hash != item.client_secret_hash))
{
//加密状态不一致,无法通信的
out_list.push(vec![
(item.name, Style::new().red()),
(name, Style::new().red()),
(item.virtual_ip, Style::new().red()),
(item.status, Style::new().red()),
("Mismatch".to_string(), Style::new().red()),
@@ -107,7 +155,7 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
} else {
if item.nat_traversal_type.contains("p2p") {
out_list.push(vec![
(item.name, Style::new().green()),
(name, Style::new().green()),
(item.virtual_ip, Style::new().green()),
(item.status, Style::new().green()),
(item.nat_traversal_type, Style::new().green()),
@@ -115,7 +163,7 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
]);
} else {
out_list.push(vec![
(item.name, Style::new().yellow()),
(name, Style::new().yellow()),
(item.virtual_ip, Style::new().yellow()),
(item.status, Style::new().yellow()),
(item.nat_traversal_type, Style::new().yellow()),
@@ -125,7 +173,7 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
}
} else {
out_list.push(vec![
(item.name, Style::new().color256(102)),
(name, Style::new().color256(102)),
(item.virtual_ip, Style::new().color256(102)),
(item.status, Style::new().color256(102)),
("".to_string(), Style::new().color256(102)),
@@ -199,3 +247,120 @@ pub fn console_device_list_all(mut list: Vec<DeviceItem>) {
}
table::println_table(out_list)
}
pub fn console_chart_a(chart_a: ChartA) {
if chart_a.disable_stats {
println!("Traffic statistics not enabled");
return;
}
println!();
println!("-----------------------------------------------------------------");
println!(
"Upload total = {}",
style(convert(chart_a.up_total)).green()
);
println!(
"Download total = {}",
style(convert(chart_a.down_total)).green()
);
println!("-----------------------------------------------------------------");
let up_keys: HashSet<_> = chart_a.up_map.keys().cloned().collect();
let down_keys: HashSet<_> = chart_a.down_map.keys().cloned().collect();
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
// 排序
keys.sort();
// 找到最大的值,用于缩放条形图长度
let up_max_value = *chart_a.up_map.values().max().unwrap_or(&0);
let down_max_value = *chart_a.down_map.values().max().unwrap_or(&0);
let max_value = up_max_value.max(down_max_value);
let max_value = max_value.max(1);
let max_height = 50;
// 打印条形图
for key in &keys {
if let Some(&value) = chart_a.up_map.get(key) {
let bar = "".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
println!(
"{:<10} | {} upload {}",
key,
bar,
style(convert(value)).green()
);
}
if let Some(&value) = chart_a.down_map.get(key) {
let bar = "".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
println!(
"{:<10} | {} download {}",
key,
bar,
style(convert(value)).green()
);
}
println!("-");
}
}
pub fn console_chart_b(chart_b: ChartB) {
if chart_b.disable_stats {
println!("Traffic statistics not enabled");
return;
}
let ip = if let Some(ip) = chart_b.ip {
ip
} else {
println!("Ip: None");
return;
};
println!("---------------------------- upload ----------------------------");
println!("IP: {}", ip);
println!("Upload total: {}", style(convert(chart_b.up_total)).green());
println!(
"Max: {}",
style(convert(
chart_b
.up_list
.iter()
.max()
.cloned()
.map_or(0, |v| v as u64)
))
.green()
);
console_chart_b_list(chart_b.up_list);
println!("---------------------------- download ----------------------------");
println!("IP: {}", ip);
println!(
"Download total: {}",
style(convert(chart_b.down_total)).green()
);
println!(
"Max: {}",
style(convert(
chart_b
.down_list
.iter()
.max()
.cloned()
.map_or(0, |v| v as u64)
))
.green()
);
console_chart_b_list(chart_b.down_list);
}
fn console_chart_b_list(list: Vec<usize>) {
let max_value = *list.iter().max().unwrap_or(&0);
let max_value = max_value.max(1);
let max_height = max_value.min(20);
// 遍历从最大高度到0
for i in (0..=max_height).rev() {
for &value in &list {
let scaled_value = (value as f64 / max_value as f64 * max_height as f64) as usize;
if scaled_value >= i {
print!("");
} else {
print!(" ");
}
}
println!();
}
}
+17 -18
View File
@@ -52,28 +52,27 @@ pub fn get_unique_identifier() -> Option<String> {
pub fn get_unique_identifier() -> Option<String> {
use std::process::Command;
// 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的
// 唯一标识,而且某些环境没有预装`dmidecode`命令
if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") {
return Some(identifier);
}
let output = match Command::new("dmidecode")
// Try to execute 'dmidecode' command to get the system identifier first.
if let Ok(output) = Command::new("dmidecode")
.arg("-s")
.arg("system-uuid")
.output()
{
Ok(output) => output,
Err(_) => {
return None;
let identifier = String::from_utf8_lossy(&output.stdout).trim().to_owned();
if !identifier.is_empty() {
return Some(identifier.to_string());
}
};
let result = String::from_utf8_lossy(&output.stdout);
let identifier = result.trim().to_string();
if identifier.is_empty() {
None
} else {
Some(identifier.to_string())
}
// Try to read file /etc/machine-id if 'dmidecode' command cannot be executed or get nothing.
// 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的
// 唯一标识,而且某些环境没有预装`dmidecode`命令
if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") {
let identifier = identifier.trim();
if !identifier.is_empty() {
return Some(identifier.to_string());
}
}
None
}
+10
View File
@@ -1,2 +1,12 @@
pub mod args_parse;
#[cfg(feature = "command")]
pub mod command;
pub mod config;
#[cfg(feature = "command")]
mod console_out;
pub mod identifier;
pub mod cli;
mod generated_serial_number;
pub mod callback;
+34
View File
@@ -0,0 +1,34 @@
[package]
name = "vn-link-cli"
version = "1.2.12"
edition = "2021"
[dependencies]
vn-link = { path = "../vn-link", default-features = false }
common = { path = "../common", default-features = false }
tokio = { version = "1.37.0", features = ["full"] }
log = "0.4.17"
[features]
default = ["default-feature"]
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
openssl = ["vn-link/openssl", "common/openssl"]
openssl-vendored = ["vn-link/openssl-vendored", "common/openssl-vendored"]
ring-cipher = ["vn-link/ring-cipher", "common/ring-cipher"]
aes_cbc = ["vn-link/aes_cbc", "common/aes_cbc"]
aes_ecb = ["vn-link/aes_ecb", "common/aes_ecb"]
sm4_cbc = ["vn-link/sm4_cbc", "common/sm4_cbc"]
aes_gcm = ["vn-link/aes_gcm", "common/aes_gcm"]
chacha20_poly1305 = ["vn-link/chacha20_poly1305", "common/chacha20_poly1305"]
server_encrypt = ["vn-link/server_encrypt", "common/server_encrypt"]
port_mapping = ["vn-link/port_mapping", "common/port_mapping"]
lz4 = ["vn-link/lz4_compress", "common/lz4"]
zstd = ["vn-link/zstd_compress", "common/zstd"]
upnp = ["vn-link/upnp", "common/upnp"]
ws = ["vn-link/ws", "common/ws"]
wss = ["vn-link/wss", "common/wss"]
log = ["common/log"]
command = ["common/command"]
file_config = ["common/file_config"]
+61
View File
@@ -0,0 +1,61 @@
# 端口映射模式
## 一、特点
1. 不需要tap/tun虚拟网卡
2. 不需要管理员/root权限
3. 不改变本地路由
4. 使用端口映射来访问目标服务
## 二、作用
和vnt互补,能简单快速构建网络,外部依赖更少
## 三、使用方式
和vnt的使用方式一样,只是多了"--vnt-mapping"这个参数
### vn-link作为被访问端,不需要额外配置vnt-mapping
### vn-link访问vnt或者vn-link,需要加vnt-mapping
例如:
设备A 运行vnt(虚拟IP 10.26.0.A),设备B 运行vn-link(虚拟IP 10.26.0.B)。
如果要用B访问A上的tcp 80端口,则在设备B上需要加--vnt-mapping "tcp:port1-10.26.0.A:80"
这个参数的作用是将B上的***本地端口port1***转发到设备A的地址10.26.0.A:
80,此时在设备B上可以访问本地port1端口从而间接访问10.26.0.A:80
## 四、vn-link的子网代理
vn-link也支持点对网参数。 还是接着上面的例子
假设 设备C在设备A的子网下,C的子网IP为192.168.1.CA的子网IP为192.168.1.A,要在设备B上访问C
则在B上加这些参数
- --vnt-mapping "tcp:port2-192.168.1.C:80" (将本地port2端口映射到C的80端口)
- -i 192.168.1.0/24,10.26.0.A (将目标192.168.1.0/24的数据发送到10.26.0.A,也就是A节点)
在A上加参数
- -o 0.0.0.0/0 (允许所有流量转发)
***再次说明,vn-link作为被访问端时和vnt使用方式一致,vn-link作为访问端时需要加--vnt-mapping映射端口***
***vn-link是基于端口映射的使用模式,不会改变本地路由***
## 五、参数介绍
--vnt-mapping支持udp/tcp,例如 --vnt-mapping "tcp:port1-remoteIp:remotePort"
- 第一部分为协议,支持使用udp/tcp
- 第二部分是本地端口,注意不要和本地服务的端口冲突
- 第三部分是目标机器的地址,一般是目标虚拟IP地址,如果配置了点对网参数(-i和-o)则也可以是目标子网地址
+84
View File
@@ -0,0 +1,84 @@
use common::callback;
use vn_link::config::VnLinkConfig;
use vn_link::vnt::core::Config;
fn main() {
let (config, vnt_link_config, cmd) = match common::cli::parse_args_config() {
Ok(rs) => {
if let Some(rs) = rs {
rs
} else {
return;
}
}
Err(e) => {
println!("{}", e);
return;
}
};
let vnt_link_config = VnLinkConfig::new(vn_link::config::convert(vnt_link_config).unwrap());
main0(config, vnt_link_config, cmd)
}
#[tokio::main]
async fn main0(config: Config, vn_link_config: VnLinkConfig, _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)
}
}
for x in &vn_link_config.mapping {
if x.protocol.is_tcp() {
println!("TCP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
} else {
println!("UDP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
}
}
let vnt_util = match vn_link::VnLink::new(config, vn_link_config, callback::VntHandler {}).await
{
Ok(vnt) => vnt,
Err(e) => {
println!("error: {:?}", e);
std::process::exit(1);
}
};
#[cfg(feature = "command")]
{
let vnt_c = vnt_util.as_vnt().clone();
std::thread::Builder::new()
.name("CommandServer".into())
.spawn(move || {
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
log::warn!("cmd:{:?}", e);
}
})
.expect("CommandServer");
let vnt_c = vnt_util.as_vnt();
if _show_cmd {
use tokio::io::AsyncBufReadExt;
let mut cmd = String::new();
let mut reader = tokio::io::BufReader::new(tokio::io::stdin());
loop {
cmd.clear();
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
match reader.read_line(&mut cmd).await {
Ok(len) => {
if !common::command::command_str(&cmd[..len], vnt_c) {
break;
}
}
Err(e) => {
println!("input err:{}", e);
break;
}
}
}
}
}
vnt_util.wait().await
}
+32
View File
@@ -0,0 +1,32 @@
[package]
name = "vn-link"
version = "1.2.12"
edition = "2021"
[dependencies]
lwip-rs = { git = "https://github.com/vnt-dev/lwip-rs" }
vnt = { path = "../vnt", package = "vnt", default-features = false }
log = "0.4.17"
anyhow = "1.0.82"
parking_lot = "0.12.1"
tokio = { version = "1.37.0", features = ["full"] }
crossbeam-utils = "0.8"
[features]
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "lz4_compress"]
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"]
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
server_encrypt = ["vnt/server_encrypt"]
port_mapping = ["vnt/port_mapping"]
lz4_compress = ["vnt/lz4_compress"]
zstd_compress = ["vnt/zstd_compress"]
upnp = ["vnt/upnp"]
ws = ["vnt/ws"]
wss = ["vnt/wss"]
+85
View File
@@ -0,0 +1,85 @@
use anyhow::Context;
use std::net::SocketAddr;
use std::str::FromStr;
#[derive(Clone, Debug)]
pub struct VnLinkConfig {
pub mapping: Vec<LinkItem>,
}
impl VnLinkConfig {
pub fn new(mapping: Vec<LinkItem>) -> Self {
Self { mapping }
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum LinkProtocol {
Tcp,
Udp,
}
impl LinkProtocol {
pub fn is_tcp(&self) -> bool {
self == &LinkProtocol::Tcp
}
}
#[derive(Copy, Clone, Debug)]
pub struct LinkItem {
pub protocol: LinkProtocol,
pub src_port: u16,
pub dest: SocketAddr,
}
impl LinkItem {
pub fn new(protocol: LinkProtocol, src_port: u16, dest: SocketAddr) -> Self {
Self {
protocol,
src_port,
dest,
}
}
}
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<LinkItem>> {
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_port = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
let bind_port = u16::from_str(bind_port)
.with_context(|| format!("udp_mapping error {}", bind_port))?;
let dest = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
let dest_addr = SocketAddr::from_str(dest)
.with_context(|| format!("udp_mapping error {}", dest))?;
rs.push(LinkItem::new(LinkProtocol::Udp, bind_port, dest_addr));
continue;
}
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
let mut split = tcp_mapping.split("-");
let bind_port = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
let bind_port = u16::from_str(bind_port)
.with_context(|| format!("tcp_mapping error {}", bind_port))?;
let dest = split
.next()
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
let dest_addr = SocketAddr::from_str(dest)
.with_context(|| format!("tcp_mapping error {}", dest))?;
rs.push(LinkItem::new(LinkProtocol::Tcp, bind_port, dest_addr));
continue;
}
Err(anyhow::anyhow!(
"vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080",
x
))?;
}
Ok(rs)
}
+2
View File
@@ -0,0 +1,2 @@
pub mod tcp;
pub mod udp;
+46
View File
@@ -0,0 +1,46 @@
use crate::out_mapping::tcp::tcp_copy;
use crossbeam_utils::atomic::AtomicCell;
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use std::time::Duration;
use tokio::net::TcpListener;
use vnt::handle::CurrentDeviceInfo;
pub async fn tcp_mapping_listen(
tcp_listener: TcpListener,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
dest: SocketAddr,
) {
loop {
let (stream, addr) = match tcp_listener.accept().await {
Ok((stream, addr)) => (stream, addr),
Err(e) => {
log::warn!("tcp_mapping_listen {:?} dest {}", e, dest);
continue;
}
};
let current_info = current_device.load();
if current_info.virtual_ip.is_unspecified() {
continue;
}
if let IpAddr::V4(ip) = dest.ip() {
if ip == current_info.virtual_ip {
//防止用错参数的
log::warn!("目的地址不能是本地虚拟ip tcp->{}", dest);
continue;
}
}
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
tokio::spawn(async move {
match LwIpTcpStream::connect(src, dest, Duration::from_secs(5)).await {
Ok(lw_tcp) => {
tcp_copy(lw_tcp, stream);
}
Err(e) => {
log::warn!("{} {}->{} {}", addr, src, dest, e);
}
};
});
}
}
+63
View File
@@ -0,0 +1,63 @@
use std::collections::HashMap;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use std::time::Instant;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use lwip_rs::udp::UdpSocketWrite;
use vnt::handle::CurrentDeviceInfo;
pub async fn udp_mapping_start(
udp: UdpSocket,
lwip_udp_write: UdpSocketWrite,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
in_udp_map: &Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
dest: SocketAddr,
) {
let udp = Arc::new(udp);
let mut buf = [0u8; 65536];
loop {
let (len, addr) = match udp.recv_from(&mut buf).await {
Ok(rs) => rs,
Err(e) => {
log::warn!("recv_from {} {}", dest, e);
continue;
}
};
let current_info = current_device.load();
if current_info.virtual_ip.is_unspecified() {
continue;
}
if let IpAddr::V4(ip) = dest.ip() {
if ip == current_info.virtual_ip {
//防止用错参数的
log::warn!("目的地址不能是本地虚拟ip udp->{}", dest);
continue;
}
}
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
in_udp_map.lock().insert(
(dest, src),
(
udp.clone(),
Some(addr),
Arc::new(AtomicCell::new(Instant::now())),
),
);
if let Err(e) = lwip_udp_write.send(&buf[..len], &src, &dest) {
log::warn!("lwip_udp_write {}->{} {}", src, dest, e);
}
}
}
+8
View File
@@ -0,0 +1,8 @@
pub mod config;
mod in_mapping;
mod out_mapping;
mod vnt_link;
pub use vnt;
pub use vnt_link::*;
+2
View File
@@ -0,0 +1,2 @@
pub mod tcp;
pub mod udp;
+64
View File
@@ -0,0 +1,64 @@
use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
use tokio::net::TcpStream;
use lwip_rs::tcp_listener::TcpListener;
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
use vnt::handle::CurrentDeviceInfo;
pub async fn tcp_mapping_listen(
mut tcp_listener: TcpListener,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) {
loop {
let stream = match tcp_listener.accept().await {
Ok(stream) => stream,
Err(e) => {
log::warn!("tcp_mapping_listen err {:?}", e);
break;
}
};
let device_info = current_device.load();
tokio::spawn(async move {
let dest = stream.dest_addr();
let src = stream.src_addr();
if let Err(e) = tcp_mapping_handle(stream, device_info).await {
log::warn!("tcp_mapping_handle {}->{} {:?}", src, dest, e)
}
});
}
}
async fn tcp_mapping_handle(
tcp_stream: LwIpTcpStream,
device_info: CurrentDeviceInfo,
) -> anyhow::Result<()> {
let mut dest = tcp_stream.dest_addr();
// let src = tcp_stream.src_addr();
if let IpAddr::V4(ip) = dest.ip() {
if ip.is_unspecified()
|| ip.is_broadcast()
|| ip.is_multicast()
|| ip == device_info.virtual_ip
|| ip == device_info.broadcast_ip
{
//是自己
dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
}
}
let peer_stream = TcpStream::connect(dest).await?;
if dest.port() == peer_stream.local_addr()?.port() {
return Err(anyhow::anyhow!("tcp port loop"));
}
tcp_copy(tcp_stream, peer_stream);
Ok(())
}
pub(crate) fn tcp_copy(lw_tcp: LwIpTcpStream, tokio_tcp: TcpStream) {
let (mut write, mut read) = lw_tcp.into_split();
let (mut peer_read, mut peer_write) = tokio_tcp.into_split();
tokio::spawn(async move { tokio::io::copy(&mut read, &mut peer_write).await });
tokio::spawn(async move { tokio::io::copy(&mut peer_read, &mut write).await });
}
+137
View File
@@ -0,0 +1,137 @@
use crossbeam_utils::atomic::AtomicCell;
use lwip_rs::udp::{UdpSocketRead, UdpSocketWrite};
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::UdpSocket;
use vnt::handle::CurrentDeviceInfo;
pub async fn udp_mapping_start(
lwip_udp_write: UdpSocketWrite,
mut lwip_udp_read: UdpSocketRead,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
in_udp_map: Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
) {
loop {
let (buf, src, dest) = match lwip_udp_read.recv().await {
Ok(rs) => rs,
Err(e) => {
log::warn!("udp_mapping err {:?}", e);
break;
}
};
if let Err(e) = handle(
&current_device,
&lwip_udp_write,
&in_udp_map,
buf,
src,
dest,
)
.await
{
log::warn!("udp_mapping err {}->{} {:?}", src, dest, e)
}
}
}
async fn handle(
current_device: &AtomicCell<CurrentDeviceInfo>,
lwip_udp_write: &UdpSocketWrite,
map: &Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
buf: Vec<u8>,
src: SocketAddr,
dest: SocketAddr,
) -> anyhow::Result<()> {
let option = map.lock().get(&(src, dest)).cloned();
if let Some((dest_udp, addr, time)) = option {
time.store(Instant::now());
if let Some(addr) = addr {
dest_udp.send_to(&buf, addr).await?;
} else {
dest_udp.send(&buf).await?;
}
} else {
let mut real_dest = dest;
let peer_udp_socket = match UdpSocket::bind(format!("0.0.0.0:{}", src.port())).await {
Ok(udp) => udp,
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
};
if let IpAddr::V4(ip) = dest.ip() {
let device_info = current_device.load();
if ip.is_unspecified()
|| ip.is_broadcast()
|| ip.is_multicast()
|| ip == device_info.virtual_ip
|| ip == device_info.broadcast_ip
{
//是自己
real_dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
}
}
peer_udp_socket.connect(real_dest).await?;
peer_udp_socket.send(&buf).await?;
let peer_udp_socket = Arc::new(peer_udp_socket);
let time = Arc::new(AtomicCell::new(Instant::now()));
let map = map.clone();
map.lock()
.insert((src, dest), (peer_udp_socket.clone(), None, time.clone()));
let lwip_udp_write = lwip_udp_write.clone();
tokio::spawn(async move {
peer_udp_handle(peer_udp_socket, lwip_udp_write, src, dest, time).await;
map.lock().remove(&(src, dest));
});
}
Ok(())
}
async fn peer_udp_handle(
peer_udp_socket: Arc<UdpSocket>,
lwip_udp_write: UdpSocketWrite,
src: SocketAddr,
dest: SocketAddr,
time: Arc<AtomicCell<Instant>>,
) {
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 lwip_udp_write.send(&buf[..len], &dest, &src) {
Ok(_) => {}
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
break;
}
},
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!("udp proxy timeout {}->{}", dest, src,);
break;
}
}
}
}
}
+217
View File
@@ -0,0 +1,217 @@
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Instant;
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tokio::net::{TcpListener, UdpSocket};
use tokio::sync::watch::{channel, Sender};
use lwip_rs::stack::{NetStack, NetStackWrite};
use lwip_rs::tcp_listener::TcpListener as LwIPTcpListener;
use lwip_rs::udp::{UdpSocket as LwIpUdpSocket, UdpSocketWrite};
use vnt::channel::BUFFER_SIZE;
use vnt::core::{Config, Vnt};
use vnt::packet::ip::ipv4::packet::IpV4Packet;
use vnt::protocol::HEAD_LEN;
use vnt::vnt_device::DeviceWrite;
use vnt::VntCallback;
use crate::config::{LinkItem, LinkProtocol, VnLinkConfig};
use crate::{in_mapping, out_mapping};
pub struct VnLink {
vnt: Vnt,
in_udp_map: Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
>,
lwip_udp_write: UdpSocketWrite,
shutdown_tx: Sender<bool>,
}
impl VnLink {
pub async fn new<Call: VntCallback>(
vnt_config: Config,
vn_link_config: VnLinkConfig,
callback: Call,
) -> anyhow::Result<Self> {
let stack = NetStack::new(HEAD_LEN, 1024, vnt_config.mtu.unwrap_or(1420) as u16).await;
let udp = LwIpUdpSocket::new()?;
let tcp_listener = LwIPTcpListener::new()?;
let (shutdown_tx, shutdown_rx) = channel(false);
let (net_stack_write, mut net_stack_read) = stack.into_split();
let vnt = Vnt::new_device(vnt_config, callback, VntDevice { net_stack_write })?;
let shutdown_tx_ = shutdown_tx.clone();
let w = vnt.add_stop_listener("vnt-link".into(), move || {
let _ = shutdown_tx_.send(true);
})?;
let ip_sender = vnt.ipv4_packet_sender().unwrap();
let mut shutdown_rx_ = shutdown_rx.clone();
tokio::spawn(async move {
let mut extend = [0; BUFFER_SIZE];
loop {
tokio::select! {
_ = shutdown_rx_.changed() => {
break;
}
rs = net_stack_read.recv_ip() => {
match rs{
Ok((mut buf, start_index, len)) => {
let ipv4_packet = if let Ok(packet) =
IpV4Packet::new(&buf[start_index..len])
{
packet
} else {
continue;
};
let destination_ip = ipv4_packet.destination_ip();
let source_ip = ipv4_packet.source_ip();
if let Err(e) = ip_sender.send_ip(&mut buf, len, &mut extend, destination_ip) {
log::warn!("{}->{},{}", source_ip, destination_ip, e);
}
},
Err(e) => {
log::error!("net_stack_read {:?}", e);
break;
}
};
}
}
}
w.stop_all();
});
let (lwip_udp_write, lwip_udp_read) = udp.into_split();
let in_udp_map: Arc<
Mutex<
HashMap<
(SocketAddr, SocketAddr),
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
>,
>,
> = Arc::new(Mutex::new(HashMap::new()));
let current_device_info = vnt.current_device_info();
let in_udp_map_ = in_udp_map.clone();
let lwip_udp_write_ = lwip_udp_write.clone();
let vnt_ = vnt.clone();
let mut shutdown_rx_ = shutdown_rx.clone();
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = out_mapping::udp::udp_mapping_start(
lwip_udp_write_,
lwip_udp_read,
current_device_info,
in_udp_map_,
) => {}
}
vnt_.stop();
});
let current_device_info = vnt.current_device_info();
let vnt_ = vnt.clone();
let mut shutdown_rx_ = shutdown_rx.clone();
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = out_mapping::tcp::tcp_mapping_listen(tcp_listener, current_device_info) => {}
}
vnt_.stop();
});
let link = Self {
vnt,
in_udp_map,
lwip_udp_write,
shutdown_tx,
};
link.add_mapping(vn_link_config.mapping).await?;
Ok(link)
}
pub async fn add_mapping(&self, mapping: Vec<LinkItem>) -> anyhow::Result<()> {
for item in mapping {
let current_device_info = self.vnt.current_device_info();
if item.dest.ip().is_unspecified() {
Err(anyhow::anyhow!("dest_address {:?} is_unspecified", item))?
}
let mut shutdown_rx_ = self.shutdown_tx.subscribe();
if *shutdown_rx_.borrow() {
Err(anyhow::anyhow!("mapping stop"))?
}
if item.protocol == LinkProtocol::Udp {
let lwip_udp_write = self.lwip_udp_write.clone();
let in_udp_map = self.in_udp_map.clone();
//只能本机访问,不然不同IP的相同来源端口会有问题
let udp = UdpSocket::bind(format!("127.0.0.1:{}", item.src_port))
.await
.with_context(|| format!("udp bind failed {}", item.src_port))?;
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = in_mapping::udp::udp_mapping_start(
udp,
lwip_udp_write,
current_device_info,
&in_udp_map,
item.dest,
) => {}
}
});
} else {
let listener = TcpListener::bind(format!("127.0.0.1:{}", item.src_port))
.await
.with_context(|| format!("tcp bind failed {}", item.src_port))?;
tokio::spawn(async move {
tokio::select! {
_ = shutdown_rx_.changed() => {}
_ = in_mapping::tcp::tcp_mapping_listen(
listener,
current_device_info,
item.dest,
) => {}
}
});
}
}
Ok(())
}
pub fn stop(&self) {
self.as_vnt().stop()
}
pub async fn wait(&self) {
loop {
let mut receiver = self.shutdown_tx.subscribe();
if *receiver.borrow() {
return;
}
if receiver.changed().await.is_err() {
return;
}
}
}
pub fn as_vnt(&self) -> &Vnt {
&self.vnt
}
}
#[derive(Clone)]
pub struct VntDevice {
net_stack_write: NetStackWrite,
}
impl DeviceWrite for VntDevice {
fn write(&self, buf: &[u8]) -> std::io::Result<usize> {
self.net_stack_write.send_ip(buf)?;
Ok(buf.len())
}
}
+28 -25
View File
@@ -1,44 +1,47 @@
[package]
name = "vnt-cli"
version = "1.2.9"
version = "1.2.12"
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 }
common = { path = "../common" }
getopts = "0.2.21"
console = "0.15.2"
os_info = "3.7.0"
serde = "1.0"
serde_yaml = "0.9.32"
vnt = { path = "../vnt", package = "vnt", default-features = false, features = ["integrated_tun"] }
common = { path = "../common", default-features = false, features = ["integrated_tun"] }
log = "0.4.17"
log4rs = "1.2.0"
[dependencies.uuid]
version = "1.4.1"
features = [
"v4", # Lets you generate random UUIDs
]
anyhow = "1.0.82"
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
sudo = "0.6.0"
signal-hook = "0.3.17"
[target.'cfg(target_os = "windows")'.dependencies]
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"]
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"]
default = ["default-feature"]
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
openssl = ["vnt/openssl", "common/openssl"]
openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"]
ring-cipher = ["vnt/ring-cipher", "common/ring-cipher"]
aes_cbc = ["vnt/aes_cbc", "common/aes_cbc"]
aes_ecb = ["vnt/aes_ecb", "common/aes_ecb"]
sm4_cbc = ["vnt/sm4_cbc", "common/sm4_cbc"]
aes_gcm = ["vnt/aes_gcm", "common/aes_gcm"]
chacha20_poly1305 = ["vnt/chacha20_poly1305", "common/chacha20_poly1305"]
server_encrypt = ["vnt/server_encrypt", "common/server_encrypt"]
port_mapping = ["vnt/port_mapping", "common/port_mapping"]
lz4 = ["vnt/lz4_compress", "common/lz4"]
zstd = ["vnt/zstd_compress", "common/zstd"]
ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"]
upnp = ["vnt/upnp", "common/upnp"]
ws = ["vnt/ws", "common/ws"]
wss = ["vnt/wss", "common/wss"]
log = ["common/log"]
command = ["common/command"]
file_config = ["common/file_config"]
[build-dependencies]
embed-manifest = "1.4.0"
rand = "0.8.5"
chrono = "0.4.23"
+131 -25
View File
@@ -1,31 +1,56 @@
## 模块介绍
体积小,可以在服务器、路由器等环境使用
## 详细参数说明
### -k `<token>`
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
### -n `<name>`
设备名称,方便区分不同设备
### -d `<id>`
设备id,每台设备的唯一标识,注意不要重复
### -c
关闭控制台交互式命令,后台运行时可以加此参数
### -s `<server>`
注册和中继服务器地址,注册和转发数据
注册和中继服务器地址,注册和转发数据,以'TXT:'开头表示解析TXT记录,TXT记录内容必须是'host:port'形式的服务器地址
### -e `<stun-server>`
使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略
### -a
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
注意:仅在windows上支持使用tap,用于兼容低版本windows系统(低版本windows不支持wintun
使用tap模式需要手动创建tap网卡,使用--nic参数指定已经创建好的tap网卡名称
### --nic `<tun0>`
指定虚拟网卡名称,默认tun模式使用vnt-tuntap模式使用vnt-tap
### -i `<in-ip>`、-o `<out-ip>`
配置点对网(IP代理)时使用,例如A(虚拟ip:10.26.0.2)通过B(虚拟ip:10.26.0.3,本地出口ip:192.168.0.10)访问C(目标网段192.168.0.0/24)
配置点对网(IP代理)时使用,例如A(虚拟ip:10.26.0.2)通过B(虚拟ip:10.26.0.3,本地出口ip:192.168.0.10)访问C(
目标网段192.168.0.0/24)
则在A配置 **'-i 192.168.0.0/24,10.26.0.3'** ,表示将192.168.0.0/24网段的数据都转发到10.26.0.3节点
在B配置 **'-o 192.168.0.0/24'** ,表示允许将数据转发到 192.168.0.0/24 ,允许转发所有网段可以使用 **'-o 0.0.0.0/0'**
-i和-o参数均可使用多次,来指定不同网段,例如 **'-o 192.168.1.0/24 -o 192.168.2.0/24'** 表示允许转发目标为192.168.1.0/24或192.168.2.0/24这两个网段的数据
-i和-o参数均可使用多次,来指定不同网段,例如 **'-o 192.168.1.0/24 -o 192.168.2.0/24'**
表示允许转发目标为192.168.1.0/24或192.168.2.0/24这两个网段的数据
### -w `<password>`
@@ -37,9 +62,11 @@
| 大于等于8 | AES256-GCM |
### -W
开启和服务端通信的数据加密,采用rsa+aes256gcm加密客户端和服务端之间通信的数据,可以避免token泄漏、中间人攻击
注意:
1. -w `<password>`是用于客户端-客户端之间的加密,password不会传递到服务端,只添加这个参数不会加密客户端-服务端通信的数据
2. -W 用于开启客户端-服务端之间的加密
@@ -47,55 +74,101 @@
设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值,不加密默认为1450,加密默认为1410
### --tcp
### --tcp
和服务端使用tcp通信。有些网络提供商对UDP限制比较大,这个时候可以选择使用TCP模式,提高稳定性。一般来说udp延迟和消耗更低
### --ip `<IP>`
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
### --par `<parallel>`
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
### --model `<model>`
加密模式,可选值 aes_gcm/aes_cbc/aes_ecb/sm4_cbc,默认使用aes_gcm,通常情况aes_gcm安全性高、aes_ecb性能更好,但是在低性能设备上sm4_cbc也许速度会更快;
加密模式,可选值
aes_gcm/aes_cbc/aes_ecb/sm4_cbc/chacha20_poly1305/chacha20/xor,默认使用aes_gcm,通常情况aes_gcm和chacha20_poly1305安全性高。
各种加密模式的安全性和速度都不相同,请按需选取
| 密码位数 | model | 加密算法 |
|-------|---------|------------|
| 1~8位 | aes_gcm | AES128-GCM |
| `>=`8 | aes_gcm | AES256-GCM |
| 1~8位 | aes_cbc | AES128-CBC |
| `>=`8 | aes_cbc | AES256-CBC |
| 1~8位 | aes_ecb | AES128-ECB |
| `>=`8 | aes_ecb | AES256-ECB |
| `>0` | sm4_cbc | SM4-CBC |
### --finger
特别说明:xor只是对数据进行简单异或,仅仅避免了明文传输,安全性很差,同时对性能影响也极小;
| 密码位数 | model | 加密算法 |
|--------|-------------------|-------------------|
| `< 8` | aes_gcm | AES128-GCM |
| `>= 8` | aes_gcm | AES256-GCM |
| `< 8` | aes_cbc | AES128-CBC |
| `>= 8` | aes_cbc | AES256-CBC |
| `< 8` | aes_ecb | AES128-ECB |
| `>= 8` | aes_ecb | AES256-ECB |
| `> 0` | sm4_cbc | SM4-CBC |
| `> 0` | chacha20_poly1305 | ChaCha20-Poly1305 |
| `> 0` | chacha20 | ChaCha20 |
| `> 0` | xor | 简单异或混淆 |
### --finger
开启数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启,开启会损耗一部分性能
注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数
### --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监听一个未使用的端口
### --cmd
开启交互式命令,开启后可以直接在窗口下输入命令,如需后台运行请勿开启
### --first_latency
优先使用低延迟通道,默认情况下优先使用p2p通道,某些情况下可能p2p比客户端中继延迟更高,可使用此参数进行优化传输
### --no-proxy
关闭内置的ip代理,内置的代理较为简单,而且一般来说直接使用网卡NAT转发性能会更高,
有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/lbl8603/vnt#%E7%BC%96%E8%AF%91)
有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/vnt-dev/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,转发的目的地址可以使用域名+端口
### --compressor `<lz4>`
启用压缩,默认仅支持lz4压缩,开启压缩后,如果数据包长度大于等于128,则会使用压缩,否则还是会按原数据发送
也支持开启zstd压缩,但是需要自行编译,编译时加入参数--features zstd
如果宽度速度比较慢,可以考虑使用高级别的压缩
### -f `<conf>`
指定配置文件
配置文件采用yaml格式,可参考:
```yaml
# 全部参数
tap: false #是否使用tap
tap: false #是否使用tap 仅在windows上支持使用tap
token: xxx #组网token
device_id: xxx #当前设备id
name: windows 11 #当前设备名称
server_address: ip:port #注册和中继服务器
stun_server: #stun服务器
stun_server: #stun服务器
- stun1.l.google.com:19302
- stun2.l.google.com:19302
in_ips: #代理ip入站
@@ -111,8 +184,8 @@ server_encrypt: true #服务端加密
parallel: 1 #任务并行度
cipher_model: aes_gcm #客户端加密算法
finger: false #关闭数据指纹
punch_model: ipv4 #打洞模式
ports:
punch_model: ipv4 #打洞模式,表示只使用ipv4地址打洞,默认会同时使用v6和v4
ports:
- 0 #使用随机端口,tcp监听此端口
- 0
cmd: false #关闭控制台输入
@@ -122,27 +195,60 @@ 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数据
disable_stats: false # 为true表示关闭统计
allow_wire_guard: false # 为true则表示允许接入wg
```
或者需要哪个配置就加哪个,当然token是必须的
```yaml
# 部分参数
token: xxx #组网token
```
### --use-channel `<relay/p2p>`
- relay:仅中继模式,会禁止打洞/p2p直连,只使用服务器转发
- p2p:仅直连模式,会禁止网络数据从服务器/客户端转发,只会使用服务器转发控制包
### --packet-loss `<0>`
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境会有帮助。
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境时会有帮助。
### --packet-delay `<0>`
模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网
### --disable-stats
关闭流量统计
### --allow-wg
允许接入WireGuard客户端,和wg混用时必须开启此参数
### --list
在后台运行时,查看其他设备列表
### --all
在后台运行时,查看其他设备完整信息
### --info
在后台运行时,查看当前设备信息
### --route
### --route
在后台运行时,查看数据转发路径
### --stop
停止后台运行
+70 -482
View File
@@ -1,509 +1,97 @@
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::str::FromStr;
use std::{io, thread};
use console::style;
use getopts::Options;
use common::args_parse::{ips_parse, out_ips_parse};
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use common::callback;
use vnt::core::{Config, Vnt};
mod command;
mod config;
mod console_out;
mod generated_serial_number;
mod root_check;
pub fn app_home() -> io::Result<PathBuf> {
let root_path = match std::env::current_exe() {
Ok(path) => {
if let Some(v) = path.as_path().parent() {
v.to_path_buf()
fn main() {
let (config, _vnt_link_config, cmd) = match common::cli::parse_args_config() {
Ok(rs) => {
if let Some(rs) = rs {
rs
} else {
log::warn!("current_exe parent none:{:?}", path);
PathBuf::new()
return;
}
}
Err(e) => {
log::warn!("current_exe err:{:?}", e);
PathBuf::new()
}
};
let path = root_path.join("env");
if !path.exists() {
std::fs::create_dir_all(&path)?;
}
Ok(path)
}
fn main() {
let _ = log4rs::init_file("log4rs.yaml", Default::default());
let args: Vec<String> = std::env::args().collect();
let program = args[0].clone();
let mut opts = Options::new();
opts.optopt("k", "", "组网标识", "<token>");
opts.optopt("n", "", "设备名称", "<name>");
opts.optopt("d", "", "设备标识", "<id>");
opts.optflag("c", "", "关闭交互式命令");
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
opts.optmulti("e", "", "stun服务器", "<stun-server>");
opts.optflag("a", "", "使用tap模式");
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
opts.optopt("w", "", "客户端加密", "<password>");
opts.optflag("W", "", "服务端加密");
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
opts.optflag("", "tcp", "tcp");
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
opts.optflag("", "relay", "仅使用服务器转发");
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
opts.optopt("", "model", "加密模式", "<model>");
opts.optflag("", "finger", "指纹校验");
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
opts.optopt("", "ports", "监听的端口", "<port,port>");
opts.optflag("", "cmd", "开启窗口输入");
opts.optflag("", "no-proxy", "关闭内置代理");
opts.optflag("", "first-latency", "优先延迟");
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
opts.optmulti("", "dns", "dns", "<dns>");
opts.optopt("f", "", "配置文件", "<conf>");
//"后台运行时,查看其他设备列表"
opts.optflag("", "list", "后台运行时,查看其他设备列表");
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
opts.optflag("", "info", "后台运行时,查看当前设备信息");
opts.optflag("", "route", "后台运行时,查看数据转发路径");
opts.optflag("", "stop", "停止后台运行");
opts.optflag("h", "help", "帮助");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
print_usage(&program, opts);
println!("{}", f.to_string());
println!("{}", e);
return;
}
};
if matches.opt_present("h") || args.len() == 1 {
print_usage(&program, opts);
return;
}
main0(config, cmd)
}
fn main0(config: Config, _show_cmd: bool) {
if !root_check::is_app_elevated() {
println!("Please run it with administrator or root privileges");
#[cfg(any(target_os = "linux", target_os = "macos"))]
sudo::escalate_if_needed().unwrap();
return;
}
if matches.opt_present("list") {
command::command(command::CommandEnum::List);
return;
} else if matches.opt_present("info") {
command::command(command::CommandEnum::Info);
return;
} else if matches.opt_present("stop") {
command::command(command::CommandEnum::Stop);
return;
} else if matches.opt_present("route") {
command::command(command::CommandEnum::Route);
return;
} else if matches.opt_present("all") {
command::command(command::CommandEnum::All);
return;
#[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 conf = matches.opt_str("f");
let (config, cmd) = if conf.is_some() {
match config::read_config(&conf.unwrap()) {
Ok(c) => c,
Err(e) => {
println!("conf err {}", e);
return;
}
let vnt_util = match Vnt::new(config, callback::VntHandler {}) {
Ok(vnt) => vnt,
Err(e) => {
println!("error: {:?}", e);
std::process::exit(1);
}
} else {
if !matches.opt_present("k") {
print_usage(&program, opts);
println!("parameter -k not found .");
return;
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
let tap = matches.opt_present("a");
let device_name = matches.opt_str("nic");
let token: String = matches.opt_get("k").unwrap().unwrap();
let device_id = matches.opt_get_default("d", String::new()).unwrap();
let device_id = if device_id.is_empty() {
config::get_device_id()
} else {
device_id
};
if device_id.is_empty() {
print_usage(&program, opts);
println!("parameter -d not found .");
return;
}
let name = matches
.opt_get_default("n", os_info::get().to_string())
.unwrap();
let server_address_str = matches
.opt_get_default("s", "nat1.wherewego.top:29872".to_string())
.unwrap();
let mut stun_server = matches.opt_strs("e");
if stun_server.is_empty() {
stun_server.push("stun1.l.google.com:19302".to_string());
stun_server.push("stun2.l.google.com:19302".to_string());
stun_server.push("stun.qq.com:3478".to_string());
}
let dns = matches.opt_strs("dns");
let in_ip = matches.opt_strs("i");
let in_ip = match ips_parse(&in_ip) {
Ok(in_ip) => in_ip,
Err(e) => {
print_usage(&program, opts);
println!();
println!("-i: {:?} {}", in_ip, e);
println!("example: -i 192.168.0.0/24,10.26.0.3");
return;
}
};
let out_ip = matches.opt_strs("o");
let out_ip = match out_ips_parse(&out_ip) {
Ok(out_ip) => out_ip,
Err(e) => {
print_usage(&program, opts);
println!();
println!("-o: {:?} {}", out_ip, e);
println!("example: -o 0.0.0.0/0");
return;
}
};
let password: Option<String> = matches.opt_get("w").unwrap();
let server_encrypt = matches.opt_present("W");
#[cfg(not(feature = "server_encrypt"))]
{
if server_encrypt {
println!("Server encryption not supported");
return;
}
}
let mtu: Option<String> = matches.opt_get("u").unwrap();
let mtu = if let Some(mtu) = mtu {
match u32::from_str(&mtu) {
Ok(mtu) => Some(mtu),
Err(e) => {
print_usage(&program, opts);
println!();
println!("'-u {}' {}", mtu, e);
return;
}
}
} else {
None
};
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
let virtual_ip =
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
if let Some(virtual_ip) = virtual_ip {
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
{
println!("'--ip {}' invalid", virtual_ip);
return;
}
}
let tcp_channel = matches.opt_present("tcp");
let relay = matches.opt_present("relay");
let parallel = matches.opt_get::<usize>("par").unwrap().unwrap_or(1);
if parallel == 0 {
println!("'--par {}' invalid", parallel);
return;
}
let cipher_model = match matches.opt_get::<CipherModel>("model") {
Ok(model) => {
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
{
if password.is_some() && model.is_none() {
println!("Encryption not supported");
return;
}
}
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
{
if password.is_some() && model.is_none() {
println!("'--model ' undefined");
return;
}
model.unwrap_or(CipherModel::None)
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
model.unwrap_or(CipherModel::AesGcm)
}
Err(e) => {
println!("'--model ' invalid,{}", e);
return;
}
};
let finger = matches.opt_present("finger");
let punch_model = matches
.opt_get::<PunchModel>("punch")
.unwrap()
.unwrap_or(PunchModel::All);
let use_channel_type = matches
.opt_get::<UseChannelType>("use-channel")
.unwrap()
.unwrap_or_else(|| {
if relay {
UseChannelType::Relay
} else {
UseChannelType::All
}
});
let ports = matches
.opt_get::<String>("ports")
.unwrap_or(None)
.map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect());
let cmd = matches.opt_present("cmd");
#[cfg(feature = "ip_proxy")]
let no_proxy = matches.opt_present("no-proxy");
let first_latency = matches.opt_present("first-latency");
let packet_loss = matches
.opt_get::<f64>("packet-loss")
.expect("--packet-loss");
let packet_delay = matches
.opt_get::<u32>("packet-delay")
.expect("--packet-delay")
.unwrap_or(0);
let config = match Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap,
token,
device_id,
name,
server_address_str,
dns,
stun_server,
in_ip,
out_ip,
password,
mtu,
tcp_channel,
virtual_ip,
#[cfg(feature = "ip_proxy")]
no_proxy,
server_encrypt,
parallel,
cipher_model,
finger,
punch_model,
ports,
first_latency,
device_name,
use_channel_type,
packet_loss,
packet_delay,
) {
Ok(config) => config,
Err(e) => {
println!("config error: {}", e);
return;
}
};
(config, cmd)
};
println!("version {}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
log::info!(
"version:{},Serial:{}",
vnt::VNT_VERSION,
generated_serial_number::SERIAL_NUMBER
);
main0(config, cmd);
std::process::exit(0);
}
mod callback;
fn main0(config: Config, show_cmd: bool) {
let vnt_util = Vnt::new(config, callback::VntHandler {}).unwrap();
let vnt_c = vnt_util.clone();
thread::Builder::new()
.name("CommandServer".into())
.spawn(move || {
if let Err(e) = command::server::CommandServer::new().start(vnt_c) {
log::warn!("cmd:{:?}", e);
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
let vnt_c = vnt_util.clone();
let mut signals = signal_hook::iterator::Signals::new(&[
signal_hook::consts::SIGINT,
signal_hook::consts::SIGTERM,
])
.unwrap();
let handle = signals.handle();
std::thread::spawn(move || {
for sig in signals.forever() {
match sig {
signal_hook::consts::SIGINT | signal_hook::consts::SIGTERM => {
println!("Received SIGINT, {}", sig);
vnt_c.stop();
handle.close();
break;
}
_ => {}
}
}
})
.expect("CommandServer");
if show_cmd {
let mut cmd = String::new();
loop {
cmd.clear();
println!("======== input:list,info,route,all,stop ========");
match io::stdin().read_line(&mut cmd) {
Ok(len) => {
if !command(&cmd[..len], &vnt_util) {
});
}
#[cfg(feature = "command")]
{
let vnt_c = vnt_util.clone();
std::thread::Builder::new()
.name("CommandServer".into())
.spawn(move || {
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
log::warn!("cmd:{:?}", e);
}
})
.expect("CommandServer");
if _show_cmd {
let mut cmd = String::new();
loop {
cmd.clear();
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
match std::io::stdin().read_line(&mut cmd) {
Ok(len) => {
if !common::command::command_str(&cmd[..len], &vnt_util) {
break;
}
}
Err(e) => {
println!("input err:{}", e);
break;
}
}
Err(e) => {
println!("input err:{}", e);
break;
}
}
}
}
vnt_util.wait()
}
fn command(cmd: &str, vnt: &Vnt) -> bool {
if cmd.is_empty() {
return false;
}
match cmd.to_lowercase().trim() {
"list" => {
let list = command::command_list(&vnt);
console_out::console_device_list(list);
}
"info" => {
let info = command::command_info(&vnt);
console_out::console_info(info);
}
"route" => {
let route = command::command_route(&vnt);
console_out::console_route_table(route);
}
"all" => {
let list = command::command_list(&vnt);
console_out::console_device_list_all(list);
}
"stop" => {
let _ = vnt.stop();
return false;
}
_ => {}
}
println!();
return true;
}
fn print_usage(program: &str, _opts: Options) {
println!("Usage: {} [options]", program);
println!("version:{}", vnt::VNT_VERSION);
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
println!("Options:");
println!(
" -k <token> {}",
green("使用相同的token,就能组建一个局域网络".to_string())
);
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2");
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,可指定多个网段");
#[cfg(feature = "ip_proxy")]
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
let enums = String::new();
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[cfg(feature = "aes_cbc")]
enums.push_str("/aes_cbc");
#[cfg(feature = "aes_ecb")]
enums.push_str("/aes_ecb");
#[cfg(feature = "sm4_cbc")]
enums.push_str("/sm4_cbc");
if !enums.is_empty() {
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
}
#[cfg(feature = "server_encrypt")]
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
println!(" -f <conf_file> 读取配置文件中的配置");
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
if !enums.is_empty() {
println!(
" --model <model> 加密模式(默认aes_gcm),可选值{}",
&enums[1..]
);
}
if !enums.is_empty() {
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
}
println!(" --punch <punch> 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞");
println!(" --ports <port,port> 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
#[cfg(feature = "ip_proxy")]
println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
println!(" --nic <tun0> 指定虚拟网卡名称");
println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网");
println!(
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
);
println!(" --dns <host:port> DNS服务器地址,可使用多个dns,不指定时使用系统解析");
println!();
println!(
" --list {}",
yellow("后台运行时,查看其他设备列表".to_string())
);
println!(
" --all {}",
yellow("后台运行时,查看其他设备完整信息".to_string())
);
println!(
" --info {}",
yellow("后台运行时,查看当前设备信息".to_string())
);
println!(
" --route {}",
yellow("后台运行时,查看数据转发路径".to_string())
);
println!(
" --stop {}",
yellow("停止后台运行".to_string())
);
println!(" -h, --help 帮助");
}
fn green(str: String) -> impl std::fmt::Display {
style(str).green()
}
fn yellow(str: String) -> impl std::fmt::Display {
style(str).yellow()
}
-18
View File
@@ -1,18 +0,0 @@
[package]
name = "vnt-jni"
version = "1.2.9"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
common = { path = "../common" }
vnt = {path="../vnt"}
parking_lot = "0.12.1"
jni = { version = "0.21.1", default-features = false }
log = "0.4.20"
spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64","pem"]}
[lib]
crate-type = ["staticlib", "cdylib"]
-1
View File
@@ -1 +0,0 @@
## 提供给安卓端使用
@@ -1,77 +0,0 @@
package top.wherewego.vnt.jni;
import top.wherewego.vnt.jni.param.*;
/**
* 回调
*
* @author https://github.com/lbl8603/vnt
*/
public interface CallBack {
/**
* 连接成功的回调
*/
void success();
/**
* 创建虚拟网卡成功的回调方法
* 仅在 windows/linux/macos上使用
*
* @param info 网卡信息
*/
void createTun(DeviceInfo info);
/**
* 连接服务端
*
* @param info 将要连接的服务端信息
*/
void connect(ConnectInfo info);
/**
* 和服务端握手
*
* @param info 握手信息
* @return 是否确认握手
*/
boolean handshake(HandshakeInfo info);
/**
* 注册成功回调
*
* @param info 注册信息
* @return 是否确认注册信息
*/
boolean register(RegisterInfo info);
/**
* 创建网卡回调
* 仅在android上使用
*
* @param info 创建配置
* @return 网卡fd
*/
int generateTun(DeviceConfig info);
/**
* 对端用户列表
*
* @param infoArray
*/
void peerClientList(PeerClientInfo[] infoArray);
/**
* 异常回调
*
* @param info 错误信息
*/
void error(ErrorInfo info);
/**
* 服务停止
*/
void stop();
}
@@ -1,300 +0,0 @@
package top.wherewego.vnt.jni;
/**
* 启动配置
*
* @author https://github.com/lbl8603/vnt
*/
public class Config {
/**
* 是否是tap模式,仅支持windows和linux
*/
private boolean tap;
/**
* 组网标识
*/
private String token;
/**
* 设备名称
*/
private String name;
/**
* 客户端间加密的密码
*/
private String password;
/**
* 客户端间加密模式 aes_gcm/aes_cbc/aes_ecb/sm4_cbc
*/
private String cipherModel;
/**
* 打洞模式 ipv4/ipv6/all
*/
private String punchModel;
/**
* mtu 默认自动计算
*/
private Integer mtu;
/**
* 是否开启服务端加密
*/
private boolean serverEncrypt;
/**
* 仅使用中继转发
*/
private boolean relay;
/**
* 设备id,请使用唯一值
*/
private String deviceId;
/**
* 服务端地址
*/
private String server;
/**
* dns地址
*/
private String[] dns;
/**
* stun服务地址
*/
private String[] stunServer;
/**
* 和服务端使用tcp通信,默认使用udp
*/
private boolean tcp;
/**
* 指定组网IP
*/
private String ip;
/**
* 开启加密指纹校验
*/
private boolean finger;
/**
* 延迟优先,默认p2p优先
*/
private boolean firstLatency;
/**
* 点对网入口 格式 192.168.0.0/26,10.26.0.2
*/
private String[] inIps;
/**
* 点对网出口 格式 192.168.0.0/26
*/
private String[] outIps;
/**
* 端口组,udp会监听一组端口,tcp监听ports[0]端口
*/
private int[] ports;
/**
* 虚拟网卡名称 仅在linux、windows、macos上支持
*/
private String deviceName;
/**
* enum: relay/p2p/all
*/
private String useChannel;
/**
* 模拟丢包率,取0~1之间的数,为null表示不丢包,1表示全部丢包
*/
private Double packetLossRate;
/**
* 模拟延迟 单位毫秒(ms)
*/
private Integer packetDelay;
public Config() {
}
public boolean isTap() {
return tap;
}
public void setTap(boolean tap) {
this.tap = tap;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCipherModel() {
return cipherModel;
}
public void setCipherModel(String cipherModel) {
this.cipherModel = cipherModel;
}
public String getPunchModel() {
return punchModel;
}
public void setPunchModel(String punchModel) {
this.punchModel = punchModel;
}
public Integer getMtu() {
return mtu;
}
public void setMtu(Integer mtu) {
this.mtu = mtu;
}
public boolean isServerEncrypt() {
return serverEncrypt;
}
public void setServerEncrypt(boolean serverEncrypt) {
this.serverEncrypt = serverEncrypt;
}
public boolean isRelay() {
return relay;
}
public void setRelay(boolean relay) {
this.relay = relay;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public String[] getDns() {
return dns;
}
public void setDns(String[] dns) {
this.dns = dns;
}
public String[] getStunServer() {
return stunServer;
}
public void setStunServer(String[] stunServer) {
this.stunServer = stunServer;
}
public boolean isTcp() {
return tcp;
}
public void setTcp(boolean tcp) {
this.tcp = tcp;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public boolean isFinger() {
return finger;
}
public void setFinger(boolean finger) {
this.finger = finger;
}
public boolean isFirstLatency() {
return firstLatency;
}
public void setFirstLatency(boolean firstLatency) {
this.firstLatency = firstLatency;
}
public String[] getInIps() {
return inIps;
}
public void setInIps(String[] inIps) {
this.inIps = inIps;
}
public String[] getOutIps() {
return outIps;
}
public void setOutIps(String[] outIps) {
this.outIps = outIps;
}
public int[] getPorts() {
return ports;
}
public void setPorts(int[] ports) {
this.ports = ports;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public String getUseChannel() {
return useChannel;
}
public void setUseChannel(String useChannel) {
this.useChannel = useChannel;
}
public Double getPacketLossRate() {
return packetLossRate;
}
public void setPacketLossRate(Double packetLossRate) {
this.packetLossRate = packetLossRate;
}
public Integer getPacketDelay() {
return packetDelay;
}
public void setPacketDelay(Integer packetDelay) {
this.packetDelay = packetDelay;
}
}
@@ -1,43 +0,0 @@
package top.wherewego.vnt.jni;
/**
* ip转换
*
* @author https://github.com/lbl8603/vnt
*/
public class IpUtils {
/**
* 将整数的ip地址转成字符串,例如 0 转成 "0.0.0.0"
*
* @param ipAddress
* @return
*/
public static String intToIpAddress(int ipAddress) {
return ((ipAddress & 0xFF000000) >>> 24) + "." +
((ipAddress & 0x00FF0000) >>> 16) + "." +
((ipAddress & 0x0000FF00) >>> 8) + "." +
(ipAddress & 0x000000FF);
}
/**
* 返回掩码的长度
*
* @param subnetMask
* @return
*/
public static int subnetMaskToPrefixLength(int subnetMask) {
int prefixLength = 0;
int bit = 1 << 31;
while (subnetMask != 0) {
if ((subnetMask & bit) != bit) {
break;
}
prefixLength++;
subnetMask <<= 1;
}
return prefixLength;
}
}
@@ -1,46 +0,0 @@
package top.wherewego.vnt.jni;
/**
* 对端设备信息
*
* @author https://github.com/lbl8603/vnt
*/
public class PeerRouteInfo {
private final int virtualIp;
private final String name;
private final String status;
private final Route route;
public PeerRouteInfo(int virtualIp, String name, String status, Route route) {
this.virtualIp = virtualIp;
this.name = name;
this.status = status;
this.route = route;
}
public int getVirtualIp() {
return virtualIp;
}
public String getName() {
return name;
}
public String getStatus() {
return status;
}
public Route getRoute() {
return route;
}
@Override
public String toString() {
return "PeerDeviceInfo{" +
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
", name='" + name + '\'' +
", status='" + status + '\'' +
", route=" + route +
'}';
}
}
@@ -1,50 +0,0 @@
package top.wherewego.vnt.jni;
/**
* 路由信息
*
* @author https://github.com/lbl8603/vnt
*/
public class Route {
/**
* 是否使用tcp
*/
private final boolean tcp;
private final String address;
private final byte metric;
private final int rt;
public Route(boolean tcp, String address, byte metric, int rt) {
this.tcp = tcp;
this.address = address;
this.metric = metric;
this.rt = rt;
}
public boolean isTcp() {
return tcp;
}
public String getAddress() {
return address;
}
public byte getMetric() {
return metric;
}
public int getRt() {
return rt;
}
@Override
public String toString() {
return "Route{" +
"tcp=" + tcp +
", address='" + address + '\'' +
", metric=" + metric +
", rt=" + rt +
'}';
}
}
@@ -1,47 +0,0 @@
package top.wherewego.vnt.jni;
import java.io.Closeable;
import java.io.IOException;
/**
* vnt的Java映射
*
* @author https://github.com/lbl8603/vnt
*/
public class Vnt implements Closeable {
private final long raw;
public Vnt(Config config, CallBack callBack) throws Exception{
this.raw = new0(config, callBack);
if (this.raw == 0) {
throw new RuntimeException();
}
}
public void stop() {
stop0(raw);
}
public void await() {
wait0(raw);
}
public PeerRouteInfo[] list() {
return list0(raw);
}
private native long new0(Config config, CallBack callBack) throws Exception;
private native void stop0(long raw);
private native void wait0(long raw);
private native void drop0(long raw);
private native PeerRouteInfo[] list0(long raw);
@Override
public void close() throws IOException {
drop0(raw);
}
}
@@ -1,32 +0,0 @@
package top.wherewego.vnt.jni.param;
/**
* 连接信息
*
* @author https://github.com/lbl8603/vnt
*/
public class ConnectInfo {
private final long count;
private final String address;
public ConnectInfo(long count, String address) {
this.count = count;
this.address = address;
}
public long getCount() {
return count;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return "ConnectInfo{" +
"count=" + count +
", address='" + address + '\'' +
'}';
}
}
@@ -1,72 +0,0 @@
package top.wherewego.vnt.jni.param;
import top.wherewego.vnt.jni.IpUtils;
import java.util.Arrays;
/**
* 创建网卡所需信息,仅在android上使用
*
* @author https://github.com/lbl8603/vnt
*/
public class DeviceConfig {
/**
* 虚拟IP
*/
public final int virtualIp;
/**
* 掩码
*/
public final int virtualNetmask;
/**
* 网关
*/
public final int virtualGateway;
/**
* 虚拟网段
*/
public final int virtualNetwork;
/**
* 额外路由,来自点对网的路由配置
*/
public final String[] externalRoute;
public DeviceConfig(int virtualIp, int virtualNetmask, int virtualGateway, int virtualNetwork, String[] externalRoute) {
this.virtualIp = virtualIp;
this.virtualNetmask = virtualNetmask;
this.virtualGateway = virtualGateway;
this.virtualNetwork = virtualNetwork;
this.externalRoute = externalRoute;
}
public int getVirtualIp() {
return virtualIp;
}
public int getVirtualNetmask() {
return virtualNetmask;
}
public int getVirtualGateway() {
return virtualGateway;
}
public int getVirtualNetwork() {
return virtualNetwork;
}
public String[] getExternalRoute() {
return externalRoute;
}
@Override
public String toString() {
return "DeviceConfig{" +
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
", virtualNetmask=" + IpUtils.intToIpAddress(virtualNetmask) +
", virtualGateway=" + IpUtils.intToIpAddress(virtualGateway) +
", virtualNetwork=" + IpUtils.intToIpAddress(virtualNetwork) +
", externalRoute=" + Arrays.toString(externalRoute) +
'}';
}
}
@@ -1,38 +0,0 @@
package top.wherewego.vnt.jni.param;
/**
* 网卡信息 仅在 windows/linux/macos上使用
*
* @author https://github.com/lbl8603/vnt
*/
public class DeviceInfo {
/**
* 虚拟网卡名称
*/
private final String name;
/**
* 虚拟网卡版本
*/
private final String version;
public DeviceInfo(String name, String version) {
this.name = name;
this.version = version;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "DeviceInfo{" +
"name='" + name + '\'' +
", version='" + version + '\'' +
'}';
}
}
@@ -1,65 +0,0 @@
package top.wherewego.vnt.jni.param;
/**
* 异常回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class ErrorInfo {
/**
* 错误码
*/
public final ErrorCodeEnum code;
/**
* 错误信息,可能为空
*/
public final String msg;
public ErrorInfo(int code, String msg) {
switch (code) {
case 1:
this.code = ErrorCodeEnum.TokenError;
break;
case 2:
this.code = ErrorCodeEnum.Disconnect;
break;
case 3:
this.code = ErrorCodeEnum.AddressExhausted;
break;
case 4:
this.code = ErrorCodeEnum.IpAlreadyExists;
break;
case 5:
this.code = ErrorCodeEnum.InvalidIp;
break;
default:
this.code = ErrorCodeEnum.Unknown;
}
this.msg = msg;
}
public ErrorCodeEnum getCode() {
return code;
}
public String getMsg() {
return msg;
}
public enum ErrorCodeEnum {
TokenError,
Disconnect,
AddressExhausted,
IpAlreadyExists,
InvalidIp,
Unknown,
}
@Override
public String toString() {
return "ErrorInfo{" +
"code=" + code +
", msg='" + msg + '\'' +
'}';
}
}
@@ -1,54 +0,0 @@
package top.wherewego.vnt.jni.param;
/**
* 握手回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class HandshakeInfo {
/**
* 公钥 pem格式 CRLF分隔,不加密时为空
*/
private final String publicKey;
/**
* 公钥签名,不加密时为空
*/
private final String finger;
/**
* 服务端版本
*/
private final String version;
public HandshakeInfo() {
this.publicKey = "publicKey";
this.finger = "finger";
this.version = "version";
}
public HandshakeInfo(String publicKey, String finger, String version) {
this.publicKey = publicKey;
this.finger = finger;
this.version = version;
}
public String getPublicKey() {
return publicKey;
}
public String getFinger() {
return finger;
}
public String getVersion() {
return version;
}
@Override
public String toString() {
return "HandshakeInfo{" +
"publicKey='" + publicKey + '\'' +
", finger='" + finger + '\'' +
", version='" + version + '\'' +
'}';
}
}
@@ -1,60 +0,0 @@
package top.wherewego.vnt.jni.param;
import top.wherewego.vnt.jni.IpUtils;
/**
* 创建网卡所需信息,仅在android上使用
*
* @author https://github.com/lbl8603/vnt
*/
public class PeerClientInfo {
/**
* 虚拟IP
*/
public final int virtualIp;
/**
* 名称
*/
public final String name;
/**
* 是否在线
*/
public final boolean online;
/**
* 是否开启客户端加密,不同加密状态的不能通信
*/
public final boolean clientSecret;
public PeerClientInfo(int virtualIp, String name, boolean online, boolean clientSecret) {
this.virtualIp = virtualIp;
this.name = name;
this.online = online;
this.clientSecret = clientSecret;
}
public int getVirtualIp() {
return virtualIp;
}
public String getName() {
return name;
}
public boolean isOnline() {
return online;
}
public boolean isClientSecret() {
return clientSecret;
}
@Override
public String toString() {
return "PeerDeviceInfo{" +
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
", name='" + name + '\'' +
", online=" + online +
", clientSecret=" + clientSecret +
'}';
}
}
@@ -1,50 +0,0 @@
package top.wherewego.vnt.jni.param;
import top.wherewego.vnt.jni.IpUtils;
/**
* 注册回调信息
*
* @author https://github.com/lbl8603/vnt
*/
public class RegisterInfo {
/**
* 虚拟IP
*/
public final int virtualIp;
/**
* 掩码
*/
public final int virtualNetmask;
/**
* 网关
*/
public final int virtualGateway;
public RegisterInfo(int virtualIp, int virtualNetmask, int virtualGateway) {
this.virtualIp = virtualIp;
this.virtualNetmask = virtualNetmask;
this.virtualGateway = virtualGateway;
}
public int getVirtualIp() {
return virtualIp;
}
public int getVirtualNetmask() {
return virtualNetmask;
}
public int getVirtualGateway() {
return virtualGateway;
}
@Override
public String toString() {
return "RegisterInfo{" +
"virtualIp='" + IpUtils.intToIpAddress(virtualIp) + '\'' +
", virtualNetmask='" + IpUtils.intToIpAddress(virtualNetmask) + '\'' +
", virtualGateway='" + IpUtils.intToIpAddress(virtualGateway) + '\'' +
'}';
}
}
-322
View File
@@ -1,322 +0,0 @@
use std::sync::Arc;
use jni::objects::{GlobalRef, JClass, JObject, JString, JValue};
use jni::{JNIEnv, JavaVM};
use spki::der::pem::LineEnding;
use spki::EncodePublicKey;
use vnt::handle::callback::ConnectInfo;
#[cfg(target_os = "android")]
use vnt::handle::callback::DeviceConfig;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
use vnt::DeviceInfo;
use vnt::{ErrorInfo, HandshakeInfo, PeerClientInfo, RegisterInfo, VntCallback};
#[derive(Clone)]
pub struct CallBack {
jvm: Arc<JavaVM>,
this: GlobalRef,
connect_info_class: GlobalRef,
handshake_info_class: GlobalRef,
error_info_class: GlobalRef,
register_info_class: GlobalRef,
#[cfg(target_os = "android")]
device_config_class: GlobalRef,
peer_client_info_class: GlobalRef,
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_info_class: GlobalRef,
}
unsafe impl Send for CallBack {}
fn find_class_global_ref(env: &mut JNIEnv, class: &str) -> jni::errors::Result<GlobalRef> {
let class = env.find_class(class)?;
env.new_global_ref(class)
}
impl CallBack {
pub fn new(jvm: JavaVM, this: GlobalRef) -> jni::errors::Result<Self> {
let mut env = jvm.attach_current_thread_as_daemon()?;
let connect_info_class =
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ConnectInfo")?;
let handshake_info_class =
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/HandshakeInfo")?;
let error_info_class =
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ErrorInfo")?;
let register_info_class =
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/RegisterInfo")?;
#[cfg(target_os = "android")]
let device_config_class = crate::callback::find_class_global_ref(
&mut env,
"top/wherewego/vnt/jni/param/DeviceConfig",
)?;
let peer_client_info_class =
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/PeerClientInfo")?;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let device_info_class =
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/DeviceInfo")?;
Ok(Self {
jvm: Arc::new(jvm),
this,
connect_info_class,
handshake_info_class,
error_info_class,
register_info_class,
#[cfg(target_os = "android")]
device_config_class,
peer_client_info_class,
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_info_class,
})
}
}
impl CallBack {
fn success0(&self) -> jni::errors::Result<()> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
env.call_method(&self.this, "success", "()V", &[])?;
Ok(())
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
fn create_tun0(&self, info: DeviceInfo) -> jni::errors::Result<()> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
let class = unsafe { JClass::from_raw(self.device_info_class.as_raw()) };
let param = env.new_object(
class,
"(Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&env.new_string(info.name)?.into()),
JValue::Object(&env.new_string(info.version)?.into()),
],
)?;
env.call_method(
&self.this,
"createTun",
"(Ltop/wherewego/vnt/jni/param/DeviceInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn connect0(&self, info: ConnectInfo) -> jni::errors::Result<()> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
let class = unsafe { JClass::from_raw(self.connect_info_class.as_raw()) };
let param = env.new_object(
class,
"(JLjava/lang/String;)V",
&[
JValue::Long(info.count as _),
JValue::Object(&env.new_string(info.address.to_string())?.into()),
],
)?;
env.call_method(
&self.this,
"connect",
"(Ltop/wherewego/vnt/jni/param/ConnectInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn handshake0(&self, info: HandshakeInfo) -> jni::errors::Result<bool> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
let public_key = if let Some(public_key) = info.public_key {
match public_key.to_public_key_pem(LineEnding::CRLF) {
Ok(public_key) => env.new_string(public_key)?,
Err(e) => {
log::warn!("{:?}", e);
JString::default()
}
}
} else {
JString::default()
};
let finger = if let Some(finger) = info.finger {
env.new_string(finger)?
} else {
JString::default()
};
let class = unsafe { JClass::from_raw(self.handshake_info_class.as_raw()) };
let param = env.new_object(
class,
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
&[
JValue::Object(&public_key),
JValue::Object(&finger),
JValue::Object(&env.new_string(info.version)?.into()),
],
)?;
let rs = env.call_method(
&self.this,
"handshake",
"(Ltop/wherewego/vnt/jni/param/HandshakeInfo;)Z",
&[JValue::Object(&param)],
)?;
rs.z()
}
fn register0(&self, info: RegisterInfo) -> jni::errors::Result<bool> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
let class = unsafe { JClass::from_raw(self.register_info_class.as_raw()) };
let param = env.new_object(
class,
"(III)V",
&[
JValue::Int(u32::from(info.virtual_ip) as _),
JValue::Int(u32::from(info.virtual_netmask) as _),
JValue::Int(u32::from(info.virtual_gateway) as _),
],
)?;
let rs = env.call_method(
&self.this,
"register",
"(Ltop/wherewego/vnt/jni/param/RegisterInfo;)Z",
&[JValue::Object(&param)],
)?;
rs.z()
}
#[cfg(target_os = "android")]
fn generate_tun0(&self, info: DeviceConfig) -> jni::errors::Result<u32> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
let class = unsafe { JClass::from_raw(self.device_config_class.as_raw()) };
let object_array = env.new_object_array(
info.external_route.len() as _,
"java/lang/String",
JObject::null(),
)?;
for (index, (network, mask)) in info.external_route.into_iter().enumerate() {
let param =
env.new_string(format!("{}/{}", network, u32::from(mask).leading_ones()))?;
env.set_object_array_element(&object_array, index as _, &param)?;
}
let param = env.new_object(
class,
"(IIII[Ljava/lang/String;)V",
&[
JValue::Int(u32::from(info.virtual_ip) as _),
JValue::Int(u32::from(info.virtual_netmask) as _),
JValue::Int(u32::from(info.virtual_gateway) as _),
JValue::Int(u32::from(info.virtual_network) as _),
JValue::Object(&object_array),
],
)?;
let rs = env.call_method(
&self.this,
"generateTun",
"(Ltop/wherewego/vnt/jni/param/DeviceConfig;)I",
&[JValue::Object(&param)],
)?;
rs.i().map(|v| v as _)
}
fn peer_client_list0(&self, info_vec: Vec<PeerClientInfo>) -> jni::errors::Result<()> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
let class = unsafe { JClass::from_raw(self.peer_client_info_class.as_raw()) };
let object_array = env.new_object_array(info_vec.len() as _, &class, JObject::null())?;
for (index, info) in info_vec.into_iter().enumerate() {
let param = env.new_object(
&class,
"(ILjava/lang/String;ZZ)V",
&[
JValue::Int(u32::from(info.virtual_ip) as _),
JValue::Object(&env.new_string(info.name)?.into()),
JValue::Bool(info.status.is_online() as _),
JValue::Bool(info.client_secret as _),
],
)?;
env.set_object_array_element(&object_array, index as _, &param)?;
}
env.call_method(
&self.this,
"peerClientList",
"([Ltop/wherewego/vnt/jni/param/PeerClientInfo;)V",
&[JValue::Object(&object_array)],
)?;
Ok(())
}
fn error0(&self, info: ErrorInfo) -> jni::errors::Result<()> {
let code: u8 = info.code.into();
let mut env = self.jvm.attach_current_thread_as_daemon()?;
let class = unsafe { JClass::from_raw(self.error_info_class.as_raw()) };
let msg = if let Some(msg) = info.msg {
env.new_string(msg)?
} else {
JString::default()
};
let param = env.new_object(
class,
"(ILjava/lang/String;)V",
&[JValue::Int(code as _), JValue::Object(&msg.into())],
)?;
env.call_method(
&self.this,
"error",
"(Ltop/wherewego/vnt/jni/param/ErrorInfo;)V",
&[JValue::Object(&param)],
)?;
Ok(())
}
fn stop0(&self) -> jni::errors::Result<()> {
let mut env = self.jvm.attach_current_thread_as_daemon()?;
env.call_method(&self.this, "stop", "()V", &[])?;
Ok(())
}
}
impl VntCallback for CallBack {
fn success(&self) {
if let Err(e) = self.success0() {
log::warn!("success {:?}", e);
}
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
fn create_tun(&self, info: DeviceInfo) {
if let Err(e) = self.create_tun0(info) {
log::warn!("create_tun {:?}", e);
}
}
fn connect(&self, info: ConnectInfo) {
if let Err(e) = self.connect0(info) {
log::warn!("connect {:?}", e);
}
}
fn handshake(&self, info: HandshakeInfo) -> bool {
self.handshake0(info).unwrap_or_else(|e| {
log::warn!("handshake {:?}", e);
false
})
}
fn register(&self, info: RegisterInfo) -> bool {
self.register0(info).unwrap_or_else(|e| {
log::warn!("register {:?}", e);
false
})
}
#[cfg(target_os = "android")]
fn generate_tun(&self, info: DeviceConfig) -> u32 {
self.generate_tun0(info).unwrap_or_else(|e| {
log::warn!("generate_tun {:?}", e);
0
})
}
fn peer_client_list(&self, info: Vec<PeerClientInfo>) {
if let Err(e) = self.peer_client_list0(info) {
log::warn!("peer_client_list {:?}", e);
}
}
fn error(&self, info: ErrorInfo) {
if let Err(e) = self.error0(info) {
log::warn!("error {:?}", e);
}
}
fn stop(&self) {
if let Err(e) = self.stop0() {
log::warn!("stop {:?}", e);
}
}
}
-131
View File
@@ -1,131 +0,0 @@
use std::str::FromStr;
use jni::errors::Error;
use jni::objects::JObject;
use jni::JNIEnv;
use vnt::channel::punch::PunchModel;
use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
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"))]
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")?;
let device_id = to_string_not_null(env, &config, "deviceId")?;
let password = to_string(env, &config, "password")?;
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 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);
let tcp = env.get_field(&config, "tcp", "Z")?.z()?;
let server_encrypt = env.get_field(&config, "serverEncrypt", "Z")?.z()?;
let use_channel = to_string(env, &config, "useChannel")?;
let finger = env.get_field(&config, "finger", "Z")?.z()?;
let first_latency = env.get_field(&config, "firstLatency", "Z")?.z()?;
let packet_delay = to_integer(env, &config, "packetDelay")?
.map(|v| v as u32)
.unwrap_or_default();
let packet_loss_rate = to_double(env, &config, "packetLossRate")?;
let in_ips = to_string_array(env, &config, "inIps")?;
let out_ips = to_string_array(env, &config, "outIps")?;
let ports =
to_i32_array(env, &config, "ports")?.map(|v| v.into_iter().map(|v| v as u16).collect());
let ip = if let Some(ip) = to_string(env, &config, "ip")? {
match ip.parse() {
Ok(ip) => Some(ip),
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("ip {} err: {}", ip, e),
)
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
None
};
let in_ips = if let Some(in_ips) = in_ips {
match common::args_parse::ips_parse(&in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("in_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let out_ips = if let Some(out_ips) = out_ips {
match common::args_parse::out_ips_parse(&out_ips) {
Ok(out_ips) => out_ips,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("out_ips {}", e))
.expect("throw");
return Err(Error::JavaException);
}
}
} else {
vec![]
};
let cipher_model = match CipherModel::from_str(&cipher_model) {
Ok(cipher_model) => cipher_model,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("cipher_model {}", e))
.expect("throw");
return Err(Error::JavaException);
}
};
#[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"))]
tap,
token,
device_id,
name,
server_address_str,
dns,
stun_server,
in_ips,
out_ips,
password,
mtu,
tcp,
ip,
false,
server_encrypt,
1,
cipher_model,
finger,
PunchModel::from_str(&punch_model.unwrap_or_default()).unwrap_or_default(),
ports,
first_latency,
#[cfg(not(target_os = "android"))]
device_name,
UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(),
packet_loss_rate,
packet_delay,
) {
Ok(config) => config,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return Err(Error::JavaException);
}
};
Ok(config)
}
-4
View File
@@ -1,4 +0,0 @@
pub mod callback;
pub mod config;
pub mod utils;
pub mod vnt;
-131
View File
@@ -1,131 +0,0 @@
use jni::errors::Error;
use jni::objects::{JIntArray, JObject, JObjectArray, JString};
use jni::JNIEnv;
pub fn to_string_not_null(
env: &mut JNIEnv,
config: &JObject,
name: &'static str,
) -> Result<String, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
env.throw_new("java/lang/NullPointerException", name)
.expect("throw");
return Err(Error::NullPtr(name));
}
let binding = JString::from(value);
let value = env.get_string(binding.as_ref())?;
match value.to_str() {
Ok(value) => Ok(value.to_string()),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
pub fn to_string(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<String>, Error> {
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
if value.is_null() {
return Ok(None);
}
let tmp = JString::from(value);
let value = env.get_string(tmp.as_ref())?;
match value.to_str() {
Ok(value) => Ok(Some(value.to_string())),
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
pub fn to_string_array_not_null(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Vec<String>, Error> {
match to_string_array(env, config, name)? {
None => {
env.throw_new("java/lang/NullPointerException", name)
.expect("throw");
return Err(Error::JavaException);
}
Some(rs) => Ok(rs),
}
}
pub fn to_string_array(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Option<Vec<String>>, Error> {
let value = env.get_field(config, name, "[Ljava/lang/String;")?.l()?;
if value.is_null() {
return Ok(None);
}
let arr = JObjectArray::from(value);
let len = env.get_array_length(&arr)?;
let mut rs = Vec::with_capacity(len as usize);
for index in 0..len {
let object = env.get_object_array_element(&arr, index)?;
if object.is_null() {
env.throw_new(
"java/lang/NullPointerException",
format!("{},index={}", name, index),
)
.expect("throw");
return Err(Error::JavaException);
}
match env.get_string(JString::from(object).as_ref())?.to_str() {
Ok(value) => {
rs.push(value.to_string());
}
Err(_) => {
env.throw_new("java/lang/RuntimeException", "not utf-8")
.expect("throw");
return Err(Error::JavaException);
}
}
}
Ok(Some(rs))
}
pub fn to_i32_array(
env: &mut JNIEnv,
config: &JObject,
name: &str,
) -> Result<Option<Vec<i32>>, Error> {
let obj = env.get_field(&config, name, "[I")?.l()?;
if obj.is_null() {
Ok(None)
} else {
let j_arr = JIntArray::from(obj);
let len = env.get_array_length(&j_arr)?;
let mut arr = vec![0i32; len as usize];
env.get_int_array_region(j_arr, 0, &mut arr)?;
Ok(Some(arr))
}
}
pub fn to_integer(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<i32>, Error> {
let value = env.get_field(config, name, "Ljava/lang/Integer;")?.l()?;
if value.is_null() {
return Ok(None);
}
// 调用 intValue
return Ok(Some(
env.call_method(value, "intValue", "()I", &[])?.i()? as _
));
}
pub fn to_double(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<f64>, Error> {
let value = env.get_field(config, name, "Ljava/lang/Double;")?.l()?;
if value.is_null() {
return Ok(None);
}
// 调用 intValue
return Ok(Some(
env.call_method(value, "doubleValue", "()D", &[])?.d()? as _,
));
}
-173
View File
@@ -1,173 +0,0 @@
use std::ptr;
use jni::errors::Error;
use jni::objects::{JClass, JObject, JValue};
use jni::sys::{jint, jlong, jobject, jobjectArray, jsize};
use jni::JNIEnv;
use vnt::channel::Route;
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>,
_class: JClass,
config: JObject,
call_back: JObject<'static>,
) -> jlong {
let jvm = if let Ok(jvm) = env.get_java_vm() {
jvm
} else {
return 0;
};
match crate::config::new_config(&mut env, config) {
Ok(config) => {
let call_back = if let Ok(call_back) = env.new_global_ref(call_back) {
call_back
} else {
return 0;
};
let call_back = match CallBack::new(jvm, call_back) {
Ok(call_back) => call_back,
Err(_) => {
return 0;
}
};
let vnt_util = match Vnt::new(config, call_back) {
Ok(vnt_util) => vnt_util,
Err(e) => {
env.throw_new(
"java/lang/RuntimeException",
format!("vnt start error {}", e),
)
.expect("throw");
return 0;
}
};
let ptr = Box::into_raw(Box::new(vnt_util));
return ptr as jlong;
}
Err(_) => {}
}
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_stop0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut Vnt;
let _ = (&*vnt).stop();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut Vnt;
let _ = (&*vnt).wait();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0(
_env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) {
let vnt = raw_vnt as *mut Vnt;
let _ = Box::from_raw(vnt).stop();
}
#[no_mangle]
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0(
mut env: JNIEnv,
_class: JClass,
raw_vnt: jlong,
) -> jobjectArray {
let vnt = raw_vnt as *mut Vnt;
let vnt = &mut *vnt;
let list = vnt.device_list();
let arr = match env.new_object_array(
list.len() as jsize,
"top/wherewego/vnt/jni/PeerRouteInfo",
JObject::null(),
) {
Ok(arr) => arr,
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
.expect("throw");
return ptr::null_mut();
}
};
for (index, peer) in list.into_iter().enumerate() {
let route = if let Some(route) = vnt.route(&peer.virtual_ip) {
match route_parse(&mut env, route) {
Ok(route) => JObject::from_raw(route),
Err(_) => JObject::null(),
}
} else {
JObject::null()
};
match peer_device_info_parse(&mut env, peer, route) {
Ok(peer) => {
match env.set_object_array_element(&arr, index as jsize, JObject::from_raw(peer)) {
Ok(_) => {}
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
.expect("throw");
return ptr::null_mut();
}
}
}
Err(e) => {
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
.expect("throw");
return ptr::null_mut();
}
}
}
arr.as_raw()
}
fn route_parse(env: &mut JNIEnv, route: Route) -> Result<jobject, Error> {
let rs = env.new_object(
"top/wherewego/vnt/jni/Route",
"(ZLjava/lang/String;BI)V",
&[
JValue::Bool(route.is_tcp as _),
JValue::Object(&env.new_string(route.addr.to_string())?.into()),
JValue::Byte(route.metric as _),
JValue::Int(route.rt as _),
],
)?;
Ok(rs.as_raw())
}
fn peer_device_info_parse(
env: &mut JNIEnv,
peer: PeerDeviceInfo,
route: JObject,
) -> Result<jobject, Error> {
let virtual_ip = u32::from(peer.virtual_ip);
let name = peer.name.to_string();
let status = format!("{:?}", peer.status);
let rs = env.new_object(
"top/wherewego/vnt/jni/PeerRouteInfo",
"(ILjava/lang/String;Ljava/lang/String;Ltop/wherewego/vnt/jni/Route;)V",
&[
JValue::Int(virtual_ip as jint),
JValue::Object(&env.new_string(name)?.into()),
JValue::Object(&env.new_string(status)?.into()),
JValue::Object(&route),
],
)?;
Ok(rs.as_raw())
}
+40 -19
View File
@@ -1,12 +1,12 @@
[package]
name = "vnt"
version = "1.2.9"
version = "1.2.12"
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", optional = true }
packet = { path = "./packet" }
bytes = "1.5.0"
log = "0.4.17"
@@ -17,41 +17,62 @@ parking_lot = "0.12.1"
rand = "0.8.5"
sha2 = { version = "0.10.6", features = ["oid"] }
thiserror = "1.0.37"
protobuf = "3.2.0"
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 }
chacha20poly1305 = { version = "0.10.1", optional = true }
chacha20 = { version = "0.9.1", 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/vnt-dev/rust-openssl", optional = true }
libsm = { git = "https://github.com/vnt-dev/libsm", optional = true }
mio = {version = "0.8.10",features = ["os-poll","net"]}
mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] }
crossbeam-queue = "0.3.11"
anyhow = "1.0.82"
dns-parser = "0.8.0"
tokio = { version = "1.37.0", features = ["full"] }
lz4_flex = { version = "0.11", default-features = false, optional = true }
zstd = { version = "0.13.1", optional = true }
fnv = "1.0.7"
igd = { version = "0.12.1", optional = true }
tokio-tungstenite = { version = "0.23.1", optional = true }
rustls = { version = "0.23.0", features = ["ring"], default-features = false, optional = true }
futures-util = "0.3.30"
[target.'cfg(target_os = "windows")'.dependencies]
libloading = "0.8.0"
[build-dependencies]
protobuf-codegen = "3.2.0"
protobuf-codegen = "=3.2.0"
protoc-bin-vendored = "3.0.0"
cfg_aliases = "0.2.1"
[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", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress", "integrated_tun"]
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"]
chacha20_poly1305 = ["chacha20poly1305", "chacha20"]
server_encrypt = ["aes-gcm", "rsa", "spki"]
ip_proxy = []
port_mapping = []
lz4_compress = ["lz4_flex"]
zstd_compress = ["zstd"]
integrated_tun = ["tun"]
upnp = ["igd"]
ws = ["tokio-tungstenite"]
wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"]
+13
View File
@@ -1,4 +1,17 @@
use cfg_aliases::cfg_aliases;
fn main() {
cfg_aliases! {
cipher: {
any(feature = "aes_gcm",
feature = "chacha20_poly1305",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)},
}
std::fs::create_dir_all("src/proto").unwrap();
protobuf_codegen::Codegen::new()
.pure()
+3
View File
@@ -81,6 +81,9 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> IpV4Packet<B> {
pub fn set_flags(&mut self, flags: u8) {
self.buffer.as_mut()[6] = (self.buffer.as_ref()[6] & 0b11100000) | (flags << 5)
}
pub fn set_ttl(&mut self, ttl: u8) {
self.buffer.as_mut()[8] = ttl
}
fn set_checksum(&mut self, value: u16) {
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
}
+1
View File
@@ -43,6 +43,7 @@ message DeviceInfo {
uint32 device_status = 3;
bool client_secret = 4;
bytes client_secret_hash = 5;
bool wireguard = 6;
}
message DeviceList {
+99 -64
View File
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use fnv::FnvHashMap;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV6, UdpSocket};
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{io, thread};
@@ -11,8 +11,10 @@ use parking_lot::RwLock;
use rand::Rng;
use crate::channel::punch::NatType;
use crate::channel::sender::{AcceptSocketSender, ChannelSender, PacketSender};
use crate::channel::{Route, RouteKey, UseChannelType, DEFAULT_RT};
use crate::channel::sender::{AcceptSocketSender, PacketSender};
use crate::channel::{ConnectProtocol, Route, RouteKey, UseChannelType, DEFAULT_RT};
use crate::protocol::NetPacket;
use crate::util::limit::TrafficMeterMultiAddress;
/// 传输通道上下文,持有udp socket、tcp socket和路由信息
#[derive(Clone)]
@@ -25,10 +27,12 @@ impl ChannelContext {
main_udp_socket: Vec<UdpSocket>,
use_channel_type: UseChannelType,
first_latency: bool,
is_tcp: bool,
protocol: ConnectProtocol,
packet_loss_rate: Option<f64>,
packet_delay: u32,
use_ipv6: bool,
up_traffic_meter: Option<TrafficMeterMultiAddress>,
down_traffic_meter: Option<TrafficMeterMultiAddress>,
) -> Self {
let channel_num = main_udp_socket.len();
assert_ne!(channel_num, 0, "not channel");
@@ -44,23 +48,21 @@ impl ChannelContext {
.unwrap_or(0);
let inner = ContextInner {
main_udp_socket,
sub_udp_socket: RwLock::new(Vec::with_capacity(64)),
tcp_map: RwLock::new(HashMap::with_capacity(64)),
sub_udp_socket: RwLock::new(Vec::new()),
packet_map: RwLock::new(FnvHashMap::default()),
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
is_tcp,
state: AtomicBool::new(true),
protocol,
packet_loss_rate,
packet_delay,
main_index: AtomicUsize::new(0),
use_ipv6,
up_traffic_meter,
down_traffic_meter,
};
Self {
inner: Arc::new(inner),
}
}
pub fn sender(&self) -> ChannelSender {
ChannelSender::new(self.clone())
}
}
impl Deref for ChannelContext {
@@ -72,7 +74,7 @@ impl Deref for ChannelContext {
}
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
pub const SYMMETRIC_CHANNEL_NUM: usize = 100;
pub const SYMMETRIC_CHANNEL_NUM: usize = 84;
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
pub struct ContextInner {
@@ -81,40 +83,34 @@ pub struct ContextInner {
// 对称网络增加的udp socket
sub_udp_socket: RwLock<Vec<UdpSocket>>,
// tcp数据发送器
pub(crate) tcp_map: RwLock<HashMap<SocketAddr, PacketSender>>,
pub(crate) packet_map: RwLock<FnvHashMap<SocketAddr, PacketSender>>,
// 路由信息
pub route_table: RouteTable,
// 是否使用tcp连接服务器
is_tcp: bool,
//状态
state: AtomicBool,
// 使用什么协议连接服务器
protocol: ConnectProtocol,
//控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000
packet_loss_rate: u32,
//控制延迟
packet_delay: u32,
main_index: AtomicUsize,
use_ipv6: bool,
pub(crate) up_traffic_meter: Option<TrafficMeterMultiAddress>,
pub(crate) down_traffic_meter: Option<TrafficMeterMultiAddress>,
}
impl ContextInner {
pub fn use_channel_type(&self) -> UseChannelType {
self.route_table.use_channel_type
}
pub fn is_stop(&self) -> bool {
!self.state.load(Ordering::Acquire)
}
pub fn stop(&self) {
self.state.store(false, Ordering::Release);
}
/// 通过sub_udp_socket是否为空来判断是否为锥形网络
pub fn is_cone(&self) -> bool {
self.sub_udp_socket.read().is_empty()
}
pub fn is_main_tcp(&self) -> bool {
self.is_tcp
pub fn main_protocol(&self) -> ConnectProtocol {
self.protocol
}
pub fn is_udp_main(&self, route_key: &RouteKey) -> bool {
!route_key.is_tcp() && route_key.index < self.main_udp_socket.len()
route_key.protocol().is_udp() && route_key.index < self.main_udp_socket.len()
}
pub fn first_latency(&self) -> bool {
self.route_table.first_latency
@@ -169,7 +165,7 @@ impl ContextInner {
Ok(ports)
}
pub fn send_tcp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
if let Some(tcp) = self.tcp_map.read().get(&addr) {
if let Some(tcp) = self.packet_map.read().get(&addr) {
tcp.try_send(buf)
} else {
Err(io::Error::from(io::ErrorKind::NotFound))
@@ -191,13 +187,20 @@ impl ContextInner {
Ok(())
}
/// 将数据发送到默认通道,一般发往服务器才用此方法
pub fn send_default(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
if self.is_tcp {
//服务端地址只在重连时检测变化
self.send_tcp(buf, addr)
pub fn send_default<B: AsRef<[u8]>>(
&self,
buf: &NetPacket<B>,
addr: SocketAddr,
) -> io::Result<()> {
if self.protocol.is_udp() {
self.send_main_udp(self.main_index.load(Ordering::Relaxed), buf.buffer(), addr)?
} else {
self.send_main_udp(self.main_index.load(Ordering::Relaxed), buf, addr)
self.send_tcp(buf.buffer(), addr)?
}
if let Some(up_traffic_meter) = &self.up_traffic_meter {
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
}
Ok(())
}
pub fn change_main_index(&self) {
@@ -211,7 +214,7 @@ impl ContextInner {
if let Err(e) = udp.send_to(buf, addr) {
log::warn!("{:?},add={:?}", e, addr);
}
thread::sleep(Duration::from_millis(1));
thread::sleep(Duration::from_millis(3));
}
}
pub fn try_send_all_main(&self, buf: &[u8], addr: SocketAddr) {
@@ -222,9 +225,9 @@ impl ContextInner {
}
}
/// 发送网络数据
pub fn send_ipv4_by_id(
pub fn send_ipv4_by_id<B: AsRef<[u8]>>(
&self,
buf: &[u8],
buf: &NetPacket<B>,
id: &Ipv4Addr,
server_addr: SocketAddr,
send_default: bool,
@@ -234,6 +237,7 @@ impl ContextInner {
return Ok(());
}
}
if self.packet_delay > 0 {
thread::sleep(Duration::from_millis(self.packet_delay as _));
}
@@ -250,7 +254,7 @@ impl ContextInner {
Ok(())
}
/// 将数据发到指定id
pub fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<()> {
pub fn send_by_id<B: AsRef<[u8]>>(&self, buf: &NetPacket<B>, id: &Ipv4Addr) -> io::Result<()> {
let mut c = 0;
loop {
let route = self.route_table.get_route_by_id(c, id)?;
@@ -270,25 +274,35 @@ impl ContextInner {
}
}
/// 将数据发到指定路由
pub fn send_by_key(&self, buf: &[u8], route_key: RouteKey) -> io::Result<()> {
if route_key.is_tcp {
self.send_tcp(buf, route_key.addr)
} else {
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
main_udp.send_to(buf, route_key.addr)?;
} else {
if let Some(udp) = self
.sub_udp_socket
.read()
.get(route_key.index - self.main_udp_socket.len())
{
udp.send_to(buf, route_key.addr)?;
pub fn send_by_key<B: AsRef<[u8]>>(
&self,
buf: &NetPacket<B>,
route_key: RouteKey,
) -> io::Result<()> {
match route_key.protocol() {
ConnectProtocol::UDP => {
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
main_udp.send_to(buf.buffer(), route_key.addr)?;
} else {
Err(io::Error::from(io::ErrorKind::NotFound))?
if let Some(udp) = self
.sub_udp_socket
.read()
.get(route_key.index - self.main_udp_socket.len())
{
udp.send_to(buf.buffer(), route_key.addr)?;
} else {
Err(io::Error::from(io::ErrorKind::NotFound))?
}
}
}
Ok(())
ConnectProtocol::TCP | ConnectProtocol::WS | ConnectProtocol::WSS => {
self.send_tcp(buf.buffer(), route_key.addr)?
}
}
if let Some(up_traffic_meter) = &self.up_traffic_meter {
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
}
Ok(())
}
pub fn remove_route(&self, ip: &Ipv4Addr, route_key: RouteKey) {
self.route_table.remove_route(ip, route_key)
@@ -297,7 +311,7 @@ impl ContextInner {
pub struct RouteTable {
pub(crate) route_table:
RwLock<HashMap<Ipv4Addr, (AtomicUsize, Vec<(Route, AtomicCell<Instant>)>)>>,
RwLock<FnvHashMap<Ipv4Addr, (AtomicUsize, Vec<(Route, AtomicCell<Instant>)>)>>,
first_latency: bool,
channel_num: usize,
use_channel_type: UseChannelType,
@@ -306,7 +320,7 @@ pub struct RouteTable {
impl RouteTable {
fn new(use_channel_type: UseChannelType, first_latency: bool, channel_num: usize) -> Self {
Self {
route_table: RwLock::new(HashMap::with_capacity(64)),
route_table: RwLock::new(FnvHashMap::with_capacity_and_hasher(64, Default::default())),
use_channel_type,
first_latency,
channel_num,
@@ -324,24 +338,33 @@ impl RouteTable {
} else {
let len = v.len();
if len != 0 {
return Ok(v[index % len].0);
let route = &v[index % len].0;
// 跳过默认rt的路由(一般是刚加入的),这有助于提升稳定性
if route.rt != DEFAULT_RT {
return Ok(*route);
}
for (route, _) in v {
if route.rt != DEFAULT_RT {
return Ok(*route);
}
}
}
}
}
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
}
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) {
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) -> bool {
self.add_route_(id, route, true)
}
pub fn add_route(&self, id: Ipv4Addr, route: Route) {
pub fn add_route(&self, id: Ipv4Addr, route: Route) -> bool {
self.add_route_(id, route, false)
}
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) {
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) -> bool {
// 限制通道类型
match self.use_channel_type {
UseChannelType::P2p => {
if !route.is_p2p() {
return;
return false;
}
}
_ => {}
@@ -349,10 +372,18 @@ impl RouteTable {
let key = route.route_key();
if only_if_absent {
if let Some((_, list)) = self.route_table.read().get(&id) {
let mut p2p_num = 0;
for (x, _) in list {
if x.route_key() == key {
return;
if x.is_p2p() {
p2p_num += 1;
}
if x.route_key() == key {
return true;
}
}
if !self.first_latency && p2p_num >= self.channel_num {
// 非优先延迟的情况下,通道满了则不用再添加
return false;
}
}
}
@@ -364,11 +395,11 @@ impl RouteTable {
for (x, time) in list.iter_mut() {
if x.metric < route.metric && !self.first_latency {
//非优先延迟的情况下 不能比当前的路径更长
return;
return false;
}
if x.route_key() == key {
if only_if_absent {
return;
return true;
}
x.metric = route.metric;
x.rt = route.rt;
@@ -383,7 +414,7 @@ impl RouteTable {
//如果延迟都稳定了,则去除多余通道
for (route, _) in list.iter() {
if route.rt == DEFAULT_RT {
return;
return true;
}
}
//延迟优先模式需要更多的通道探测延迟最低的路线
@@ -399,6 +430,9 @@ impl RouteTable {
//非优先延迟的情况下 添加了直连的则排除非直连的
list.retain(|(k, _)| k.is_p2p());
}
if self.channel_num <= list.len() {
return false;
}
};
//增加路由表容量,避免波动
let limit_len = self.channel_num * 2;
@@ -406,6 +440,7 @@ impl RouteTable {
self.truncate_(list, limit_len);
list.push((route, AtomicCell::new(Instant::now())));
}
return true;
}
fn truncate_(&self, list: &mut Vec<(Route, AtomicCell<Instant>)>, len: usize) {
if list.len() <= len {
+8 -2
View File
@@ -1,6 +1,12 @@
use crate::channel::context::ChannelContext;
use crate::channel::RouteKey;
pub trait RecvChannelHandler: Clone + Send + 'static {
fn handle(&mut self, buf: &mut [u8], route_key: RouteKey, context: &ChannelContext);
pub trait RecvChannelHandler: Clone + Send + Sync + 'static {
fn handle(
&self,
buf: &mut [u8],
extend: &mut [u8],
route_key: RouteKey,
context: &ChannelContext,
);
}
+1 -1
View File
@@ -39,7 +39,7 @@ impl Idle {
}
}
}
let sleep_time = self.read_idle - max;
let sleep_time = self.read_idle.checked_sub(max).unwrap_or_default();
return IdleType::Sleep(sleep_time);
}
}
+110 -49
View File
@@ -1,13 +1,17 @@
use std::io;
use anyhow::Context;
use std::net::{SocketAddr, UdpSocket};
use std::str::FromStr;
use tokio::sync::mpsc::channel;
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::sender::AcceptSocketSender;
use crate::channel::sender::{AcceptSocketSender, ConnectUtil};
use crate::channel::tcp_channel::tcp_listen;
use crate::channel::udp_channel::udp_listen;
use crate::util::{io_convert, StopManager};
#[cfg(feature = "ws")]
use crate::channel::ws_channel::ws_connect_accept;
use crate::util::limit::TrafficMeterMultiAddress;
use crate::util::StopManager;
pub mod context;
pub mod handler;
@@ -17,14 +21,21 @@ pub mod punch;
pub mod sender;
pub mod tcp_channel;
pub mod udp_channel;
#[cfg(feature = "ws")]
pub mod ws_channel;
pub const BUFFER_SIZE: usize = 1024 * 64;
// 这里留个坑,tcp是支持_TCP_MAX_PACKET_SIZE长度的,
// 但是缓存只用BUFFER_SIZE,会导致多余的数据接收不了
const TCP_MAX_PACKET_SIZE: usize = (1 << 24) - 1;
const BUFFER_SIZE: usize = 1024 * 16;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum UseChannelType {
Relay,
P2p,
All,
}
impl UseChannelType {
pub fn is_only_relay(&self) -> bool {
self == &UseChannelType::Relay
@@ -36,6 +47,7 @@ impl UseChannelType {
self == &UseChannelType::All
}
}
impl FromStr for UseChannelType {
type Err = String;
@@ -48,15 +60,49 @@ impl FromStr for UseChannelType {
}
}
}
impl Default for UseChannelType {
fn default() -> Self {
UseChannelType::All
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ConnectProtocol {
UDP,
TCP,
WS,
WSS,
}
impl ConnectProtocol {
#[inline]
pub fn is_tcp(&self) -> bool {
self == &ConnectProtocol::TCP
}
#[inline]
pub fn is_udp(&self) -> bool {
self == &ConnectProtocol::UDP
}
#[inline]
pub fn is_ws(&self) -> bool {
self == &ConnectProtocol::WS
}
#[inline]
pub fn is_wss(&self) -> bool {
self == &ConnectProtocol::WSS
}
pub fn is_transport(&self) -> bool {
self.is_tcp() || self.is_udp()
}
pub fn is_base_tcp(&self) -> bool {
self.is_tcp() || self.is_ws() || self.is_wss()
}
}
#[derive(Copy, Clone, Debug)]
pub struct Route {
pub is_tcp: bool,
pub protocol: ConnectProtocol,
index: usize,
pub addr: SocketAddr,
pub metric: u8,
@@ -68,11 +114,19 @@ pub struct RouteSortKey {
pub metric: u8,
pub rt: i64,
}
const DEFAULT_RT: i64 = 999;
const DEFAULT_RT: i64 = 9999;
impl Route {
pub fn new(is_tcp: bool, index: usize, addr: SocketAddr, metric: u8, rt: i64) -> Self {
pub fn new(
protocol: ConnectProtocol,
index: usize,
addr: SocketAddr,
metric: u8,
rt: i64,
) -> Self {
Self {
is_tcp,
protocol,
index,
addr,
metric,
@@ -81,7 +135,7 @@ impl Route {
}
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
Self {
is_tcp: route_key.is_tcp,
protocol: route_key.protocol,
index: route_key.index,
addr: route_key.addr,
metric,
@@ -90,7 +144,7 @@ impl Route {
}
pub fn from_default_rt(route_key: RouteKey, metric: u8) -> Self {
Self {
is_tcp: route_key.is_tcp,
protocol: route_key.protocol,
index: route_key.index,
addr: route_key.addr,
metric,
@@ -99,7 +153,7 @@ impl Route {
}
pub fn route_key(&self) -> RouteKey {
RouteKey {
is_tcp: self.is_tcp,
protocol: self.protocol,
index: self.index,
addr: self.addr,
}
@@ -117,35 +171,39 @@ impl Route {
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub struct RouteKey {
is_tcp: bool,
protocol: ConnectProtocol,
index: usize,
pub addr: SocketAddr,
}
impl RouteKey {
pub(crate) fn new(is_tcp: bool, index: usize, addr: SocketAddr) -> Self {
pub(crate) fn new(protocol: ConnectProtocol, index: usize, addr: SocketAddr) -> Self {
Self {
is_tcp,
protocol,
index,
addr,
}
}
pub fn is_tcp(&self) -> bool {
self.is_tcp
#[inline]
pub fn protocol(&self) -> ConnectProtocol {
self.protocol
}
#[inline]
pub fn index(&self) -> usize {
self.index
}
}
pub fn init_context(
pub(crate) fn init_context(
ports: Vec<u16>,
use_channel_type: UseChannelType,
first_latency: bool,
is_tcp: bool,
protocol: ConnectProtocol,
packet_loss_rate: Option<f64>,
packet_delay: u32,
) -> io::Result<(ChannelContext, mio::net::TcpListener)> {
up_traffic_meter: Option<TrafficMeterMultiAddress>,
down_traffic_meter: Option<TrafficMeterMultiAddress>,
) -> anyhow::Result<(ChannelContext, std::net::TcpListener)> {
assert!(!ports.is_empty(), "not channel");
let mut udps = Vec::with_capacity(ports.len());
//检查系统是否支持ipv6
@@ -161,9 +219,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 +230,12 @@ 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_recv_buffer_size(2 * 1024 * 1024) {
log::warn!("set_recv_buffer_size {:?}", e);
}
socket
.bind(&address.into())
.with_context(|| format!("bind failed: {}", &address))?;
let main_channel: UdpSocket = socket.into();
udps.push(main_channel);
}
@@ -189,10 +243,12 @@ pub fn init_context(
udps,
use_channel_type,
first_latency,
is_tcp,
protocol,
packet_loss_rate,
packet_delay,
use_ipv6,
up_traffic_meter,
down_traffic_meter,
);
let port = context.main_local_udp_port()?[0];
@@ -200,9 +256,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,43 +275,48 @@ 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)?;
socket.set_nonblocking(true)?;
socket.set_nodelay(false)?;
let tcp_listener = mio::net::TcpListener::from_std(socket.into());
Ok((context, tcp_listener))
Ok((context, socket.into()))
}
pub fn init_channel<H>(
tcp_listener: mio::net::TcpListener,
pub(crate) fn init_channel<H>(
tcp_listener: std::net::TcpListener,
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>>)>,
ConnectUtil,
)>
where
H: RecvChannelHandler,
{
let (tcp_connect_s, tcp_connect_r) = channel(16);
let (ws_connect_s, _ws_connect_r) = channel(16);
let connect_util = ConnectUtil::new(tcp_connect_s, ws_connect_s);
// udp监听,udp_socket_sender 用于NAT类型切换
let udp_socket_sender =
udp_listen(stop_manager.clone(), recv_handler.clone(), context.clone())?;
// 建立tcp监听,tcp_socket_sender 用于tcp 直连
let tcp_socket_sender = tcp_listen(
tcp_listen(
tcp_listener,
stop_manager.clone(),
tcp_connect_r,
recv_handler.clone(),
context.clone(),
stop_manager.clone(),
)?;
#[cfg(feature = "ws")]
ws_connect_accept(_ws_connect_r, recv_handler, context.clone(), stop_manager)?;
Ok((udp_socket_sender, tcp_socket_sender))
Ok((udp_socket_sender, connect_util))
}
+43 -55
View File
@@ -1,16 +1,19 @@
use crossbeam_utils::atomic::AtomicCell;
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::ops::{Div, Mul};
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
use mio::net::TcpStream;
use rand::prelude::SliceRandom;
use rand::Rng;
use crate::channel::context::ChannelContext;
use crate::channel::sender::AcceptSocketSender;
use crate::channel::sender::ConnectUtil;
use crate::external_route::ExternalRoute;
use crate::handle::CurrentDeviceInfo;
use crate::nat::NatTest;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
@@ -47,7 +50,7 @@ pub struct NatInfo {
pub nat_type: NatType,
pub(crate) local_ipv4: Option<Ipv4Addr>,
pub(crate) ipv6: Option<Ipv6Addr>,
pub(crate) udp_ports: Vec<u16>,
pub udp_ports: Vec<u16>,
pub tcp_port: u16,
}
@@ -99,26 +102,25 @@ impl NatInfo {
nat_type,
}
}
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) {
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
let mut updated = false;
if port != 0 {
if let Some(public_port) = self.public_ports.get_mut(index) {
if *public_port != port {
log::info!("端口变化={}:{}", ip, port)
updated = true;
log::info!("端口变化={}:{} index={}", ip, port, index)
}
*public_port = port;
}
}
if !ip.is_multicast()
&& !ip.is_broadcast()
&& !ip.is_unspecified()
&& !ip.is_loopback()
&& !ip.is_private()
{
if crate::nat::is_ipv4_global(&ip) {
if !self.public_ips.contains(&ip) {
self.public_ips.push(ip);
updated = true;
log::info!("ip变化={},{:?}", ip, self.public_ips)
}
}
updated
}
pub fn local_ipv4(&self) -> Option<Ipv4Addr> {
self.local_ipv4
@@ -186,9 +188,10 @@ pub struct Punch {
port_index: HashMap<Ipv4Addr, usize>,
punch_model: PunchModel,
is_tcp: bool,
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
connect_util: ConnectUtil,
external_route: ExternalRoute,
nat_test: NatTest,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
}
impl Punch {
@@ -196,9 +199,10 @@ impl Punch {
context: ChannelContext,
punch_model: PunchModel,
is_tcp: bool,
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
connect_util: ConnectUtil,
external_route: ExternalRoute,
nat_test: NatTest,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
) -> Self {
let mut port_vec: Vec<u16> = (1..65535).collect();
port_vec.push(65535);
@@ -210,34 +214,20 @@ impl Punch {
port_index: HashMap::new(),
punch_model,
is_tcp,
tcp_socket_sender,
connect_util,
external_route,
nat_test,
current_device,
}
}
}
impl Punch {
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) -> bool {
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) {
if self.nat_test.is_local_address(true, addr) {
return false;
return;
}
// mio是非阻塞的,不能立马判断是否能连接成功,所以用标准库的tcp
match std::net::TcpStream::connect_timeout(&addr, Duration::from_millis(100)) {
Ok(tcp_stream) => {
if tcp_stream.set_nonblocking(true).is_err() {
return false;
}
return self
.tcp_socket_sender
.try_add_socket((TcpStream::from_std(tcp_stream), addr, Some(buf.to_vec())))
.is_ok();
}
Err(e) => {
log::warn!("连接到tcp失败,addr={},err={}", addr, e);
}
}
false
self.connect_util.try_connect_tcp(buf.to_vec(), addr);
}
pub fn punch(
&mut self,
@@ -245,19 +235,21 @@ impl Punch {
id: Ipv4Addr,
mut nat_info: NatInfo,
punch_tcp: bool,
count: usize,
) -> io::Result<()> {
if self.context.route_table.no_need_punch(&id) {
log::info!("已打洞成功,无需打洞:{:?}", id);
return Ok(());
}
nat_info
.public_ips
.retain(|ip| self.external_route.route(&ip).is_none());
nat_info
.local_ipv4
.filter(|ip| self.external_route.route(&ip).is_none());
let device_info = self.current_device.load();
nat_info.public_ips.retain(|ip| {
self.external_route.route(ip).is_none() && device_info.not_in_network(*ip)
});
nat_info.local_ipv4.filter(|ip| {
self.external_route.route(ip).is_none() && device_info.not_in_network(*ip)
});
nat_info.ipv6.filter(|ip| {
if let Some(ip) = ip.to_ipv4_mapped() {
if let Some(ip) = ip.to_ipv4() {
self.external_route.route(&ip).is_none()
} else {
true
@@ -266,22 +258,15 @@ impl Punch {
if punch_tcp && self.is_tcp && nat_info.tcp_port != 0 {
//向tcp发起连接
if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() {
if self.connect_tcp(buf, ipv6_addr) {
// return Ok(());
}
self.connect_tcp(buf, ipv6_addr)
}
//向tcp发起连接
if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() {
if self.connect_tcp(buf, ipv4_addr) {
// return Ok(());
}
self.connect_tcp(buf, ipv4_addr)
}
if nat_info.nat_type == NatType::Cone && nat_info.public_ips.len() == 1 {
let addr =
SocketAddr::V4(SocketAddrV4::new(nat_info.public_ips[0], nat_info.tcp_port));
if self.connect_tcp(buf, addr) {
// return Ok(());
}
for ip in &nat_info.public_ips {
let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.tcp_port));
self.connect_tcp(buf, addr)
}
}
let channel_num = self.context.channel_num();
@@ -316,7 +301,11 @@ impl Punch {
//预测范围内最多发送max_k1个包
let max_k1 = 60;
//全局最多发送max_k2个包
let max_k2 = rand::thread_rng().gen_range(600..800);
let mut max_k2: usize = rand::thread_rng().gen_range(600..800);
if count > 2 {
//递减探测规模
max_k2 = max_k2.mul(2).div(count).max(max_k1 as usize);
}
let port = nat_info.public_ports.get(0).map(|e| *e).unwrap_or(0);
if nat_info.public_port_range < max_k1 * 3 {
//端口变化不大时,在预测的范围内随机发送
@@ -332,8 +321,7 @@ impl Punch {
} else {
(max_port - min_port + 1) as usize
};
let mut nums: Vec<u16> = (min_port..max_port).collect();
nums.push(max_port);
let mut nums: Vec<u16> = (min_port..=max_port).collect();
nums.shuffle(&mut rand::thread_rng());
self.punch_symmetric(&nums[..k], buf, &nat_info.public_ips, max_k1 as usize)?;
}
@@ -397,7 +385,7 @@ impl Punch {
}
let addr = SocketAddr::V4(SocketAddrV4::new(*pub_ip, *port));
self.context.send_main_udp(0, buf, addr)?;
thread::sleep(Duration::from_millis(2));
thread::sleep(Duration::from_millis(3));
}
}
Ok(ports.len())
+212 -51
View File
@@ -1,31 +1,190 @@
use std::collections::HashMap;
use std::io;
use std::ops::Deref;
use std::net::{Ipv4Addr, SocketAddr};
use std::sync::mpsc::{SyncSender, TrySendError};
use std::sync::Arc;
use mio::Token;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tokio::sync::mpsc::Sender;
use crate::channel::context::ChannelContext;
use crate::channel::notify::{AcceptNotify, WritableNotify};
use crate::channel::notify::AcceptNotify;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
use crate::protocol;
use crate::protocol::{ip_turn_packet, NetPacket};
#[derive(Clone)]
pub struct ChannelSender {
pub struct IpPacketSender {
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
compressor: Compressor,
client_cipher: Cipher,
server_cipher: Cipher,
ip_route: ExternalRoute,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
allow_wire_guard: bool,
}
impl ChannelSender {
pub fn new(context: ChannelContext) -> Self {
Self { context }
impl IpPacketSender {
pub fn new(
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
compressor: Compressor,
client_cipher: Cipher,
server_cipher: Cipher,
ip_route: ExternalRoute,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
allow_wire_guard: bool,
) -> Self {
Self {
context,
current_device,
compressor,
client_cipher,
server_cipher,
ip_route,
device_map,
allow_wire_guard,
}
}
pub fn self_virtual_ip(&self) -> Ipv4Addr {
self.current_device.load().virtual_ip
}
pub fn send_ip(
&self,
buf: &mut [u8],
data_len: usize,
auxiliary_buf: &mut [u8],
mut dest_ip: Ipv4Addr,
) -> anyhow::Result<()> {
let device_info = self.current_device.load();
let src_ip = device_info.virtual_ip;
if src_ip.is_unspecified() {
return Ok(());
}
if let Some(v) = self.ip_route.route(&dest_ip) {
dest_ip = v;
}
if dest_ip.is_multicast() {
//广播
dest_ip = Ipv4Addr::BROADCAST;
}
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 self.allow_wire_guard {
if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip {
let exists_wg = self
.device_map
.lock()
.1
.values()
.any(|v| v.status.is_online() && v.wireguard);
if exists_wg {
send_to_wg_broadcast(
&self.context,
&net_packet,
&self.server_cipher,
&device_info,
)?;
}
} else {
let guard = self.device_map.lock();
if let Some(peer_info) = guard.1.get(&dest_ip) {
if peer_info.wireguard {
if peer_info.status.is_offline() {
return Ok(());
}
drop(guard);
send_to_wg(
&self.context,
&mut net_packet,
&self.server_cipher,
&device_info,
)?;
return Ok(());
}
}
}
}
let mut auxiliary = NetPacket::new(auxiliary_buf)?;
let mut net_packet = if self.compressor.compress(&net_packet, &mut auxiliary)? {
auxiliary.set_default_version();
auxiliary.set_protocol(protocol::Protocol::IpTurn);
auxiliary.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
auxiliary.first_set_ttl(6);
auxiliary.set_source(src_ip);
auxiliary.set_destination(dest_ip);
auxiliary
} else {
net_packet
};
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip {
//走服务端广播
self.context
.send_default(&net_packet, device_info.connect_server)?;
return Ok(());
}
if device_info.not_in_network(dest_ip) {
//不是一个网段的直接忽略
return Ok(());
}
self.context.send_ipv4_by_id(
&net_packet,
&dest_ip,
device_info.connect_server,
device_info.status.online(),
)?;
Ok(())
}
}
impl Deref for ChannelSender {
type Target = ChannelContext;
pub fn send_to_wg_broadcast(
sender: &ChannelContext,
net_packet: &NetPacket<&mut [u8]>,
server_cipher: &Cipher,
current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()> {
let mut copy_packet = NetPacket::new0(net_packet.data_len(), [0; 65536])?;
copy_packet.set_default_version();
copy_packet.set_protocol(protocol::Protocol::IpTurn);
copy_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into());
copy_packet.first_set_ttl(6);
copy_packet.set_source(net_packet.source());
copy_packet.set_destination(net_packet.destination());
copy_packet.set_gateway_flag(true);
copy_packet.set_payload(net_packet.payload())?;
server_cipher.encrypt_ipv4(&mut copy_packet)?;
sender.send_default(&copy_packet, current_device.connect_server)?;
fn deref(&self) -> &Self::Target {
&self.context
}
Ok(())
}
pub fn send_to_wg(
sender: &ChannelContext,
net_packet: &mut NetPacket<&mut [u8]>,
server_cipher: &Cipher,
current_device: &CurrentDeviceInfo,
) -> anyhow::Result<()> {
net_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into());
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(net_packet)?;
sender.send_default(&net_packet, current_device.connect_server)?;
Ok(())
}
pub struct AcceptSocketSender<T> {
sender: SyncSender<T>,
notify: AcceptNotify,
@@ -39,6 +198,7 @@ impl<T> Clone for AcceptSocketSender<T> {
}
}
}
impl<T> AcceptSocketSender<T> {
pub fn new(notify: AcceptNotify, sender: SyncSender<T>) -> Self {
Self { sender, notify }
@@ -53,53 +213,54 @@ impl<T> AcceptSocketSender<T> {
}
}
}
#[derive(Clone)]
pub struct PacketSender {
inner: Arc<PacketSenderInner>,
sender: Sender<Vec<u8>>,
}
impl PacketSender {
pub fn new(notify: WritableNotify, buffer: SyncSender<Vec<u8>>, token: Token) -> Self {
Self {
inner: Arc::new(PacketSenderInner {
token,
notify,
buffer,
}),
}
pub fn new(sender: Sender<Vec<u8>>) -> Self {
Self { sender }
}
#[inline]
pub fn try_send(&self, buf: &[u8]) -> io::Result<()> {
self.inner.try_send(buf)
}
pub fn shutdown(&self) -> io::Result<()> {
self.inner.shutdown()
}
}
pub struct PacketSenderInner {
token: Token,
notify: WritableNotify,
buffer: SyncSender<Vec<u8>>,
}
impl PacketSenderInner {
#[inline]
fn try_send(&self, buf: &[u8]) -> io::Result<()> {
let len = buf.len();
let mut buf_vec = Vec::with_capacity(buf.len() + 4);
buf_vec.extend_from_slice(&[0, 0, (len >> 8) as u8, (len & 0xFF) as u8]);
buf_vec.extend_from_slice(buf);
match self.buffer.try_send(buf_vec) {
Ok(_) => self.notify.notify(self.token, true),
Err(e) => match e {
TrySendError::Disconnected(_) => Err(io::Error::from(io::ErrorKind::WriteZero)),
TrySendError::Full(_) => Err(io::Error::from(io::ErrorKind::WouldBlock)),
},
match self.sender.try_send(buf.to_vec()) {
Ok(_) => Ok(()),
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Err(io::Error::new(
io::ErrorKind::WouldBlock,
"通道已满,发生丢包",
)),
Err(_) => Err(io::Error::new(
io::ErrorKind::ConnectionRefused,
"通道关闭,发生丢包",
)),
}
}
fn shutdown(&self) -> io::Result<()> {
self.notify.notify(self.token, false)
}
#[derive(Clone)]
pub struct ConnectUtil {
connect_tcp: Sender<(Vec<u8>, SocketAddr)>,
connect_ws: Sender<(Vec<u8>, String)>,
}
impl ConnectUtil {
pub fn new(
connect_tcp: Sender<(Vec<u8>, SocketAddr)>,
connect_ws: Sender<(Vec<u8>, String)>,
) -> Self {
Self {
connect_tcp,
connect_ws,
}
}
pub fn try_connect_tcp(&self, buf: Vec<u8>, addr: SocketAddr) {
if self.connect_tcp.try_send((buf, addr)).is_err() {
log::warn!("try_connect_tcp failed {}", addr);
}
}
pub fn try_connect_ws(&self, buf: Vec<u8>, addr: String) {
if self.connect_ws.try_send((buf, addr)).is_err() {
log::warn!("try_connect_ws failed");
}
}
}
+150 -420
View File
@@ -1,456 +1,186 @@
use std::collections::HashMap;
use std::io::{Read, Write};
use std::net::{Shutdown, SocketAddr};
#[cfg(any(unix))]
use std::os::fd::FromRawFd;
#[cfg(any(unix))]
use std::os::fd::IntoRawFd;
#[cfg(windows)]
use std::os::windows::io::FromRawSocket;
#[cfg(windows)]
use std::os::windows::io::IntoRawSocket;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError, TrySendError};
use std::{io, thread};
use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interest, Poll, Registry, Token, Waker};
use anyhow::{anyhow, Context};
use std::net::SocketAddr;
use std::thread;
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::tcp::OwnedReadHalf;
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::mpsc::{channel, Receiver};
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::notify::{AcceptNotify, WritableNotify};
use crate::channel::sender::{AcceptSocketSender, PacketSender};
use crate::channel::{RouteKey, BUFFER_SIZE};
use crate::channel::sender::PacketSender;
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE, TCP_MAX_PACKET_SIZE};
use crate::util::StopManager;
const SERVER: Token = Token(0);
const NOTIFY: Token = Token(1);
/// 监听tcp端口,等待客户端连接
pub fn tcp_listen<H>(
tcp_server: TcpListener,
stop_manager: StopManager,
tcp_server: std::net::TcpListener,
receiver: Receiver<(Vec<u8>, SocketAddr)>,
recv_handler: H,
context: ChannelContext,
) -> io::Result<AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>>
where
H: RecvChannelHandler,
{
let (tcp_sender, tcp_receiver) = sync_channel(64);
let poll = Poll::new()?;
let waker = AcceptNotify::new(Waker::new(poll.registry(), NOTIFY)?);
let accept = AcceptSocketSender::new(waker.clone(), tcp_sender);
let worker = {
let waker = waker.clone();
stop_manager.add_listener("tcp_listen".into(), move || {
if let Err(e) = waker.stop() {
log::error!("{:?}", e);
}
})?
};
thread::Builder::new()
.name("tcpRead".into())
.spawn(move || {
if let Err(e) = tcp_listen0(
poll,
tcp_server,
&stop_manager,
waker,
tcp_receiver,
recv_handler,
context,
) {
log::error!("{:?}", e);
}
worker.stop_all();
})?;
Ok(accept)
}
fn tcp_listen0<H>(
mut poll: Poll,
mut tcp_server: TcpListener,
stop_manager: &StopManager,
accept_notify: AcceptNotify,
accept_tcp_receiver: Receiver<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
mut recv_handler: H,
context: ChannelContext,
) -> io::Result<()>
where
H: RecvChannelHandler,
{
let (tcp_sender, tcp_receiver) = sync_channel(64);
let write_waker = init_writable_handler(tcp_receiver, stop_manager.clone(), context.clone())?;
poll.registry()
.register(&mut tcp_server, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(1024);
let mut read_map: HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)> =
HashMap::with_capacity(32);
loop {
poll.poll(&mut events, None)?;
for event in events.iter() {
match event.token() {
SERVER => loop {
match tcp_server.accept() {
Ok((stream, addr)) => {
accept_handle(
stream,
addr,
None,
&write_waker,
&mut read_map,
&tcp_sender,
poll.registry(),
)?;
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
},
NOTIFY => {
if accept_notify.is_stop() {
return Ok(());
}
if accept_notify.is_add_socket() {
while let Ok((stream, addr, init_buf)) = accept_tcp_receiver.try_recv() {
accept_handle(
stream,
addr,
init_buf,
&write_waker,
&mut read_map,
&tcp_sender,
poll.registry(),
)?;
}
}
}
token => {
if event.is_readable() {
if let Err(e) =
readable_handle(&token, &mut read_map, &mut recv_handler, &context)
{
closed_handle_r(&token, &mut read_map);
log::warn!("{:?}", e);
if let Err(e) = write_waker.notify(token, false) {
log::warn!("{:?}", e);
}
}
} else {
closed_handle_r(&token, &mut read_map);
if let Err(e) = write_waker.notify(token, false) {
log::warn!("{:?}", e);
}
}
}
}
}
}
}
/// 处理写事件
fn init_writable_handler(
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
stop_manager: StopManager,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("tcpChannel".into(), move || {
let _ = stop_sender.send(());
})?;
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.context("tcp tokio runtime build failed")?;
thread::Builder::new()
.name("tcpChannel".into())
.spawn(move || {
runtime.spawn(async move {
{
let recv_handler = recv_handler.clone();
let context = context.clone();
tokio::spawn(async move {
if let Err(e) = tcp_accept(tcp_server, recv_handler, context).await {
log::warn!("tcp_listen {:?}", e);
}
});
}
tokio::spawn(
async move { connect_tcp_handle(receiver, recv_handler, context).await },
);
});
runtime.block_on(async {
let _ = stop_receiver.await;
});
runtime.shutdown_background();
worker.stop_all();
})
.context("tcp thread build failed")?;
Ok(())
}
async fn connect_tcp_handle<H>(
mut receiver: Receiver<(Vec<u8>, SocketAddr)>,
recv_handler: H,
context: ChannelContext,
) -> io::Result<WritableNotify> {
let poll = Poll::new()?;
let writable_notify = WritableNotify::new(Waker::new(poll.registry(), NOTIFY)?);
let worker = {
let writable_notify = writable_notify.clone();
stop_manager.add_listener("tcp_writable_handler".into(), move || {
if let Err(e) = writable_notify.stop() {
log::error!("{:?}", e);
) where
H: RecvChannelHandler,
{
while let Some((data, addr)) = receiver.recv().await {
let recv_handler = recv_handler.clone();
let context = context.clone();
tokio::spawn(async move {
if let Err(e) = connect_tcp0(data, addr, recv_handler, context).await {
log::warn!("发送失败,链接终止:{:?},{:?}", addr, e);
}
})?
};
{
let writable_notify = writable_notify.clone();
thread::Builder::new()
.name("tcpWriteableListen".into())
.spawn(move || {
if let Err(e) = tcp_writable_listen(receiver, poll, writable_notify, &context) {
log::error!("{:?}", e);
}
worker.stop_all();
})?;
});
}
Ok(writable_notify)
}
/// 处理写事件
fn tcp_writable_listen(
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
mut poll: Poll,
writable_notify: WritableNotify,
context: &ChannelContext,
) -> io::Result<()> {
let mut events = Events::with_capacity(1024);
let mut write_map: HashMap<
Token,
(
TcpStream,
SocketAddr,
Receiver<Vec<u8>>,
Option<(Vec<u8>, usize)>,
),
> = HashMap::with_capacity(32);
async fn connect_tcp0<H>(
data: Vec<u8>,
addr: SocketAddr,
recv_handler: H,
context: ChannelContext,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let mut stream =
tokio::time::timeout(Duration::from_secs(3), TcpStream::connect(addr)).await??;
tcp_write(&mut stream, &data).await?;
tcp_stream_handle(stream, addr, recv_handler, context).await;
Ok(())
}
async fn tcp_accept<H>(
tcp_server: std::net::TcpListener,
recv_handler: H,
context: ChannelContext,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let tcp_server = TcpListener::from_std(tcp_server)?;
loop {
poll.poll(&mut events, None)?;
for event in events.iter() {
match event.token() {
NOTIFY => {
if writable_notify.is_stop() {
//服务停止
return Ok(());
}
if writable_notify.is_need_write() {
// 需要写入数据
if let Some(tokens) = writable_notify.take_all() {
for (token, state) in tokens {
if !state {
closed_handle_w(&token, &mut write_map, &context);
continue;
}
if let Err(e) = writable_handle(&token, &mut write_map) {
closed_handle_w(&token, &mut write_map, &context);
log::warn!("{:?}", e);
}
}
}
}
if writable_notify.is_add_socket() {
//添加tcp连接,并监听写事件
while let Ok((mut stream, token, addr, init_buf)) = receiver.try_recv() {
if let Err(e) = stream.set_nodelay(true) {
log::warn!("set_nodelay err={:?}", e);
}
if let Err(e) =
poll.registry()
.register(&mut stream, token, Interest::WRITABLE)
{
log::warn!("registry err={:?}", e);
continue;
}
let (sender, receiver) = sync_channel(128);
let packet_sender =
PacketSender::new(writable_notify.clone(), sender, token);
if let Some(init_buf) = init_buf {
packet_sender.try_send(&init_buf)?;
}
context.tcp_map.write().insert(addr, packet_sender);
write_map.insert(token, (stream, addr, receiver, None));
}
}
}
token => {
if event.is_writable() {
if let Err(e) = writable_handle(&token, &mut write_map) {
closed_handle_w(&token, &mut write_map, &context);
log::warn!("{:?}", e);
}
} else {
closed_handle_w(&token, &mut write_map, &context);
}
}
}
}
let (stream, addr) = tcp_server.accept().await?;
tcp_stream_handle(stream, addr, recv_handler.clone(), context.clone()).await;
}
}
fn accept_handle(
pub async fn tcp_stream_handle<H>(
stream: TcpStream,
addr: SocketAddr,
init_buf: Option<Vec<u8>>,
write_waker: &WritableNotify,
read_map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
tcp_sender: &SyncSender<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
registry: &Registry,
) -> io::Result<()> {
#[cfg(windows)]
let (tcp_stream, index) = unsafe {
let fd = stream.into_raw_socket();
(std::net::TcpStream::from_raw_socket(fd), fd as usize)
};
#[cfg(any(unix))]
let (tcp_stream, index) = unsafe {
let fd = stream.into_raw_fd();
(std::net::TcpStream::from_raw_fd(fd), fd as usize)
};
if index == 0 || index == 1 {
log::error!("index err={:?}", addr);
return Ok(());
}
let token = Token(index);
match tcp_stream.try_clone() {
Ok(tcp_writer) => {
match tcp_sender.try_send((TcpStream::from_std(tcp_writer), token, addr, init_buf)) {
Ok(_) => {
if let Err(e) = write_waker.add_socket() {
log::error!("write_waker,err={:?},addr={:?}", e, addr);
return Ok(());
}
}
Err(e) => {
return match e {
TrySendError::Full(_) => {
log::error!("Full,addr={:?}", addr);
Ok(())
}
TrySendError::Disconnected(_) => {
Err(io::Error::new(io::ErrorKind::Other, "write thread exit"))
}
};
}
recv_handler: H,
context: ChannelContext,
) where
H: RecvChannelHandler,
{
let _ = stream.set_nodelay(true);
let (r, mut w) = stream.into_split();
let (sender, mut receiver) = channel::<Vec<u8>>(100);
context
.packet_map
.write()
.insert(addr, PacketSender::new(sender));
tokio::spawn(async move {
while let Some(data) = receiver.recv().await {
if let Err(e) = tcp_write(&mut w, &data).await {
log::info!("发送失败,tcp链接终止:{:?},{:?}", addr, e);
break;
}
}
Err(e) => {
log::error!("try_clone err={:?},addr={:?}", e, addr);
return Ok(());
let _ = w.shutdown().await;
});
tokio::spawn(async move {
if let Err(e) = tcp_read(r, addr, &context, recv_handler).await {
log::warn!("tcp_read {:?}", e)
}
context.packet_map.write().remove(&addr);
});
}
async fn tcp_write<W: AsyncWrite + Unpin>(w: &mut W, buf: &[u8]) -> anyhow::Result<()> {
let len = buf.len();
if len > TCP_MAX_PACKET_SIZE {
return Err(anyhow!("超过了tcp的最大长度传输"));
}
let mut stream = TcpStream::from_std(tcp_stream);
if let Err(e) = registry.register(&mut stream, token, Interest::READABLE) {
log::error!("registry err={:?},addr={:?}", e, addr);
return Ok(());
}
read_map.insert(
token,
(
RouteKey::new(true, index, addr),
stream,
Box::new([0; BUFFER_SIZE]),
0,
),
);
w.write_all(&[0, (len >> 16) as u8, (len >> 8) as u8, len as u8])
.await?;
w.write_all(&buf).await?;
Ok(())
}
fn readable_handle<H>(
token: &Token,
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
recv_handler: &mut H,
async fn tcp_read<H>(
mut read: OwnedReadHalf,
addr: SocketAddr,
context: &ChannelContext,
) -> io::Result<()>
recv_handler: H,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
if let Some((route_key, stream, buf, begin)) = map.get_mut(token) {
loop {
let end = if *begin >= 4 {
4 + (((buf[2] as u16) << 8) | buf[3] as u16) as usize
} else {
4
};
if end > BUFFER_SIZE {
return Err(io::Error::from(io::ErrorKind::InvalidData));
}
match stream.read(&mut buf[*begin..end]) {
Ok(len) => {
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
*begin += len;
if end > 4 && *begin == end {
recv_handler.handle(&mut buf[4..end], *route_key, context);
*begin = 0;
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
let mut head = [0; 4];
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
loop {
read.read_exact(&mut head).await?;
if head[0] != 0 {
return Err(anyhow!("tcp数据流错误 {}", addr));
}
}
Ok(())
}
fn writable_handle(
token: &Token,
map: &mut HashMap<
Token,
(
TcpStream,
SocketAddr,
Receiver<Vec<u8>>,
Option<(Vec<u8>, usize)>,
),
>,
) -> io::Result<()> {
if let Some((stream, _, receiver, last)) = map.get_mut(token) {
loop {
if let Some((buf, begin)) = last {
match stream.write(&buf[*begin..]) {
Ok(len) => {
if len == 0 {
return Err(io::Error::from(io::ErrorKind::WriteZero));
}
if len + *begin == buf.len() {
*last = None;
} else {
*begin += len;
continue;
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
match receiver.try_recv() {
Ok(buf) => *last = Some((buf, 0)),
Err(e) => match e {
TryRecvError::Empty => {
break;
}
TryRecvError::Disconnected => {
return Err(io::Error::from(io::ErrorKind::Other));
}
},
}
let len = ((head[1] as usize) << 16) | ((head[2] as usize) << 8) | head[3] as usize;
if len < 12 || len > buf.len() {
return Err(anyhow!("tcp数据长度无效 {}", addr));
}
}
Ok(())
}
fn closed_handle_r(
token: &Token,
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
) {
if let Some((_, tcp, _, _)) = map.remove(token) {
let _ = tcp.shutdown(Shutdown::Both);
}
}
fn closed_handle_w(
token: &Token,
map: &mut HashMap<
Token,
(
TcpStream,
SocketAddr,
Receiver<Vec<u8>>,
Option<(Vec<u8>, usize)>,
),
>,
context: &ChannelContext,
) {
if let Some((tcp, addr, _, _)) = map.remove(token) {
context.tcp_map.write().remove(&addr);
let _ = tcp.shutdown(Shutdown::Both);
read.read_exact(&mut buf[..len]).await?;
recv_handler.handle(
&mut buf[..len],
&mut extend,
RouteKey::new(ConnectProtocol::TCP, 0, addr),
context,
);
}
}
+20 -10
View File
@@ -10,14 +10,14 @@ use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::notify::AcceptNotify;
use crate::channel::sender::AcceptSocketSender;
use crate::channel::{RouteKey, BUFFER_SIZE};
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
use crate::util::StopManager;
pub fn udp_listen<H>(
stop_manager: StopManager,
recv_handler: H,
context: ChannelContext,
) -> io::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
) -> anyhow::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
where
H: RecvChannelHandler,
{
@@ -31,7 +31,7 @@ fn sub_udp_listen<H>(
stop_manager: StopManager,
recv_handler: H,
context: ChannelContext,
) -> io::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
) -> anyhow::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
where
H: RecvChannelHandler,
{
@@ -60,7 +60,7 @@ where
fn sub_udp_listen0<H>(
mut poll: Poll,
mut recv_handler: H,
recv_handler: H,
context: ChannelContext,
accept_notify: AcceptNotify,
accept_receiver: Receiver<Option<Vec<UdpSocket>>>,
@@ -70,9 +70,13 @@ where
{
let mut events = Events::with_capacity(1024);
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
let mut read_map: HashMap<Token, UdpSocket> = HashMap::with_capacity(32);
loop {
poll.poll(&mut events, None)?;
if let Err(e) = poll.poll(&mut events, None) {
crate::ignore_io_interrupted(e)?;
continue;
}
for event in events.iter() {
match event.token() {
NOTIFY => {
@@ -115,7 +119,8 @@ where
Ok((len, addr)) => {
recv_handler.handle(
&mut buf[..len],
RouteKey::new(false, token.0, addr),
&mut extend,
RouteKey::new(ConnectProtocol::UDP, token.0, addr),
&context,
);
}
@@ -206,7 +211,7 @@ fn main_udp_listen<H>(
stop_manager: StopManager,
recv_handler: H,
context: ChannelContext,
) -> io::Result<()>
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
@@ -233,7 +238,7 @@ where
pub fn main_udp_listen0<H>(
mut poll: Poll,
mut recv_handler: H,
recv_handler: H,
context: ChannelContext,
) -> io::Result<()>
where
@@ -252,8 +257,12 @@ where
}
let mut events = Events::with_capacity(udps.len());
let mut extend = [0; BUFFER_SIZE];
loop {
poll.poll(&mut events, None)?;
if let Err(e) = poll.poll(&mut events, None) {
crate::ignore_io_interrupted(e)?;
continue;
}
for x in events.iter() {
let index = match x.token() {
NOTIFY => return Ok(()),
@@ -270,7 +279,8 @@ where
Ok((len, addr)) => {
recv_handler.handle(
&mut buf[..len],
RouteKey::new(false, index, addr),
&mut extend,
RouteKey::new(ConnectProtocol::UDP, index, addr),
&context,
);
}
+159
View File
@@ -0,0 +1,159 @@
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
use anyhow::Context;
use futures_util::stream::SplitStream;
use futures_util::{SinkExt, StreamExt};
use std::convert::Into;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::thread;
use std::time::Duration;
use tokio::net::TcpStream;
use tokio::sync::mpsc::{channel, Receiver};
use tokio_tungstenite::tungstenite::http::StatusCode;
use tokio_tungstenite::tungstenite::{Error, Message};
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
use crate::channel::context::ChannelContext;
use crate::channel::handler::RecvChannelHandler;
use crate::channel::sender::PacketSender;
use crate::util::StopManager;
/// ws协议,
/// 暂时只允许用ws连服务端,不能用ws打洞/连客户端
pub fn ws_connect_accept<H>(
receiver: Receiver<(Vec<u8>, String)>,
recv_handler: H,
context: ChannelContext,
stop_manager: StopManager,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("wsChannel".into(), move || {
let _ = stop_sender.send(());
})?;
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.context("ws tokio runtime build failed")?;
thread::Builder::new()
.name("wsChannel".into())
.spawn(move || {
runtime.spawn(async move { connect_ws_handle(receiver, recv_handler, context).await });
runtime.block_on(async {
let _ = stop_receiver.await;
});
runtime.shutdown_background();
worker.stop_all();
})
.context("ws thread build failed")?;
Ok(())
}
async fn connect_ws_handle<H>(
mut receiver: Receiver<(Vec<u8>, String)>,
recv_handler: H,
context: ChannelContext,
) where
H: RecvChannelHandler,
{
while let Some((data, url)) = receiver.recv().await {
let recv_handler = recv_handler.clone();
let context = context.clone();
tokio::spawn(async move {
if let Err(e) = connect_ws(data, url, recv_handler, context).await {
log::warn!("发送失败,ws链接终止:{:?}", e);
}
});
}
}
const WS_ADDR: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0));
async fn connect_ws<H>(
data: Vec<u8>,
mut url: String,
recv_handler: H,
context: ChannelContext,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let mut count = 0;
log::info!("尝试建立连接 {:?}", url);
let (mut ws, response) = loop {
count += 1;
if count > 3 {
Err(anyhow::anyhow!("发生多次重定向,链接终止"))?
}
match tokio::time::timeout(Duration::from_secs(3), connect_async(url)).await? {
Ok(rs) => break rs,
Err(e) => {
if let Error::Http(res) = &e {
if res.status() == StatusCode::MOVED_PERMANENTLY
|| res.status() == StatusCode::FOUND
|| res.status() == StatusCode::SEE_OTHER
|| res.status() == StatusCode::TEMPORARY_REDIRECT
|| res.status() == StatusCode::PERMANENT_REDIRECT
{
if let Some(v) = res.headers().get("Location") {
if let Ok(redirect) = v.to_str() {
log::info!("url重定向响应头 {:?}", res.headers());
log::info!("url重定向地址 {}", redirect);
url = redirect.to_string();
continue;
}
}
}
}
return Err(e)?;
}
}
};
log::info!("ws协议握手 {:?}", response);
ws.send(Message::Binary(data)).await?;
let (mut ws_write, ws_read) = ws.split();
let (sender, mut receiver) = channel::<Vec<u8>>(100);
context
.packet_map
.write()
.insert(WS_ADDR, PacketSender::new(sender));
tokio::spawn(async move {
while let Some(data) = receiver.recv().await {
if let Err(e) = ws_write.send(Message::Binary(data)).await {
log::warn!("websocket err {:?}", e);
break;
}
}
let _ = ws_write.close().await;
});
if let Err(e) = ws_read_handle(ws_read, recv_handler, &context).await {
log::warn!("{:?}", e);
}
context.packet_map.write().remove(&WS_ADDR);
Ok(())
}
async fn ws_read_handle<H>(
mut ws_read: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
recv_handler: H,
context: &ChannelContext,
) -> anyhow::Result<()>
where
H: RecvChannelHandler,
{
let mut extend = [0; BUFFER_SIZE];
let route_key = RouteKey::new(ConnectProtocol::WS, 0, WS_ADDR);
while let Some(msg) = ws_read.next().await {
let msg = msg.context("Error during WebSocket ")?;
match msg {
Message::Text(txt) => log::info!("Received text message: {}", txt),
Message::Binary(mut data) => {
recv_handler.handle(&mut data, &mut extend, route_key, context);
}
Message::Ping(_) | Message::Pong(_) => (),
Message::Close(_) => break,
_ => {}
}
}
Ok(())
}
+2
View File
@@ -0,0 +1,2 @@
mod rs_aes_cbc;
pub use rs_aes_cbc::*;
@@ -1,6 +1,5 @@
use std::io;
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
use anyhow::anyhow;
use rand::RngCore;
use crate::cipher::Finger;
@@ -50,22 +49,17 @@ impl AesCbcCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < 16 {
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("aes_cbc data err"));
}
let mut iv = [0; 16];
iv[0..4].copy_from_slice(&net_packet.source().octets());
iv[4..8].copy_from_slice(&net_packet.destination().octets());
iv[8] = net_packet.protocol().into();
iv[9] = net_packet.transport_protocol();
iv[10] = net_packet.is_gateway() as u8;
iv[11] = net_packet.source_ttl();
iv[0..12].copy_from_slice(&net_packet.head_tag());
if let Some(finger) = &self.finger {
iv[12..16].copy_from_slice(&finger.hash[0..4]);
}
@@ -75,7 +69,7 @@ impl AesCbcCipher {
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&iv[..12], secret_body.en_body());
if &finger != secret_body.finger() {
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
return Err(anyhow!("aes_cbc finger err"));
}
}
let rs = match &self.cipher {
@@ -92,10 +86,7 @@ impl AesCbcCipher {
net_packet.set_data_len(HEAD_LEN + len - 4)?;
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("解密失败:{}", e),
)),
Err(e) => Err(anyhow!("aes_cbc 解密失败:{}", e)),
}
}
/// net_packet 必须预留足够长度
@@ -103,15 +94,10 @@ impl AesCbcCipher {
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
let data_len = net_packet.data_len();
let mut iv = [0; 16];
iv[0..4].copy_from_slice(&net_packet.source().octets());
iv[4..8].copy_from_slice(&net_packet.destination().octets());
iv[8] = net_packet.protocol().into();
iv[9] = net_packet.transport_protocol();
iv[10] = net_packet.is_gateway() as u8;
iv[11] = net_packet.source_ttl();
iv[0..12].copy_from_slice(&net_packet.head_tag());
if let Some(finger) = &self.finger {
iv[12..16].copy_from_slice(&finger.hash[0..4]);
net_packet.set_data_len(data_len + 16)?;
@@ -146,10 +132,22 @@ impl AesCbcCipher {
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("加密失败:{}", e),
)),
Err(e) => Err(anyhow!("aes_cbc 加密失败:{}", e)),
};
}
}
#[test]
fn test_aes_cbc() {
let d = AesCbcCipher::new_128([0; 16], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = AesCbcCipher::new_128([0; 16], None);
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+9
View File
@@ -0,0 +1,9 @@
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
mod rs_aes_ecb;
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
pub use rs_aes_ecb::*;
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
mod openssl_aes_ecb;
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
pub use openssl_aes_ecb::*;
@@ -1,8 +1,11 @@
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
use std::ptr;
use anyhow::anyhow;
use libc::c_int;
use openssl_sys::EVP_CIPHER_CTX;
use std::{io, ptr};
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
pub struct AesEcbCipher {
key: Vec<u8>,
@@ -100,34 +103,28 @@ impl AesEcbCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
return Err(anyhow!("not encrypt"));
}
if let Some(finger) = &self.finger {
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let len = net_packet.payload().len();
if len < 12 {
return Err(io::Error::new(io::ErrorKind::Other, "data len err"));
return Err(anyhow!("data len err"));
}
let secret_body = &net_packet.payload()[..len - 12];
let finger = finger.calculate_finger(&nonce_raw, secret_body);
if &finger != &net_packet.payload()[len - 12..] {
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
return Err(anyhow!("finger err"));
}
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
}
if net_packet.payload().len() < 16 {
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
let input = net_packet.payload();
let mut out = [0u8; 1024 * 5];
@@ -147,22 +144,22 @@ impl AesEcbCipher {
//校验头部
let src_net_packet = NetPacket::new(text)?;
if src_net_packet.source() != net_packet.source() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
}
net_packet.set_encrypt_flag(false);
@@ -175,7 +172,7 @@ impl AesEcbCipher {
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
let input = net_packet.buffer();
let mut out = [0u8; 1024 * 5];
let mut out_len = 0;
@@ -191,7 +188,7 @@ impl AesEcbCipher {
}
let out_len = out_len as usize;
if out_len == 0 {
return Err(io::Error::new(io::ErrorKind::Other, "ciphertext len err"));
return Err(anyhow!("ciphertext len err"));
}
//密文
let ciphertext = &out[..out_len];
@@ -199,13 +196,7 @@ impl AesEcbCipher {
net_packet.payload_mut().copy_from_slice(ciphertext);
net_packet.set_encrypt_flag(true);
if let Some(finger) = &self.finger {
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let finger = finger.calculate_finger(&nonce_raw, ciphertext);
let src_data_len = net_packet.data_len();
//设置实际长度
@@ -221,6 +212,8 @@ impl AesEcbCipher {
fn test_openssl_aes_ecb() {
let d = AesEcbCipher::new_128([0; 16], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
@@ -1,7 +1,8 @@
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyInit};
use anyhow::anyhow;
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyInit};
use std::io;
type Aes128EcbEnc = ecb::Encryptor<aes::Aes128>;
type Aes128EcbDec = ecb::Decryptor<aes::Aes128>;
@@ -46,34 +47,28 @@ impl AesEcbCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
return Err(anyhow!("not encrypt"));
}
if let Some(finger) = &self.finger {
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let len = net_packet.payload().len();
if len < 12 {
return Err(io::Error::new(io::ErrorKind::Other, "payload len <12"));
return Err(anyhow!("payload len <12"));
}
let secret_body = &net_packet.payload()[..len - 12];
let finger = finger.calculate_finger(&nonce_raw, secret_body);
if &finger != &net_packet.payload()[len - 12..] {
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
return Err(anyhow!("finger err"));
}
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
}
if net_packet.payload().len() < 16 {
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
let mut out = [0u8; 1024 * 5];
let rs = match self.key {
@@ -87,32 +82,29 @@ impl AesEcbCipher {
//校验头部
let src_net_packet = NetPacket::new(buf)?;
if src_net_packet.source() != net_packet.source() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
net_packet.set_data_len(buf.len())?;
net_packet.set_payload(src_net_packet.payload())?;
net_packet.set_encrypt_flag(false);
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("aes_ecb解密失败:{}", e),
)),
Err(e) => Err(anyhow!("aes_ecb解密失败:{}", e)),
}
}
/// net_packet 必须预留足够长度
@@ -120,7 +112,7 @@ impl AesEcbCipher {
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
let mut out = [0u8; 1024 * 5];
let rs = match self.key {
AesEcbEnum::AES128ECB(key) => Aes128EcbEnc::new(&key.into())
@@ -136,13 +128,7 @@ impl AesEcbCipher {
net_packet.set_encrypt_flag(true);
if let Some(finger) = &self.finger {
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let finger = finger.calculate_finger(&nonce_raw, buf);
let src_data_len = net_packet.data_len();
//设置实际长度
@@ -152,10 +138,7 @@ impl AesEcbCipher {
}
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("aes_ecb加密失败:{}", e),
)),
Err(e) => Err(anyhow!("aes_ecb加密失败:{}", e)),
};
}
}
@@ -1,8 +1,7 @@
use std::io;
use aes_gcm::aead::consts::{U12, U16};
use aes_gcm::aead::generic_array::GenericArray;
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit, Nonce, Tag};
use anyhow::anyhow;
use rand::RngCore;
use crate::cipher::finger::Finger;
@@ -39,22 +38,16 @@ impl AesGcmCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
@@ -62,7 +55,7 @@ impl AesGcmCipher {
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
if &finger != secret_body.finger() {
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
return Err(anyhow!("finger err"));
}
}
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(tag);
@@ -75,10 +68,7 @@ impl AesGcmCipher {
}
};
if let Err(e) = rs {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("解密失败:{}", e),
));
return Err(anyhow!("解密失败:{}", e));
}
net_packet.set_encrypt_flag(false);
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
@@ -89,17 +79,11 @@ impl AesGcmCipher {
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if net_packet.reserve() < AES_GCM_ENCRYPTION_RESERVED {
return Err(io::Error::new(io::ErrorKind::Other, "too short"));
return Err(anyhow!("too short"));
}
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
net_packet.set_data_len(data_len)?;
@@ -123,10 +107,26 @@ impl AesGcmCipher {
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("加密失败:{}", e),
)),
Err(e) => Err(anyhow!("加密失败:{}", e)),
};
}
}
#[test]
fn test_aes_gcm() {
let d = AesGcmCipher::new_256([0; 32], Some(Finger::new("123")));
let mut p =
NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = AesGcmCipher::new_256([0; 32], None);
let mut p =
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+9
View File
@@ -0,0 +1,9 @@
#[cfg(feature = "ring-cipher")]
mod ring_aes_gcm_cipher;
#[cfg(feature = "ring-cipher")]
pub use ring_aes_gcm_cipher::*;
#[cfg(not(feature = "ring-cipher"))]
mod aes_gcm_cipher;
#[cfg(not(feature = "ring-cipher"))]
pub use aes_gcm_cipher::*;
@@ -1,9 +1,9 @@
use crate::cipher::Finger;
use anyhow::anyhow;
use rand::RngCore;
use ring::aead;
use ring::aead::{LessSafeKey, UnboundKey};
use std::io;
use crate::cipher::Finger;
use crate::protocol::body::{SecretBody, AES_GCM_ENCRYPTION_RESERVED};
use crate::protocol::NetPacket;
@@ -53,28 +53,22 @@ impl AesGcmCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let nonce = aead::Nonce::assume_unique_for_key(nonce_raw);
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
if &finger != secret_body.finger() {
return Err(io::Error::new(io::ErrorKind::Other, "ring aes finger err"));
return Err(anyhow!("ring aes finger err"));
}
}
@@ -87,10 +81,7 @@ impl AesGcmCipher {
}
};
if let Err(e) = rs {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("解密失败:{}", e),
));
return Err(anyhow!("解密失败:{}", e));
}
net_packet.set_encrypt_flag(false);
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
@@ -102,14 +93,8 @@ impl AesGcmCipher {
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
) -> anyhow::Result<()> {
let nonce_raw = net_packet.head_tag();
let nonce = aead::Nonce::assume_unique_for_key(nonce_raw);
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
net_packet.set_data_len(data_len)?;
@@ -128,10 +113,7 @@ impl AesGcmCipher {
Ok(tag) => {
let tag = tag.as_ref();
if tag.len() != 16 {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("加密tag长度错误:{}", tag.len()),
));
return Err(anyhow!("加密tag长度错误:{}", tag.len()));
}
secret_body.set_tag(tag)?;
if let Some(finger) = &self.finger {
@@ -141,10 +123,26 @@ impl AesGcmCipher {
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("加密失败:{}", e),
)),
Err(e) => Err(anyhow!("加密失败:{}", e)),
};
}
}
#[test]
fn test_aes_gcm() {
let d = AesGcmCipher::new_256([0; 32], Some(Finger::new("123")));
let mut p =
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = AesGcmCipher::new_256([0; 32], None);
let mut p =
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+2
View File
@@ -0,0 +1,2 @@
mod rs_chacha20;
pub use rs_chacha20::*;
+107
View File
@@ -0,0 +1,107 @@
use aes::cipher::Iv;
use anyhow::anyhow;
use chacha20::cipher::{Key, KeyIvInit, StreamCipher};
use chacha20::ChaCha20;
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
use crate::cipher::Finger;
use crate::protocol::body::{
IVSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED,
};
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct ChaCha20Cipher {
key: [u8; 32],
pub(crate) finger: Option<Finger>,
}
impl ChaCha20Cipher {
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
Self { key, finger }
}
}
impl ChaCha20Cipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl ChaCha20Cipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
let mut head_tag = net_packet.head_tag();
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data());
if &finger != secret_body.finger() {
return Err(anyhow!("ChaCha20 finger err"));
}
}
gen_nonce(&mut head_tag, secret_body.random_buf());
ChaCha20::new(
Key::<ChaCha20>::from_slice(&self.key),
Iv::<ChaCha20>::from_slice(&head_tag),
)
.apply_keystream(secret_body.data_mut());
let len = secret_body.data().len();
net_packet.set_encrypt_flag(false);
net_packet.set_payload_len(len)?;
Ok(())
}
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let data_len = net_packet.data_len();
let head_tag = net_packet.head_tag();
if let Some(_) = &self.finger {
net_packet.set_data_len(data_len + RANDOM_RESERVED + FINGER_RESERVED)?;
} else {
net_packet.set_data_len(data_len + RANDOM_RESERVED)?;
}
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
let mut nonce = head_tag;
secret_body.set_random(&gen_random_nonce(&mut nonce));
ChaCha20::new(
Key::<ChaCha20>::from_slice(&self.key),
Iv::<ChaCha20>::from_slice(&nonce),
)
.apply_keystream(secret_body.data_mut());
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data());
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), true)?;
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
}
#[test]
fn test_chacha20() {
let d = ChaCha20Cipher::new_256([0; 32], Some(Finger::new("123")));
let mut p =
NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = ChaCha20Cipher::new_256([0; 32], None);
let mut p =
NetPacket::new_encrypt([2; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+9
View File
@@ -0,0 +1,9 @@
#[cfg(feature = "ring-cipher")]
mod ring_chacha20_poly1305;
#[cfg(feature = "ring-cipher")]
pub use ring_chacha20_poly1305::*;
#[cfg(not(feature = "ring-cipher"))]
mod rs_chacha20_poly1305;
#[cfg(not(feature = "ring-cipher"))]
pub use rs_chacha20_poly1305::*;
@@ -0,0 +1,127 @@
use anyhow::anyhow;
use ring::aead;
use ring::aead::{LessSafeKey, UnboundKey};
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
use crate::cipher::Finger;
use crate::protocol::body::{
AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED,
};
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct ChaCha20Poly1305Cipher {
key: Vec<u8>,
pub(crate) cipher: LessSafeKey,
pub(crate) finger: Option<Finger>,
}
impl ChaCha20Poly1305Cipher {
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
let cipher = LessSafeKey::new(UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap());
Self {
key: key.to_vec(),
cipher,
finger,
}
}
}
impl ChaCha20Poly1305Cipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl ChaCha20Poly1305Cipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < TAG_RESERVED {
log::error!("数据异常,长度小于{}", TAG_RESERVED);
return Err(anyhow!("data err"));
}
let mut head_tag = net_packet.head_tag();
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
if &finger != secret_body.finger() {
return Err(anyhow!("ring CHACHA20_POLY1305 finger err"));
}
}
gen_nonce(&mut head_tag, secret_body.random_buf());
let nonce = aead::Nonce::assume_unique_for_key(head_tag);
let rs = self
.cipher
.open_in_place(nonce, aead::Aad::empty(), secret_body.data_tag_mut());
if let Err(e) = rs {
return Err(anyhow!("ring CHACHA20_POLY1305 解密失败:{}", e));
}
let len = secret_body.data().len();
net_packet.set_encrypt_flag(false);
net_packet.set_payload_len(len)?;
return Ok(());
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
/// 返回加密后载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let head_tag = net_packet.head_tag();
let data_len = net_packet.data_len();
if self.finger.is_some() {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?;
} else {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?;
}
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
let mut nonce = head_tag;
secret_body.set_random(&gen_random_nonce(&mut nonce));
let nonce = aead::Nonce::assume_unique_for_key(nonce);
let rs = self.cipher.seal_in_place_separate_tag(
nonce,
aead::Aad::empty(),
secret_body.data_mut(),
);
match rs {
Ok(tag) => {
let tag = tag.as_ref();
if tag.len() != 16 {
return Err(anyhow!("加密tag长度错误:{}", tag.len()));
}
secret_body.set_tag(tag)?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("ring CHACHA20_POLY1305 加密失败:{}", e)),
}
}
}
#[test]
fn test_ring_chacha20_poly1305() {
let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = ChaCha20Poly1305Cipher::new_256([0; 32], None);
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
@@ -0,0 +1,126 @@
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
use crate::cipher::Finger;
use crate::protocol::body::{
AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED,
};
use crate::protocol::NetPacket;
use anyhow::anyhow;
use chacha20poly1305::aead::{Nonce, Tag};
use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit};
#[derive(Clone)]
pub struct ChaCha20Poly1305Cipher {
key: Vec<u8>,
pub(crate) cipher: ChaCha20Poly1305,
pub(crate) finger: Option<Finger>,
}
impl ChaCha20Poly1305Cipher {
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
let key: &Key = &key.into();
let cipher = ChaCha20Poly1305::new(key);
Self {
key: key.to_vec(),
cipher,
finger,
}
}
}
impl ChaCha20Poly1305Cipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl ChaCha20Poly1305Cipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
if net_packet.payload().len() < TAG_RESERVED {
log::error!("数据异常,长度小于{}", TAG_RESERVED);
return Err(anyhow!("data err"));
}
let mut head_tag = net_packet.head_tag();
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
if &finger != secret_body.finger() {
return Err(anyhow!("rs CHACHA20_POLY1305 finger err"));
}
}
gen_nonce(&mut head_tag, secret_body.random_buf());
let nonce: Nonce<ChaCha20Poly1305> = head_tag.into();
let tag: Tag<ChaCha20Poly1305> =
Tag::<ChaCha20Poly1305>::from_slice(secret_body.tag()).clone();
if let Err(e) =
self.cipher
.decrypt_in_place_detached(&nonce, &[], secret_body.data_mut(), &tag)
{
return Err(anyhow!("rs CHACHA20_POLY1305 decrypt_ipv4 {:?}", e));
}
let len = secret_body.data().len();
net_packet.set_encrypt_flag(false);
net_packet.set_payload_len(len)?;
Ok(())
}
/// net_packet 必须预留足够长度
/// data_len是有效载荷的长度
/// 返回加密后载荷的长度
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
let head_tag = net_packet.head_tag();
let data_len = net_packet.data_len();
if self.finger.is_some() {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?;
} else {
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?;
}
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
let mut nonce = head_tag;
secret_body.set_random(&gen_random_nonce(&mut nonce));
let nonce = nonce.into();
let rs = self
.cipher
.encrypt_in_place_detached(&nonce, &[], secret_body.data_mut());
match rs {
Ok(tag) => {
let tag: &[u8] = tag.as_ref();
if tag.len() != 16 {
return Err(anyhow!("加密tag长度错误:{}", tag.len(),));
}
secret_body.set_tag(tag)?;
if let Some(finger) = &self.finger {
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
secret_body.set_finger(&finger)?;
}
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(anyhow!("rs CHACHA20_POLY1305 加密失败:{}", e)),
}
}
}
#[test]
fn test_rs_chacha20_poly1305() {
let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123")));
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
let d = ChaCha20Poly1305Cipher::new_256([0; 32], None);
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src);
}
+126 -142
View File
@@ -1,110 +1,99 @@
#[cfg(feature = "aes_ecb")]
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
use crate::cipher::aes_ecb::AesEcbCipher;
use std::fmt::Display;
use std::str::FromStr;
use anyhow::anyhow;
#[cfg(cipher)]
use sha2::Digest;
#[cfg(feature = "aes_cbc")]
use crate::cipher::aes_cbc::AesCbcCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(not(feature = "ring-cipher"))]
use crate::cipher::aes_gcm_cipher::AesGcmCipher;
#[cfg(feature = "aes_ecb")]
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
use crate::cipher::openssl_aes_ecb::AesEcbCipher;
use crate::cipher::aes_ecb::AesEcbCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(feature = "ring-cipher")]
use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher;
use crate::cipher::aes_gcm::AesGcmCipher;
#[cfg(feature = "chacha20_poly1305")]
use crate::cipher::chacha20::ChaCha20Cipher;
#[cfg(feature = "chacha20_poly1305")]
use crate::cipher::chacha20_poly1305::ChaCha20Poly1305Cipher;
#[cfg(feature = "sm4_cbc")]
use crate::cipher::sm4_cbc::Sm4CbcCipher;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
use crate::cipher::xor::XORCipher;
#[cfg(cipher)]
use crate::cipher::Finger;
use crate::protocol::NetPacket;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
use sha2::Digest;
use std::io;
use std::str::FromStr;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum CipherModel {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm,
#[cfg(feature = "chacha20_poly1305")]
Chacha20Poly1305,
#[cfg(feature = "chacha20_poly1305")]
Chacha20,
#[cfg(feature = "aes_cbc")]
AesCbc,
#[cfg(feature = "aes_ecb")]
AesEcb,
#[cfg(feature = "sm4_cbc")]
Sm4Cbc,
Xor,
None,
}
impl Display for CipherModel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let str = match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm => "aes_gcm".to_string(),
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20Poly1305 => "chacha20_poly1305".to_string(),
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20 => "chacha20".to_string(),
#[cfg(feature = "aes_cbc")]
CipherModel::AesCbc => "aes_cbc".to_string(),
#[cfg(feature = "aes_ecb")]
CipherModel::AesEcb => "aes_ecb".to_string(),
#[cfg(feature = "sm4_cbc")]
CipherModel::Sm4Cbc => "sm4_cbc".to_string(),
CipherModel::Xor => "xor".to_string(),
CipherModel::None => "none".to_string(),
};
write!(f, "{}", str)
}
}
impl FromStr for CipherModel {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
return Err(format!("not match '{}', no encrypt", s));
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
match s.to_lowercase().trim() {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
"aes_gcm" => Ok(CipherModel::AesGcm),
#[cfg(feature = "chacha20_poly1305")]
"chacha20_poly1305" => Ok(CipherModel::Chacha20Poly1305),
#[cfg(feature = "chacha20_poly1305")]
"chacha20" => Ok(CipherModel::Chacha20),
#[cfg(feature = "aes_cbc")]
"aes_cbc" => Ok(CipherModel::AesCbc),
#[cfg(feature = "aes_ecb")]
"aes_ecb" => Ok(CipherModel::AesEcb),
#[cfg(feature = "sm4_cbc")]
"sm4_cbc" => Ok(CipherModel::Sm4Cbc),
"xor" => Ok(CipherModel::Xor),
_ => {
let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[cfg(feature = "chacha20_poly1305")]
enums.push_str("/chacha20_poly1305/chacha20");
#[cfg(feature = "aes_cbc")]
enums.push_str("/aes_cbc");
#[cfg(feature = "aes_ecb")]
enums.push_str("/aes_ecb");
#[cfg(feature = "sm4_cbc")]
enums.push_str("/sm4_cbc");
let str = if enums.is_empty() {
"no encrypt"
} else {
&enums[1..]
};
Err(format!("not match '{}', enum:{}", s, str))
enums.push_str("/xor");
Err(format!("not match '{}', enum:{}", s, &enums[1..]))
}
}
}
@@ -114,199 +103,176 @@ impl FromStr for CipherModel {
pub enum Cipher {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm((AesGcmCipher, Vec<u8>)),
#[cfg(feature = "chacha20_poly1305")]
Chacha20Poly1305(ChaCha20Poly1305Cipher),
#[cfg(feature = "chacha20_poly1305")]
Chacha20(ChaCha20Cipher),
#[cfg(feature = "aes_cbc")]
AesCbc(AesCbcCipher),
#[cfg(feature = "aes_ecb")]
AesEcb(AesEcbCipher),
#[cfg(feature = "sm4_cbc")]
Sm4Cbc(Sm4CbcCipher),
Xor(XORCipher),
None,
}
impl Cipher {
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
pub fn new_password(
_model: CipherModel,
_password: Option<String>,
_token: Option<String>,
) -> Self {
Cipher::None
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn new_password(
model: CipherModel,
password: Option<String>,
token: Option<String>,
) -> Self {
let finger = token.map(|token| Finger::new(&token));
) -> anyhow::Result<Self> {
if let Some(password) = password {
let mut hasher = sha2::Sha256::new();
hasher.update(password.as_bytes());
let key: [u8; 32] = hasher.finalize().into();
#[cfg(cipher)]
let key: [u8; 32] = {
let mut hasher = sha2::Sha256::new();
hasher.update(password.as_bytes());
hasher.finalize().into()
};
match model {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm => {
let finger = token.map(|token| Finger::new(&token));
if password.len() < 8 {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::AesGcm((aes, key[..16].to_vec()))
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
} else {
let aes = AesGcmCipher::new_256(key, finger);
Cipher::AesGcm((aes, key.to_vec()))
Ok(Cipher::AesGcm((aes, key.to_vec())))
}
}
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20Poly1305 => {
let finger = token.map(|token| Finger::new(&token));
let chacha = ChaCha20Poly1305Cipher::new_256(key, finger);
Ok(Cipher::Chacha20Poly1305(chacha))
}
#[cfg(feature = "chacha20_poly1305")]
CipherModel::Chacha20 => {
let finger = token.map(|token| Finger::new(&token));
let chacha = ChaCha20Cipher::new_256(key, finger);
Ok(Cipher::Chacha20(chacha))
}
#[cfg(feature = "aes_cbc")]
CipherModel::AesCbc => {
let finger = token.map(|token| Finger::new(&token));
if password.len() < 8 {
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::AesCbc(aes)
Ok(Cipher::AesCbc(aes))
} else {
let aes = AesCbcCipher::new_256(key, finger);
Cipher::AesCbc(aes)
Ok(Cipher::AesCbc(aes))
}
}
#[cfg(feature = "aes_ecb")]
CipherModel::AesEcb => {
let finger = token.map(|token| Finger::new(&token));
if password.len() < 8 {
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::AesEcb(aes)
Ok(Cipher::AesEcb(aes))
} else {
let aes = AesEcbCipher::new_256(key, finger);
Cipher::AesEcb(aes)
Ok(Cipher::AesEcb(aes))
}
}
#[cfg(feature = "sm4_cbc")]
CipherModel::Sm4Cbc => {
let finger = token.map(|token| Finger::new(&token));
let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::Sm4Cbc(aes)
Ok(Cipher::Sm4Cbc(aes))
}
CipherModel::None => Cipher::None,
CipherModel::Xor => {
if token.is_some() {
Err(anyhow::anyhow!(
"'finger' and 'xor' cannot be used simultaneously"
))?
}
Ok(Cipher::Xor(XORCipher::new_256(
crate::cipher::xor::simple_hash(&password),
)))
}
CipherModel::None => Ok(Cipher::None),
}
} else {
Cipher::None
Ok(Cipher::None)
}
}
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
pub fn new_key(_key: [u8; 32], _token: String) -> io::Result<Self> {
Err(io::Error::new(io::ErrorKind::Other, "key error"))
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
pub fn new_key(_key: [u8; 32], _token: String) -> anyhow::Result<Self> {
Err(anyhow!("key error"))
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
pub fn new_key(key: [u8; 32], token: String) -> anyhow::Result<Self> {
let finger = Some(Finger::new(&token));
match key.len() {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
16 => {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
32 => {
let aes = AesGcmCipher::new_256(key, finger);
Ok(Cipher::AesGcm((aes, key.to_vec())))
}
_ => Err(io::Error::new(io::ErrorKind::Other, "key error")),
_ => Err(anyhow!("key error")),
}
}
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305.decrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => chacha20.decrypt_ipv4(net_packet),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.decrypt_ipv4(net_packet),
Cipher::Xor(xor) => xor.decrypt_ipv4(net_packet),
Cipher::None => {
if net_packet.is_encrypt() {
return Err(io::Error::new(io::ErrorKind::Other, "not key"));
return Err(anyhow!("not key"));
}
Ok(())
}
}
}
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
Ok(())
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305.encrypt_ipv4(net_packet),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => chacha20.encrypt_ipv4(net_packet),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.encrypt_ipv4(net_packet),
Cipher::Xor(xor) => xor.encrypt_ipv4(net_packet),
Cipher::None => Ok(()),
}
}
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
#[cfg(not(cipher))]
pub fn check_finger<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_net_packet: &NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
Ok(())
}
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
#[cfg(cipher)]
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> anyhow::Result<()> {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm
@@ -314,6 +280,18 @@ impl Cipher {
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => chacha20
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc
.finger
@@ -332,6 +310,7 @@ impl Cipher {
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
Cipher::Xor(_) => Ok(()),
Cipher::None => Ok(()),
}
}
@@ -339,12 +318,17 @@ impl Cipher {
match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((_, key)) => Some(key),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20Poly1305(chacha20poly1305) => Some(chacha20poly1305.key()),
#[cfg(feature = "chacha20_poly1305")]
Cipher::Chacha20(chacha20) => Some(chacha20.key()),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => Some(sm4_cbc.key()),
Cipher::Xor(xor) => Some(xor.key()),
Cipher::None => None,
}
}
+30 -5
View File
@@ -1,4 +1,5 @@
use std::io;
use anyhow::anyhow;
use rand::RngCore;
use sha2::Digest;
@@ -16,15 +17,15 @@ impl Finger {
let hash: [u8; 32] = hasher.finalize().into();
Finger { hash }
}
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
return Err(anyhow!("not encrypt"));
}
let payload_len = net_packet.payload().len();
if payload_len < 12 {
log::error!("数据异常,长度小于{}", 12);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
@@ -36,7 +37,7 @@ impl Finger {
let payload = net_packet.payload();
let finger = self.calculate_finger(&nonce_raw, &payload[..payload_len - 12]);
if &finger[..] != &payload[payload_len - 12..] {
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
return Err(anyhow!("finger err"));
}
Ok(())
}
@@ -49,3 +50,27 @@ impl Finger {
return key[20..].try_into().unwrap();
}
}
impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn head_tag(&self) -> [u8; 12] {
let mut tag = [0; 12];
tag[0..4].copy_from_slice(&self.buffer()[4..8]);
tag[4..8].copy_from_slice(&self.buffer()[8..12]);
tag[8] = self.protocol().into();
tag[9] = self.transport_protocol();
tag[10] = self.is_gateway() as u8;
tag[11] = self.source_ttl();
tag
}
}
pub fn gen_nonce(tag: &mut [u8], random: &[u8]) {
tag[8] = random[0] ^ tag[8];
tag[9] = random[1] ^ tag[9];
tag[10] = random[2] ^ tag[10];
tag[11] = random[3] ^ tag[11];
}
pub fn gen_random_nonce(tag: &mut [u8; 12]) -> [u8; 4] {
let mut random = [0; 4];
rand::thread_rng().fill_bytes(&mut random);
gen_nonce(tag, &random);
random
}
+22 -30
View File
@@ -1,40 +1,32 @@
#[cfg(feature = "aes_cbc")]
mod aes_cbc;
#[cfg(feature = "aes_ecb")]
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
mod aes_ecb;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(not(feature = "ring-cipher"))]
mod aes_gcm_cipher;
mod cipher;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
#[cfg(cipher)]
mod finger;
#[cfg(feature = "aes_ecb")]
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
mod openssl_aes_ecb;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(feature = "ring-cipher")]
mod ring_aes_gcm_cipher;
#[cfg(feature = "sm4_cbc")]
mod sm4_cbc;
pub use cipher::Cipher;
pub use cipher::CipherModel;
#[cfg(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
))]
#[cfg(cipher)]
pub use finger::Finger;
#[cfg(feature = "server_encrypt")]
mod rsa_cipher;
#[cfg(feature = "server_encrypt")]
pub use rsa_cipher::RsaCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
mod aes_gcm;
#[cfg(feature = "chacha20_poly1305")]
mod chacha20;
#[cfg(feature = "chacha20_poly1305")]
mod chacha20_poly1305;
#[cfg(feature = "aes_ecb")]
mod aes_ecb;
#[cfg(feature = "aes_cbc")]
mod aes_cbc;
#[cfg(feature = "sm4_cbc")]
mod sm4_cbc;
mod xor;
pub use xor::simple_hash;
+2
View File
@@ -0,0 +1,2 @@
mod rs_sm4_cbc;
pub use rs_sm4_cbc::*;
@@ -1,9 +1,9 @@
use crate::cipher::Finger;
use crate::protocol::{NetPacket, HEAD_LEN};
use anyhow::anyhow;
use libsm::sm4::cipher_mode::CipherMode;
use libsm::sm4::Sm4CipherMode;
use rand::RngCore;
use std::io;
pub struct Sm4CbcCipher {
key: [u8; 16],
@@ -41,28 +41,22 @@ impl Sm4CbcCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
return Err(anyhow!("not encrypt"));
}
if let Some(finger) = &self.finger {
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let len = net_packet.payload().len();
if len < 12 {
return Err(io::Error::new(io::ErrorKind::Other, "payload len <12"));
return Err(anyhow!("payload len <12"));
}
let secret_body = &net_packet.payload()[..len - 12];
let finger = finger.calculate_finger(&nonce_raw, secret_body);
if &finger != &net_packet.payload()[len - 12..] {
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
return Err(anyhow!("finger err"));
}
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
}
@@ -70,7 +64,7 @@ impl Sm4CbcCipher {
let len = payload.len();
if len < 16 || len > 1024 * 4 {
log::error!("数据异常,长度{}小于16或大于4096", len);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
let mut out = [0u8; 1024 * 4];
let data = &payload[..len - 16];
@@ -79,32 +73,29 @@ impl Sm4CbcCipher {
Ok(len) => {
let src_net_packet = NetPacket::new(&out[..len])?;
if src_net_packet.source() != net_packet.source() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.destination() != net_packet.destination() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.protocol() != net_packet.protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.is_gateway() != net_packet.is_gateway() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
if src_net_packet.source_ttl() != net_packet.source_ttl() {
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
net_packet.set_data_len(len)?;
net_packet.set_payload(src_net_packet.payload())?;
net_packet.set_encrypt_flag(false);
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("sm4_cbc解密失败:{}", e),
)),
Err(e) => Err(anyhow!("sm4_cbc解密失败:{}", e)),
}
}
/// net_packet 必须预留足够长度
@@ -112,7 +103,7 @@ impl Sm4CbcCipher {
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> io::Result<()> {
) -> anyhow::Result<()> {
let mut out = [0u8; 1024 * 4];
let mut iv = [0u8; 16];
rand::thread_rng().fill_bytes(&mut iv);
@@ -121,7 +112,7 @@ impl Sm4CbcCipher {
"数据异常,长度{}大于1024 * 4 - 32",
net_packet.buffer().len()
);
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
return Err(anyhow!("data err"));
}
match self.cipher.encrypt(net_packet.buffer(), &iv, &mut out) {
Ok(len) => {
@@ -129,13 +120,7 @@ impl Sm4CbcCipher {
net_packet.payload_mut()[..len].copy_from_slice(&out[..len]);
net_packet.payload_mut()[len..].copy_from_slice(&iv);
if let Some(finger) = &self.finger {
let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets());
nonce_raw[8] = net_packet.protocol().into();
nonce_raw[9] = net_packet.transport_protocol();
nonce_raw[10] = net_packet.is_gateway() as u8;
nonce_raw[11] = net_packet.source_ttl();
let nonce_raw = net_packet.head_tag();
let finger = finger.calculate_finger(&nonce_raw, net_packet.payload());
let src_data_len = net_packet.data_len();
//设置实际长度
@@ -146,10 +131,7 @@ impl Sm4CbcCipher {
net_packet.set_encrypt_flag(true);
Ok(())
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("sm4_cbc加密失败:{}", e),
)),
Err(e) => Err(anyhow!("sm4_cbc加密失败:{}", e)),
}
}
}
+2
View File
@@ -0,0 +1,2 @@
mod xor;
pub use xor::*;
+84
View File
@@ -0,0 +1,84 @@
use anyhow::anyhow;
use crate::protocol::NetPacket;
pub fn simple_hash(input: &str) -> [u8; 32] {
let mut result = [0u8; 32];
let bytes = input.as_bytes();
for (index, v) in result.iter_mut().enumerate() {
*v = bytes[index % bytes.len()];
}
let mut state = 0u8;
for (i, &byte) in bytes.iter().enumerate() {
let combined = byte.wrapping_add(state).rotate_left((i % 8) as u32);
result[i % 32] ^= combined;
state = state.wrapping_add(byte).rotate_left(3);
}
for i in 0..32 {
result[i] = result[i]
.rotate_left((result[(i + 1) % 32] % 8) as u32)
.wrapping_add(state);
state = state.wrapping_add(result[i]).rotate_left(3);
}
result
}
#[derive(Clone)]
pub struct XORCipher {
key: [u8; 32],
}
impl XORCipher {
pub fn new_256(key: [u8; 32]) -> Self {
Self { key }
}
}
impl XORCipher {
pub fn key(&self) -> &[u8] {
&self.key
}
}
impl XORCipher {
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
if !net_packet.is_encrypt() {
//未加密的数据直接丢弃
return Err(anyhow!("not encrypt"));
}
let key = &self.key;
for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() {
*byte ^= key[i & 31];
}
net_packet.set_encrypt_flag(false);
Ok(())
}
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
net_packet: &mut NetPacket<B>,
) -> anyhow::Result<()> {
net_packet.set_encrypt_flag(true);
let key = &self.key;
for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() {
*byte ^= key[i & 31];
}
Ok(())
}
}
#[test]
fn test_xor() {
let d = XORCipher::new_256(simple_hash("password"));
let mut p = NetPacket::new_encrypt([0; 1000]).unwrap();
let src = p.buffer().to_vec();
d.encrypt_ipv4(&mut p).unwrap();
d.decrypt_ipv4(&mut p).unwrap();
assert_eq!(p.buffer(), &src)
}
+33
View File
@@ -0,0 +1,33 @@
use anyhow::anyhow;
use crate::protocol::NetPacket;
#[derive(Clone)]
pub struct Lz4Compressor;
impl Lz4Compressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match lz4_flex::compress_into(in_net_packet.payload(), out.payload_mut()) {
Ok(len) => len,
Err(e) => Err(anyhow!("Lz4 compress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match lz4_flex::decompress_into(in_net_packet.payload(), out.payload_mut()) {
Ok(len) => len,
Err(e) => Err(anyhow!("Lz4 decompress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
}
+220
View File
@@ -0,0 +1,220 @@
use std::str::FromStr;
use anyhow::anyhow;
#[cfg(feature = "lz4_compress")]
use crate::compression::lz4_compress::Lz4Compressor;
#[cfg(feature = "zstd_compress")]
use crate::compression::zstd_compress::ZstdCompressor;
use crate::protocol::extension::CompressionAlgorithm;
#[cfg(feature = "zstd_compress")]
use zstd::zstd_safe::CompressionLevel;
use crate::protocol::NetPacket;
#[cfg(feature = "lz4_compress")]
mod lz4_compress;
#[cfg(feature = "zstd_compress")]
mod zstd_compress;
#[derive(Clone, Copy, Debug)]
pub enum Compressor {
#[cfg(feature = "lz4_compress")]
Lz4,
#[cfg(feature = "zstd_compress")]
Zstd(CompressionLevel),
None,
}
impl FromStr for Compressor {
type Err = String;
#[cfg(not(any(feature = "lz4_compress", feature = "zstd_compress")))]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Err(format!("not match '{}', Compression not supported", s))
}
#[cfg(any(feature = "lz4_compress", feature = "zstd_compress"))]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let str = s.trim().to_lowercase();
match str.as_str() {
#[cfg(feature = "lz4_compress")]
"lz4" => Ok(Compressor::Lz4),
#[cfg(feature = "zstd_compress")]
"zstd" => Ok(Compressor::Zstd(9)),
"none" => Ok(Compressor::None),
_ => {
#[cfg(feature = "zstd_compress")]
{
let string_array: Vec<String> = str.split(',').map(|s| s.to_string()).collect();
if string_array.len() != 2 || string_array[0] != "zstd" {
return Err(format!("not match '{}', exp: zstd,10", s));
}
return match CompressionLevel::from_str(&string_array[1]) {
Ok(level) => Ok(Compressor::Zstd(level)),
Err(_) => Err(format!("not match '{}', exp: zstd,10", s)),
};
}
#[cfg(not(feature = "zstd_compress"))]
#[cfg(feature = "lz4_compress")]
return Err(format!("not match '{}', exp: lz4", s));
}
}
}
}
#[cfg(not(any(feature = "lz4_compress", feature = "zstd_compress")))]
impl Compressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_in_net_packet: &NetPacket<I>,
_out: &mut NetPacket<O>,
) -> anyhow::Result<bool> {
Ok(false)
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
_algorithm: CompressionAlgorithm,
_in_net_packet: &NetPacket<I>,
_out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
Err(anyhow!("Unsupported decompress"))
}
}
#[cfg(any(feature = "lz4_compress", feature = "zstd_compress"))]
impl Compressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
&self,
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<bool> {
match self {
#[cfg(feature = "lz4_compress")]
Compressor::Lz4 => {
if in_net_packet.data_len() < 128 {
return Ok(false);
}
Lz4Compressor::compress(in_net_packet, out)?;
let mut compression_extension_tail = out.append_compression_extension_tail()?;
compression_extension_tail.set_algorithm(CompressionAlgorithm::Lz4);
//压缩没效果,则放弃压缩
if out.data_len() >= in_net_packet.data_len() - 16 {
return Ok(false);
}
return Ok(true);
}
#[cfg(feature = "zstd_compress")]
Compressor::Zstd(level) => {
if in_net_packet.data_len() < 128 {
return Ok(false);
}
ZstdCompressor::compress(*level, in_net_packet, out)?;
let mut compression_extension_tail = out.append_compression_extension_tail()?;
compression_extension_tail.set_algorithm(CompressionAlgorithm::Zstd);
//压缩没效果,则放弃压缩
if out.data_len() >= in_net_packet.data_len() - 16 {
return Ok(false);
}
return Ok(true);
}
Compressor::None => {}
}
Ok(false)
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
algorithm: CompressionAlgorithm,
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
match algorithm {
#[cfg(feature = "lz4_compress")]
CompressionAlgorithm::Lz4 => Lz4Compressor::decompress(in_net_packet, out),
#[cfg(feature = "zstd_compress")]
CompressionAlgorithm::Zstd => ZstdCompressor::decompress(in_net_packet, out),
_ => Err(anyhow!("Unknown decompress {:?}", algorithm)),
}
}
}
#[test]
#[cfg(feature = "zstd_compress")]
fn test_lz4() {
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
let lz4 = Compressor::Lz4;
let in_packet = NetPacket::new([
65, 108, 105, 99, 101, 32, 119, 97, 116, 32, 98, 101, 103, 105, 110, 110, 105, 110, 103,
32, 116, 111, 32, 103, 101, 116, 32, 118, 101, 114, 121, 32, 116, 105, 114, 101, 100, 32,
111, 102, 32, 115, 105, 116, 116, 105, 110, 103, 32, 98, 121, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 111, 110, 32, 116, 104, 101, 32, 98, 97, 110, 107, 44, 32, 97,
110, 100, 32, 111, 102, 32, 104, 97, 118, 105, 110, 103, 32, 110, 111, 116, 104, 105, 110,
103, 32, 116, 111, 32, 100, 111, 58, 32, 111, 110, 99, 101, 32, 111, 114, 32, 116, 119,
105, 99, 101, 32, 115, 104, 101, 32, 104, 97, 100, 32, 112, 101, 101, 112, 101, 100, 32,
105, 110, 116, 111, 32, 116, 104, 101, 32, 98, 111, 111, 107, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 119, 97, 115, 32, 114, 101, 97, 100, 105, 110, 103, 44, 32,
98, 117, 116, 32, 105, 116, 32, 104, 97, 100, 32, 110, 111, 32, 112, 105, 99, 116, 117,
114, 101, 115, 32, 111, 114, 32, 99, 111, 110, 118, 101, 114, 115, 97, 116, 105,
])
.unwrap();
let mut out_packet = NetPacket::new([0; 1000]).unwrap();
let mut src_out_packet = NetPacket::new([0; 1000]).unwrap();
lz4.compress(&in_packet, &mut out_packet).unwrap();
let tail = out_packet.split_tail_packet().unwrap();
match tail {
ExtensionTailPacket::Compression(c) => match c.algorithm() {
CompressionAlgorithm::Lz4 => {
Compressor::decompress(CompressionAlgorithm::Lz4, &out_packet, &mut src_out_packet)
.unwrap();
}
_ => {
unimplemented!()
}
},
_ => {
unimplemented!()
}
}
assert!(!out_packet.is_extension());
assert_eq!(in_packet.payload(), src_out_packet.payload())
}
#[test]
#[cfg(feature = "zstd_compress")]
fn test_zstd() {
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
let zstd = Compressor::Zstd(22);
let in_packet = NetPacket::new([
65, 108, 105, 99, 101, 32, 119, 97, 115, 32, 98, 101, 103, 105, 110, 110, 105, 110, 103,
32, 116, 111, 32, 103, 101, 116, 32, 118, 101, 114, 121, 32, 116, 105, 114, 101, 100, 32,
111, 102, 32, 115, 105, 116, 116, 105, 110, 103, 32, 98, 121, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 111, 110, 32, 116, 104, 101, 32, 98, 97, 110, 107, 44, 32, 97,
110, 100, 32, 111, 102, 32, 104, 97, 118, 105, 110, 103, 32, 110, 111, 116, 104, 105, 110,
103, 32, 116, 111, 32, 100, 111, 58, 32, 111, 110, 99, 101, 32, 111, 114, 32, 116, 119,
105, 99, 101, 32, 115, 104, 101, 32, 104, 97, 100, 32, 112, 101, 101, 112, 101, 100, 32,
105, 110, 116, 111, 32, 116, 104, 101, 32, 98, 111, 111, 107, 32, 104, 101, 114, 32, 115,
105, 115, 116, 101, 114, 32, 119, 97, 115, 32, 114, 101, 97, 100, 105, 110, 103, 44, 32,
98, 117, 116, 32, 105, 116, 32, 104, 97, 100, 32, 110, 111, 32, 112, 105, 99, 116, 117,
114, 101, 115, 32, 111, 114, 32, 99, 111, 110, 118, 101, 114, 115, 97, 116, 105,
])
.unwrap();
let mut out_packet = NetPacket::new([0; 1000]).unwrap();
let mut src_out_packet = NetPacket::new([0; 1000]).unwrap();
zstd.compress(&in_packet, &mut out_packet).unwrap();
let tail = out_packet.split_tail_packet().unwrap();
match tail {
ExtensionTailPacket::Compression(c) => match c.algorithm() {
CompressionAlgorithm::Zstd => {
Compressor::decompress(
CompressionAlgorithm::Zstd,
&out_packet,
&mut src_out_packet,
)
.unwrap();
}
_ => {
unimplemented!()
}
},
_ => {
unimplemented!()
}
}
assert!(!out_packet.is_extension());
assert_eq!(in_packet.payload(), src_out_packet.payload())
}
+38
View File
@@ -0,0 +1,38 @@
use crate::protocol::NetPacket;
use anyhow::anyhow;
use zstd::zstd_safe::CompressionLevel;
#[derive(Clone)]
pub struct ZstdCompressor;
impl ZstdCompressor {
pub fn compress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
compression_level: CompressionLevel,
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match zstd::zstd_safe::compress(
out.payload_mut(),
in_net_packet.payload(),
compression_level,
) {
Ok(len) => len,
Err(e) => Err(anyhow!("zstd compress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
pub fn decompress<I: AsRef<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<()> {
out.set_data_len_max();
let len = match zstd::zstd_safe::decompress(out.payload_mut(), in_net_packet.payload()) {
Ok(len) => len,
Err(e) => Err(anyhow!("zstd decompress {}", e))?,
};
out.set_payload_len(len)?;
Ok(())
}
}
+232 -115
View File
@@ -1,23 +1,22 @@
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::ops::Deref;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::{Mutex, RwLock};
use rand::Rng;
use rsa::signature::digest::Digest;
#[cfg(not(target_os = "android"))]
use tun::device::IFace;
use crate::channel::context::ChannelContext;
use crate::channel::idle::Idle;
use crate::channel::punch::{NatInfo, Punch};
use crate::channel::sender::IpPacketSender;
use crate::channel::{init_channel, init_context, Route, RouteKey};
use crate::cipher::Cipher;
#[cfg(feature = "server_encrypt")]
use crate::cipher::RsaCipher;
use crate::compression::Compressor;
use crate::core::Config;
use crate::external_route::{AllowExternalRoute, ExternalRoute};
use crate::handle::handshaker::Handshake;
@@ -25,31 +24,87 @@ use crate::handle::maintain::PunchReceiver;
use crate::handle::recv_data::RecvDataHandler;
use crate::handle::{maintain, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
use crate::nat::NatTest;
#[cfg(feature = "integrated_tun")]
use crate::tun_tap_device::tun_create_helper::{DeviceAdapter, TunDeviceHelper};
use crate::util::{
Scheduler, SingleU64Adder, StopManager, U64Adder, WatchSingleU64Adder, WatchU64Adder,
};
use crate::tun_tap_device::vnt_device::DeviceWrite;
use crate::util::limit::TrafficMeterMultiAddress;
use crate::util::{Scheduler, StopManager};
use crate::{nat, VntCallback};
#[cfg(not(target_os = "android"))]
use crate::{tun_tap_device, DeviceInfo};
#[derive(Clone)]
pub struct Vnt {
inner: Arc<VntInner>,
}
impl Vnt {
#[cfg(feature = "integrated_tun")]
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
let inner = Arc::new(VntInner::new(config, callback)?);
Ok(Self { inner })
}
#[cfg(not(feature = "integrated_tun"))]
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
config: Config,
callback: Call,
device: Device,
) -> anyhow::Result<Self> {
let inner = Arc::new(VntInner::new_device(config, callback, device)?);
Ok(Self { inner })
}
}
impl Deref for Vnt {
type Target = VntInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
pub struct VntInner {
stop_manager: StopManager,
config: Config,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
context: ChannelContext,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
context: Arc<Mutex<Option<ChannelContext>>>,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
down_count_watcher: WatchU64Adder,
up_count_watcher: WatchSingleU64Adder,
client_secret_hash: Option<[u8; 16]>,
compressor: Compressor,
client_cipher: Cipher,
server_cipher: Cipher,
external_route: ExternalRoute,
up_traffic_meter: Option<TrafficMeterMultiAddress>,
down_traffic_meter: Option<TrafficMeterMultiAddress>,
}
impl Vnt {
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> io::Result<Self> {
log::info!("config:{:?}", config);
impl VntInner {
#[cfg(feature = "integrated_tun")]
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
VntInner::new_device0(config, callback, DeviceAdapter::default())
}
#[cfg(not(feature = "integrated_tun"))]
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
config: Config,
callback: Call,
device: Device,
) -> anyhow::Result<Self> {
VntInner::new_device0(config, callback, device)
}
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
config: Config,
callback: Call,
device: Device,
) -> anyhow::Result<Self> {
log::info!("config: {:?}", config);
let (up_traffic_meter, down_traffic_meter) = if config.enable_traffic {
(
Some(TrafficMeterMultiAddress::default()),
Some(TrafficMeterMultiAddress::default()),
)
} else {
(None, None)
};
//服务端非对称加密
#[cfg(feature = "server_encrypt")]
let rsa_cipher: Arc<Mutex<Option<RsaCipher>>> = Arc::new(Mutex::new(None));
@@ -68,47 +123,64 @@ impl Vnt {
};
//客户端对称加密
let client_cipher =
Cipher::new_password(config.cipher_model, config.password.clone(), finger);
Cipher::new_password(config.cipher_model, config.password.clone(), finger)?;
//当前设备信息
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new0(
config.server_address,
)));
//设备列表
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> =
Arc::new(Mutex::new((0, Vec::with_capacity(16))));
let device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>> =
Arc::new(Mutex::new((0, HashMap::with_capacity(16))));
//基础信息
let config_info = BaseConfigInfo::new(
config.name.clone(),
config.token.clone(),
config.ip,
config.password.as_ref().map(|v| {
let mut hasher = sha2::Sha256::new();
hasher.update(config.cipher_model.to_string().as_bytes());
hasher.update(v.as_bytes());
hasher.update(config.token.as_bytes());
let key: [u8; 32] = hasher.finalize().into();
key[16..].try_into().unwrap()
}),
config.password_hash(),
config.server_encrypt,
config.device_id.clone(),
config.server_address_str.clone(),
config.name_servers.clone(),
config.mtu.unwrap_or(1420),
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
config.tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
config.device_name.clone(),
config.allow_wire_guard,
);
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,
config.use_channel_type,
config.first_latency,
config.tcp,
config.protocol,
config.packet_loss_rate,
config.packet_delay,
up_traffic_meter.clone(),
down_traffic_meter.clone(),
)?;
let local_ipv4 = nat::local_ipv4();
let local_ipv6 = nat::local_ipv6();
@@ -123,30 +195,16 @@ impl Vnt {
udp_ports,
tcp_port,
);
// pc上先创建虚拟网卡
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let device = {
let device = tun_tap_device::create_device(&config)?;
let tun_info = DeviceInfo::new(device.name()?, device.version()?);
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());
let out_external_route = AllowExternalRoute::new(config.out_ips.clone());
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
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(),
@@ -157,29 +215,26 @@ impl Vnt {
let (punch_sender, punch_receiver) = maintain::punch_channel();
let peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>> =
Arc::new(RwLock::new(HashMap::with_capacity(16)));
let down_counter =
U64Adder::with_capacity(config.ports.as_ref().map(|v| v.len()).unwrap_or_default() + 8);
let down_count_watcher = down_counter.watch();
let handshake = Handshake::new(rsa_cipher.clone());
let up_counter = SingleU64Adder::new();
let up_count_watcher = up_counter.watch();
let tun_helper = TunDeviceHelper::new(
stop_manager.clone(),
context.clone(),
current_device.clone(),
external_route.clone(),
#[cfg(feature = "ip_proxy")]
proxy_map.clone(),
client_cipher.clone(),
server_cipher.clone(),
config.parallel,
up_counter,
device_list.clone(),
let handshake = Handshake::new(
#[cfg(feature = "server_encrypt")]
rsa_cipher.clone(),
);
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let device_adapter = DeviceAdapter::new(device.clone());
#[cfg(target_os = "android")]
let device_adapter = DeviceAdapter::new(tun_helper);
#[cfg(feature = "integrated_tun")]
let tun_device_helper = {
TunDeviceHelper::new(
stop_manager.clone(),
context.clone(),
current_device.clone(),
external_route.clone(),
#[cfg(feature = "ip_proxy")]
proxy_map.clone(),
client_cipher.clone(),
server_cipher.clone(),
device_map.clone(),
config.compressor,
device.clone().into_device_adapter(),
)
};
let handler = RecvDataHandler::new(
#[cfg(feature = "server_encrypt")]
@@ -187,8 +242,8 @@ impl Vnt {
server_cipher.clone(),
client_cipher.clone(),
current_device.clone(),
device_adapter,
device_list.clone(),
device,
device_map.clone(),
config_info.clone(),
nat_test.clone(),
callback.clone(),
@@ -197,33 +252,36 @@ impl Vnt {
external_route.clone(),
out_external_route,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
proxy_map.clone(),
down_counter,
handshake.clone(),
#[cfg(feature = "integrated_tun")]
tun_device_helper,
);
//初始化网络数据通道
let (udp_socket_sender, tcp_socket_sender) =
let (udp_socket_sender, connect_util) =
init_channel(tcp_listener, context.clone(), stop_manager.clone(), handler)?;
// 打洞逻辑
let punch = Punch::new(
context.clone(),
config.punch_model,
config.tcp,
tcp_socket_sender.clone(),
config.protocol.is_base_tcp(),
connect_util.clone(),
external_route.clone(),
nat_test.clone(),
current_device.clone(),
);
#[cfg(not(target_os = "android"))]
tun_helper.start(device)?;
// #[cfg(not(target_os = "android"))]
// tun_helper.start(device)?;
maintain::idle_gateway(
&scheduler,
context.clone(),
current_device.clone(),
config_info.clone(),
tcp_socket_sender.clone(),
connect_util.clone(),
callback.clone(),
0,
handshake,
@@ -231,9 +289,7 @@ impl Vnt {
{
let context = context.clone();
let nat_test = nat_test.clone();
let device_list = device_list.clone();
let down_count_watcher = down_count_watcher.clone();
let up_count_watcher = up_count_watcher.clone();
let device_map = device_map.clone();
let config_info = config_info.clone();
let current_device = current_device.clone();
if !config.use_channel_type.is_only_relay() {
@@ -245,13 +301,15 @@ impl Vnt {
udp_socket_sender,
);
}
let client_cipher = client_cipher.clone();
let server_cipher = server_cipher.clone();
//延迟启动
scheduler.timeout(Duration::from_secs(3), move |scheduler| {
start(
scheduler,
context,
nat_test,
device_list,
device_map,
current_device,
client_cipher,
server_cipher,
@@ -259,23 +317,25 @@ impl Vnt {
config_info,
punch,
callback,
down_count_watcher,
up_count_watcher,
);
});
}
let compressor = config.compressor;
Ok(Self {
stop_manager,
config,
current_device,
nat_test,
device_list,
context,
device_map,
context: Arc::new(Mutex::new(Some(context))),
peer_nat_info_map,
down_count_watcher,
up_count_watcher,
client_secret_hash: config_info.client_secret_hash,
compressor,
client_cipher,
server_cipher,
external_route,
up_traffic_meter,
down_traffic_meter,
})
}
}
@@ -284,7 +344,7 @@ pub fn start<Call: VntCallback>(
scheduler: &Scheduler,
context: ChannelContext,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
server_cipher: Cipher,
@@ -292,15 +352,13 @@ pub fn start<Call: VntCallback>(
config_info: BaseConfigInfo,
punch: Punch,
callback: Call,
down_count_watcher: WatchU64Adder,
up_count_watcher: WatchSingleU64Adder,
) {
// 定时心跳
maintain::heartbeat(
&scheduler,
context.clone(),
current_device.clone(),
device_list.clone(),
device_map.clone(),
client_cipher.clone(),
server_cipher.clone(),
);
@@ -320,41 +378,36 @@ pub fn start<Call: VntCallback>(
&scheduler,
context.clone(),
current_device.clone(),
device_list.clone(),
device_map.clone(),
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(),
nat_test.clone(),
config_info.clone(),
);
// 定时打洞
maintain::punch(
&scheduler,
context.clone(),
nat_test.clone(),
device_list.clone(),
device_map.clone(),
current_device.clone(),
client_cipher.clone(),
punch_receiver,
punch,
);
}
maintain::up_status(
scheduler,
context.clone(),
current_device.clone(),
down_count_watcher,
up_count_watcher,
)
maintain::up_status(scheduler, context.clone(), current_device.clone())
}
impl Vnt {
impl VntInner {
pub fn name(&self) -> &str {
&self.config.name
}
@@ -370,6 +423,9 @@ impl Vnt {
pub fn current_device(&self) -> CurrentDeviceInfo {
self.current_device.load()
}
pub fn current_device_info(&self) -> Arc<AtomicCell<CurrentDeviceInfo>> {
self.current_device.clone()
}
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
self.peer_nat_info_map.read().get(ip).cloned()
}
@@ -380,33 +436,94 @@ impl Vnt {
self.nat_test.nat_info()
}
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
let device_list_lock = self.device_list.lock();
let device_list_lock = self.device_map.lock();
let (_epoch, device_list) = device_list_lock.clone();
drop(device_list_lock);
device_list
device_list.into_values().collect()
}
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
self.context.route_table.route_one(ip)
self.context.lock().as_ref()?.route_table.route_one(ip)
}
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
self.current_device.load().is_gateway(ip)
}
pub fn route_key(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
self.context.route_table.route_to_id(route_key)
self.context
.lock()
.as_ref()?
.route_table
.route_to_id(route_key)
}
pub fn route_table(&self) -> Vec<(Ipv4Addr, Vec<Route>)> {
self.context.route_table.route_table()
if let Some(context) = self.context.lock().as_ref() {
context.route_table.route_table()
} else {
vec![]
}
}
pub fn up_stream(&self) -> u64 {
self.up_count_watcher.get()
self.up_traffic_meter.as_ref().map_or(0, |v| v.total())
}
pub fn up_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
self.up_traffic_meter.as_ref().map(|v| v.get_all())
}
pub fn up_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
self.up_traffic_meter.as_ref().map(|v| v.get_all_history())
}
pub fn down_stream(&self) -> u64 {
self.down_count_watcher.get()
self.down_traffic_meter.as_ref().map_or(0, |v| v.total())
}
pub fn down_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
self.down_traffic_meter.as_ref().map(|v| v.get_all())
}
pub fn down_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
self.down_traffic_meter
.as_ref()
.map(|v| v.get_all_history())
}
pub fn stop(&self) {
//退出协助回收资源
let _ = self.context.lock().take();
self.stop_manager.stop()
}
pub fn is_stopped(&self) -> bool {
self.stop_manager.is_stopped()
}
pub fn add_stop_listener<F>(&self, name: String, f: F) -> anyhow::Result<crate::util::Worker>
where
F: FnOnce() + Send + 'static,
{
self.stop_manager.add_listener(name, f)
}
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
}
pub fn ipv4_packet_sender(&self) -> Option<IpPacketSender> {
if let Some(c) = self.context.lock().as_ref() {
Some(IpPacketSender::new(
c.clone(),
self.current_device.clone(),
self.compressor.clone(),
self.client_cipher.clone(),
self.server_cipher.clone(),
self.external_route.clone(),
self.device_map.clone(),
self.config.allow_wire_guard,
))
} else {
None
}
}
}
impl Drop for VntInner {
fn drop(&mut self) {
self.stop();
}
}
+100 -16
View File
@@ -5,15 +5,17 @@ use std::str::FromStr;
pub use conn::Vnt;
use crate::channel::punch::PunchModel;
use crate::channel::UseChannelType;
use crate::channel::{ConnectProtocol, UseChannelType};
use crate::cipher::CipherModel;
use crate::compression::Compressor;
use crate::util::{address_choose, dns_query_all};
mod conn;
#[derive(Clone, Debug)]
pub struct Config {
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
pub tap: bool,
pub token: String,
pub device_id: String,
@@ -26,52 +28,69 @@ pub struct Config {
pub out_ips: Vec<(u32, u32)>,
pub password: Option<String>,
pub mtu: Option<u32>,
pub tcp: bool,
pub protocol: ConnectProtocol,
pub ip: Option<Ipv4Addr>,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
pub no_proxy: bool,
pub server_encrypt: bool,
pub parallel: usize,
pub cipher_model: CipherModel,
pub finger: bool,
pub punch_model: PunchModel,
pub ports: Option<Vec<u16>>,
pub first_latency: bool,
#[cfg(not(target_os = "android"))]
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub device_name: Option<String>,
pub use_channel_type: UseChannelType,
//控制丢包率
pub packet_loss_rate: Option<f64>,
pub packet_delay: u32,
// 端口映射
#[cfg(feature = "port_mapping")]
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
pub compressor: Compressor,
pub enable_traffic: bool,
pub allow_wire_guard: bool,
}
impl Config {
pub fn new(
#[cfg(any(target_os = "windows", target_os = "linux"))] tap: bool,
#[cfg(feature = "integrated_tun")]
#[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>,
tcp: bool,
ip: Option<Ipv4Addr>,
#[cfg(feature = "ip_proxy")] no_proxy: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
no_proxy: bool,
server_encrypt: bool,
parallel: usize,
cipher_model: CipherModel,
finger: bool,
punch_model: PunchModel,
ports: Option<Vec<u16>>,
first_latency: bool,
#[cfg(not(target_os = "android"))] device_name: Option<String>,
#[cfg(feature = "integrated_tun")]
#[cfg(not(target_os = "android"))]
device_name: Option<String>,
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>,
compressor: Compressor,
enable_traffic: bool,
// 允许传递wg流量
allow_wire_guard: bool,
) -> anyhow::Result<Self> {
for x in stun_server.iter_mut() {
if !x.contains(":") {
@@ -94,10 +113,43 @@ impl Config {
if name.is_empty() || name.len() > 128 {
return Err(anyhow!("name too long"));
}
let server_address =
address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?;
let mut server_address_str = server_address_str.to_lowercase();
let mut _query_dns = true;
let mut protocol = ConnectProtocol::UDP;
if server_address_str.starts_with("ws://") {
#[cfg(not(feature = "ws"))]
Err(anyhow!("Ws not supported"))?;
protocol = ConnectProtocol::WS;
_query_dns = false;
}
if server_address_str.starts_with("wss://") {
#[cfg(not(feature = "wss"))]
Err(anyhow!("Wss not supported"))?;
protocol = ConnectProtocol::WSS;
_query_dns = false;
}
let mut server_address = "0.0.0.0:0".parse().unwrap();
if _query_dns {
if let Some(s) = server_address_str.strip_prefix("udp://") {
server_address_str = s.to_string();
} else if let Some(s) = server_address_str.strip_prefix("tcp://") {
server_address_str = s.to_string();
protocol = ConnectProtocol::TCP;
}
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(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap,
token,
device_id,
@@ -110,22 +162,54 @@ impl Config {
out_ips,
password,
mtu,
tcp,
protocol,
ip,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
no_proxy,
server_encrypt,
parallel,
cipher_model,
finger,
punch_model,
ports,
first_latency,
#[cfg(feature = "integrated_tun")]
#[cfg(not(target_os = "android"))]
device_name,
use_channel_type,
packet_loss_rate,
packet_delay,
#[cfg(feature = "port_mapping")]
port_mapping_list,
compressor,
enable_traffic,
allow_wire_guard,
})
}
}
impl Config {
pub fn password_hash(&self) -> Option<[u8; 16]> {
if let Some(p) = self.password.as_ref() {
match self.cipher_model {
CipherModel::Xor => {
let key = crate::cipher::simple_hash(&format!("Xor{}{}", p, self.token));
Some(key[16..].try_into().unwrap())
}
CipherModel::None => None,
#[cfg(cipher)]
_ => {
use sha2::Digest;
let mut hasher = sha2::Sha256::new();
hasher.update(self.cipher_model.to_string().as_bytes());
hasher.update(p.as_bytes());
hasher.update(self.token.as_bytes());
let key: [u8; 32] = hasher.finalize().into();
Some(key[16..].try_into().unwrap())
}
}
} else {
None
}
}
}
+14 -6
View File
@@ -1,15 +1,18 @@
use std::net::Ipv4Addr;
use std::sync::Arc;
// 目标ip,子网掩码,网关
// 目标网段,子网掩码,网关
#[derive(Clone)]
pub struct ExternalRoute {
route_table: Vec<(u32, u32, Ipv4Addr)>,
}
impl ExternalRoute {
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
pub fn new(mut route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
for (dest, mask, _) in &mut route_table {
*dest = *mask & *dest;
}
route_table.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1));
Self { route_table }
}
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
@@ -18,7 +21,7 @@ impl ExternalRoute {
}
let ip = u32::from_be_bytes(ip.octets());
for (dest, mask, gateway) in self.route_table.iter() {
if *mask & ip == *mask & *dest {
if *mask & ip == *dest {
return Some(*gateway);
}
}
@@ -27,18 +30,23 @@ impl ExternalRoute {
pub fn to_route(&self) -> Vec<(Ipv4Addr, Ipv4Addr)> {
self.route_table
.iter()
.map(|(dest, mask, _)| (Ipv4Addr::from(*dest & *mask), Ipv4Addr::from(*mask)))
.map(|(dest, mask, _)| (Ipv4Addr::from(*dest), Ipv4Addr::from(*mask)))
.collect::<Vec<(Ipv4Addr, Ipv4Addr)>>()
}
}
// 目标网段,子网掩码
#[derive(Clone)]
pub struct AllowExternalRoute {
route_table: Arc<Vec<(u32, u32)>>,
}
impl AllowExternalRoute {
pub fn new(route_table: Vec<(u32, u32)>) -> Self {
pub fn new(mut route_table: Vec<(u32, u32)>) -> Self {
for (dest, mask) in &mut route_table {
*dest = *mask & *dest;
}
route_table.sort_by(|(dest1, _), (dest2, _)| dest2.cmp(dest1));
Self {
route_table: Arc::new(route_table),
}
+28 -5
View File
@@ -189,9 +189,16 @@ impl Into<u8> for ErrorType {
}
}
#[cfg(target_os = "android")]
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct DeviceConfig {
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
pub tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub device_name: Option<String>,
//虚拟网卡mtu值
pub mtu: u32,
//本机虚拟IP
pub virtual_ip: Ipv4Addr,
//子网掩码
@@ -204,9 +211,15 @@ pub struct DeviceConfig {
pub external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
}
#[cfg(target_os = "android")]
impl DeviceConfig {
pub fn new(
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name: Option<String>,
mtu: u32,
virtual_ip: Ipv4Addr,
virtual_netmask: Ipv4Addr,
virtual_gateway: Ipv4Addr,
@@ -214,6 +227,13 @@ impl DeviceConfig {
external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
) -> Self {
Self {
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name,
mtu,
virtual_ip,
virtual_netmask,
virtual_gateway,
@@ -223,7 +243,6 @@ impl DeviceConfig {
}
}
#[cfg(target_os = "android")]
impl Display for DeviceConfig {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!(
@@ -272,6 +291,7 @@ pub trait VntCallback: Clone + Send + Sync + 'static {
/// 创建网卡的信息
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
#[cfg(feature = "integrated_tun")]
fn create_tun(&self, _info: DeviceInfo) {}
/// 连接
fn connect(&self, _info: ConnectInfo) {}
@@ -283,8 +303,11 @@ pub trait VntCallback: Clone + Send + Sync + 'static {
fn register(&self, _info: RegisterInfo) -> bool {
true
}
#[cfg(not(feature = "integrated_tun"))]
fn create_device(&self, _info: DeviceConfig) {}
#[cfg(target_os = "android")]
fn generate_tun(&self, _info: DeviceConfig) -> u32 {
#[cfg(feature = "integrated_tun")]
fn generate_tun(&self, _info: DeviceConfig) -> usize {
0
}
fn peer_client_list(&self, _info: Vec<PeerClientInfo>) {}
+24
View File
@@ -0,0 +1,24 @@
use crate::compression::Compressor;
use crate::protocol::extension::ExtensionTailPacket;
use crate::protocol::NetPacket;
use anyhow::anyhow;
pub fn handle_extension_tail<I: AsRef<[u8]> + AsMut<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>(
in_net_packet: &mut NetPacket<I>,
out: &mut NetPacket<O>,
) -> anyhow::Result<bool> {
if in_net_packet.is_extension() {
let tail_packet = in_net_packet.split_tail_packet()?;
match tail_packet {
ExtensionTailPacket::Compression(extension) => {
let compression_algorithm = extension.algorithm();
Compressor::decompress(compression_algorithm, &in_net_packet, out)?;
out.head_mut().copy_from_slice(in_net_packet.head());
Ok(true)
}
ExtensionTailPacket::Unknown => Err(anyhow!("Unknown decompress")),
}
} else {
Ok(false)
}
}
+13 -10
View File
@@ -4,6 +4,7 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
#[cfg(feature = "server_encrypt")]
use parking_lot::Mutex;
use protobuf::Message;
@@ -18,22 +19,23 @@ use crate::proto::message::SecretHandshakeRequest;
use crate::protocol::body::RSA_ENCRYPTION_RESERVED;
use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL};
pub enum HandshakeEnum {
NotSecret,
KeyError,
Timeout,
ServerError(String),
Other(String),
}
#[derive(Clone)]
pub struct Handshake {
time: Arc<AtomicCell<Instant>>,
#[cfg(feature = "server_encrypt")]
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
}
impl Handshake {
pub fn new(rsa_cipher: Arc<Mutex<Option<RsaCipher>>>) -> Self {
pub fn new(
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
) -> Self {
Handshake {
time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
time: Arc::new(AtomicCell::new(
Instant::now()
.checked_sub(Duration::from_secs(60))
.unwrap_or(Instant::now()),
)),
#[cfg(feature = "server_encrypt")]
rsa_cipher,
}
}
@@ -45,7 +47,7 @@ impl Handshake {
}
let request_packet = self.handshake_request_packet(secret)?;
log::info!("发送握手请求,secret={},{:?}", secret, addr);
context.send_default(request_packet.buffer(), addr)?;
context.send_default(&request_packet, addr)?;
self.time.store(Instant::now());
Ok(())
}
@@ -54,6 +56,7 @@ impl Handshake {
let mut request = HandshakeRequest::new();
request.secret = secret;
request.version = crate::VNT_VERSION.to_string();
#[cfg(feature = "server_encrypt")]
if let Some(finger) = self.rsa_cipher.lock().as_ref().map(|v| v.finger().clone()) {
request.key_finger = finger;
}
+40 -36
View File
@@ -4,64 +4,68 @@ use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::channel::punch::NatType;
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::{control_packet, NetPacket, Protocol, MAX_TTL};
use crate::nat::NatTest;
use crate::util::Scheduler;
pub fn addr_request(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
server_cipher: Cipher,
nat_test: NatTest,
_config: BaseConfigInfo,
) {
pub_address_request(
scheduler,
context,
current_device_info.clone(),
server_cipher,
);
pub_address_request(scheduler, context, current_device_info.clone(), nat_test, 0);
}
pub fn pub_address_request(
fn pub_address_request(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
server_cipher: Cipher,
nat_test: NatTest,
count: usize,
) {
addr_request0(&context, &current_device_info, &server_cipher);
// 9秒发送一次
let rs = scheduler.timeout(Duration::from_secs(9), |s| {
pub_address_request(s, context, current_device_info, server_cipher)
let channel_num = context.channel_num();
let index = count % channel_num;
if let Err(e) = addr_request0(&context, &current_device_info, &nat_test, index) {
log::warn!("{:?}", e);
}
let nat_info = nat_test.nat_info();
let time = if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
//对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改)
if nat_info.nat_type == NatType::Symmetric {
600
} else {
if index == channel_num - 1 {
19
} else {
9
}
}
} else {
3
};
let rs = scheduler.timeout(Duration::from_secs(time), move |s| {
pub_address_request(s, context, current_device_info, 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() {
// 如果连接的是ipv4服务,则探测公网端口
let gateway_ip = current_dev.virtual_gateway;
let src_ip = current_dev.virtual_ip;
let mut packet = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED]).unwrap();
packet.set_default_version();
packet.set_gateway_flag(true);
packet.set_protocol(Protocol::Control);
packet.set_transport_protocol(control_packet::Protocol::AddrRequest.into());
packet.first_set_ttl(MAX_TTL);
packet.set_source(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);
}
if current_dev.status.offline() {
return Ok(());
}
let (data, addr) = nat_test.send_data()?;
context.send_main_udp(index, &data, addr)?;
Ok(())
}
+32 -31
View File
@@ -1,4 +1,4 @@
use std::io;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::Duration;
@@ -20,14 +20,14 @@ pub fn heartbeat(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
client_cipher: Cipher,
server_cipher: Cipher,
) {
heartbeat0(
&context,
&current_device_info.load(),
&device_list,
&device_map,
&client_cipher,
&server_cipher,
);
@@ -37,7 +37,7 @@ pub fn heartbeat(
s,
context,
current_device_info,
device_list,
device_map,
client_cipher,
server_cipher,
)
@@ -50,7 +50,7 @@ pub fn heartbeat(
fn heartbeat0(
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
client_cipher: &Cipher,
server_cipher: &Cipher,
) {
@@ -58,10 +58,9 @@ fn heartbeat0(
let src_ip = current_device.virtual_ip;
// 可能服务器ip发生变化,导致发送失败
let mut is_send_gateway = false;
match heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip) {
match heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip) {
Ok(net_packet) => {
if let Err(e) = context.send_default(net_packet.buffer(), current_device.connect_server)
{
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
log::warn!("heartbeat err={:?}", e)
} else {
is_send_gateway = true
@@ -77,7 +76,7 @@ fn heartbeat0(
if is_send_gateway {
continue;
}
heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip)
heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip)
} else {
heartbeat_packet_client(client_cipher, src_ip, dest_ip)
};
@@ -89,14 +88,14 @@ fn heartbeat0(
}
};
for route in routes {
if let Err(e) = context.send_by_key(net_packet.buffer(), route.route_key()) {
if let Err(e) = context.send_by_key(&net_packet, route.route_key()) {
log::warn!("heartbeat err={:?}", e)
}
}
}
let peer_list = { device_list.lock().1.clone() };
for peer in &peer_list {
if !peer.status.is_online() {
let peer_list = { device_map.lock().1.clone() };
for peer in peer_list.values() {
if !peer.status.is_online() || peer.wireguard {
continue;
}
if current_device.is_gateway(&peer.virtual_ip) {
@@ -114,8 +113,7 @@ fn heartbeat0(
continue;
}
};
if let Err(e) = context.send_default(net_packet.buffer(), current_device.connect_server)
{
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
log::error!("heartbeat_packet send_default err={:?}", e);
}
}
@@ -127,11 +125,11 @@ pub fn client_relay(
scheduler: &Scheduler,
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
client_cipher: Cipher,
) {
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
client_relay_(s, context, current_device, device_list, client_cipher)
client_relay_(s, context, current_device, device_map, client_cipher)
});
if !rs {
log::info!("定时任务停止");
@@ -143,19 +141,19 @@ fn client_relay_(
scheduler: &Scheduler,
context: ChannelContext,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
client_cipher: Cipher,
) {
if let Err(e) = client_relay0(
&context,
&current_device.load(),
&device_list,
&device_map,
&client_cipher,
) {
log::error!("{:?}", e);
}
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
client_relay_(s, context, current_device, device_list, client_cipher)
client_relay_(s, context, current_device, device_map, client_cipher)
});
if !rs {
log::info!("定时任务停止");
@@ -165,17 +163,20 @@ fn client_relay_(
fn client_relay0(
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
client_cipher: &Cipher,
) -> io::Result<()> {
) -> anyhow::Result<()> {
// 离线了不再探测
if current_device.status.offline() {
return Ok(());
}
let peer_list = { device_list.lock().1.clone() };
let peer_list = { device_map.lock().1.clone() };
let mut routes = context.route_table.route_table_p2p();
for peer in &peer_list {
if !peer.status.is_online() || peer.virtual_ip == current_device.virtual_ip {
for peer in peer_list.values() {
if peer.wireguard
|| !peer.status.is_online()
|| peer.virtual_ip == current_device.virtual_ip
{
continue;
}
if context
@@ -196,7 +197,7 @@ fn client_relay0(
if current_device.is_gateway(ip) {
continue;
}
if let Err(e) = context.send_by_key(client_packet.buffer(), route.route_key()) {
if let Err(e) = context.send_by_key(&client_packet, route.route_key()) {
log::error!("{:?}", e);
}
if index >= 2 {
@@ -211,7 +212,7 @@ fn client_relay0(
fn heartbeat_packet(
src: Ipv4Addr,
dest: Ipv4Addr,
) -> io::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
let mut net_packet = NetPacket::new_encrypt([0u8; 12 + 4 + ENCRYPTION_RESERVED])?;
net_packet.set_default_version();
net_packet.set_protocol(Protocol::Control);
@@ -228,21 +229,21 @@ fn heartbeat_packet_client(
client_cipher: &Cipher,
src: Ipv4Addr,
dest: Ipv4Addr,
) -> io::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
let mut net_packet = heartbeat_packet(src, dest)?;
client_cipher.encrypt_ipv4(&mut net_packet)?;
Ok(net_packet)
}
fn heartbeat_packet_server(
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
server_cipher: &Cipher,
src: Ipv4Addr,
dest: Ipv4Addr,
) -> io::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
let mut net_packet = heartbeat_packet(src, dest)?;
let mut ping = PingPacket::new(net_packet.payload_mut())?;
ping.set_epoch(device_list.lock().0);
ping.set_epoch(device_map.lock().0);
net_packet.set_gateway_flag(true);
server_cipher.encrypt_ipv4(&mut net_packet)?;
Ok(net_packet)
+25 -25
View File
@@ -1,14 +1,13 @@
use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use mio::net::TcpStream;
use crate::channel::context::ChannelContext;
use crate::channel::idle::{Idle, IdleType};
use crate::channel::sender::AcceptSocketSender;
use crate::channel::sender::ConnectUtil;
use crate::channel::ConnectProtocol;
use crate::handle::callback::{ConnectInfo, ErrorType};
use crate::handle::handshaker::Handshake;
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
@@ -36,7 +35,7 @@ pub fn idle_gateway<Call: VntCallback>(
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
config: BaseConfigInfo,
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
connect_util: ConnectUtil,
call: Call,
mut connect_count: usize,
handshake: Handshake,
@@ -45,7 +44,7 @@ pub fn idle_gateway<Call: VntCallback>(
&context,
&current_device_info,
&config,
&tcp_socket_sender,
&connect_util,
&call,
&mut connect_count,
&handshake,
@@ -56,7 +55,7 @@ pub fn idle_gateway<Call: VntCallback>(
context,
current_device_info,
config,
tcp_socket_sender,
connect_util,
call,
connect_count,
handshake,
@@ -71,7 +70,7 @@ fn idle_gateway0<Call: VntCallback>(
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
config: &BaseConfigInfo,
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
connect_util: &ConnectUtil,
call: &Call,
connect_count: &mut usize,
handshake: &Handshake,
@@ -80,7 +79,7 @@ fn idle_gateway0<Call: VntCallback>(
context,
current_device,
config,
tcp_socket_sender,
connect_util,
call,
connect_count,
handshake,
@@ -120,7 +119,7 @@ fn check_gateway_channel<Call: VntCallback>(
context: &ChannelContext,
current_device_info: &AtomicCell<CurrentDeviceInfo>,
config: &BaseConfigInfo,
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
connect_util: &ConnectUtil,
call: &Call,
count: &mut usize,
handshake: &Handshake,
@@ -128,28 +127,29 @@ fn check_gateway_channel<Call: VntCallback>(
let mut current_device = current_device_info.load();
if current_device.status.offline() {
*count += 1;
// 探测服务器地址
current_device = domain_request0(current_device_info, config);
let connect_protocol = context.main_protocol();
if connect_protocol.is_transport() {
// 传输层的协议需要探测服务器地址
current_device = domain_request0(current_device_info, config);
}
//需要重连
call.connect(ConnectInfo::new(*count, current_device.connect_server));
log::info!("发送握手请求,{:?}", config);
if let Err(e) = handshake.send(context, config.server_secret, current_device.connect_server)
{
log::warn!("{:?}", e);
if context.is_main_tcp() {
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
//tcp需要重连
let tcp_stream = std::net::TcpStream::connect_timeout(
&current_device.connect_server,
Duration::from_secs(5),
)?;
tcp_stream.set_nonblocking(true)?;
if let Err(e) = tcp_socket_sender.try_add_socket((
TcpStream::from_std(tcp_stream),
current_device.connect_server,
Some(request_packet.into_buffer()),
)) {
log::warn!("{:?}", e)
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
match connect_protocol {
ConnectProtocol::UDP => {}
ConnectProtocol::TCP => {
connect_util.try_connect_tcp(
request_packet.into_buffer(),
current_device.connect_server,
);
}
ConnectProtocol::WS | ConnectProtocol::WSS => {
connect_util
.try_connect_ws(request_packet.into_buffer(), config.server_addr.clone());
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ mod re_nat_type;
pub use re_nat_type::retrieve_nat_type;
mod addr_request;
pub use addr_request::addr_request;
pub use addr_request::*;
mod punch;
pub use punch::*;
+23 -19
View File
@@ -1,10 +1,12 @@
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::ops::{Div, Mul};
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{io, thread};
use anyhow::anyhow;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use protobuf::Message;
@@ -88,7 +90,7 @@ pub fn punch(
scheduler: &Scheduler,
context: ChannelContext,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
receiver: PunchReceiver,
@@ -100,7 +102,7 @@ pub fn punch(
scheduler,
context,
nat_test,
device_list,
device_map,
current_device.clone(),
client_cipher.clone(),
0,
@@ -157,7 +159,7 @@ fn punch_start(
log::error!("{:?}", e);
continue;
}
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info, count < 2) {
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info, count < 2, count) {
log::warn!("{:?}", e)
}
}
@@ -168,7 +170,7 @@ fn punch_request(
scheduler: &Scheduler,
context: ChannelContext,
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
count: usize,
@@ -180,7 +182,7 @@ fn punch_request(
if let Err(e) = punch0(
&context,
&nat_test,
&device_list,
&device_map,
curr,
&client_cipher,
&punch_record,
@@ -189,7 +191,7 @@ fn punch_request(
) {
log::warn!("{:?}", e)
}
let sleep_time = [5, 6, 7];
let sleep_time = [6, 7];
Duration::from_secs(sleep_time[count % sleep_time.len()])
} else {
Duration::from_secs(5)
@@ -199,7 +201,7 @@ fn punch_request(
s,
context,
nat_test,
device_list,
device_map,
current_device,
client_cipher,
count + 1,
@@ -216,13 +218,13 @@ fn punch_request(
fn punch0(
context: &ChannelContext,
nat_test: &NatTest,
device_list: &Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: &Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
current_device: CurrentDeviceInfo,
client_cipher: &Cipher,
punch_record: &Mutex<HashMap<Ipv4Addr, usize>>,
last_punch_record: &mut HashMap<Ipv4Addr, usize>,
total_count: usize,
) -> io::Result<()> {
) -> anyhow::Result<()> {
let nat_info = nat_test.nat_info();
if total_count < 10
&& (nat_info.public_ips.is_empty()
@@ -231,15 +233,15 @@ fn punch0(
|| nat_info.public_ports.iter().filter(|&&v| v == 0).count()
> nat_info.public_ports.len() / 2)
{
log::info!("公网地址为空,暂时放弃打洞,第{}轮", total_count);
log::info!("未获取到公网地址,暂时放弃打洞,第{}轮", total_count);
return Ok(());
}
let current_ip = current_device.virtual_ip;
let mut list: Vec<PeerDeviceInfo> = device_list
let mut list: Vec<PeerDeviceInfo> = device_map
.lock()
.1
.iter()
.filter(|info| info.status.is_online() && info.virtual_ip > current_ip)
.values()
.filter(|info| !info.wireguard && info.status.is_online() && info.virtual_ip > current_ip)
.cloned()
.collect();
list.shuffle(&mut rand::thread_rng());
@@ -248,9 +250,11 @@ fn punch0(
.lock()
.get(&info.virtual_ip)
.cloned()
.unwrap_or(0);
.unwrap_or(0)
.mul(2)
.div(3);
let p2p_num = context.route_table.p2p_num(&info.virtual_ip);
let mut max_punch_interval = 70;
let mut max_punch_interval = 50;
if p2p_num > 0 {
if punch_count == 0 {
continue;
@@ -285,7 +289,7 @@ fn punch0(
punch_count,
total_count,
);
context.send_default(packet.buffer(), current_device.connect_server)?;
context.send_default(&packet, current_device.connect_server)?;
break;
}
}
@@ -297,7 +301,7 @@ fn punch_packet(
virtual_ip: Ipv4Addr,
nat_info: &NatInfo,
dest: Ipv4Addr,
) -> io::Result<NetPacket<Vec<u8>>> {
) -> anyhow::Result<NetPacket<Vec<u8>>> {
let mut punch_reply = PunchInfo::new();
punch_reply.reply = false;
punch_reply.public_ip_list = nat_info
@@ -320,7 +324,7 @@ fn punch_packet(
log::info!("请求打洞={:?}", punch_reply);
let bytes = punch_reply
.write_to_bytes()
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("punch_packet {:?}", e)))?;
.map_err(|e| anyhow!("punch_packet {:?}", e))?;
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
net_packet.set_default_version();
net_packet.set_protocol(Protocol::OtherTurn);
+3
View File
@@ -42,6 +42,9 @@ fn retrieve_nat_type0(
log::warn!("nat re_test {:?}", e);
}
};
#[cfg(feature = "upnp")]
nat_test.reset_upnp();
log::info!("刷新nat结束")
}
})
.expect("natTest");
+7 -30
View File
@@ -3,7 +3,7 @@ use crate::handle::CurrentDeviceInfo;
use crate::proto::message::{ClientStatusInfo, PunchNatType, RouteItem};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::{service_packet, NetPacket, Protocol, HEAD_LEN, MAX_TTL};
use crate::util::{Scheduler, WatchSingleU64Adder, WatchU64Adder};
use crate::util::Scheduler;
use crossbeam_utils::atomic::AtomicCell;
use protobuf::Message;
use std::io;
@@ -15,17 +15,9 @@ pub fn up_status(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
down_count_watcher: WatchU64Adder,
up_count_watcher: WatchSingleU64Adder,
) {
let _ = scheduler.timeout(Duration::from_secs(60), move |x| {
up_status0(
x,
context,
current_device_info,
down_count_watcher,
up_count_watcher,
)
up_status0(x, context, current_device_info)
});
}
@@ -33,25 +25,12 @@ fn up_status0(
scheduler: &Scheduler,
context: ChannelContext,
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
down_count_watcher: WatchU64Adder,
up_count_watcher: WatchSingleU64Adder,
) {
if let Err(e) = send_up_status_packet(
&context,
&current_device_info,
&down_count_watcher,
&up_count_watcher,
) {
if let Err(e) = send_up_status_packet(&context, &current_device_info) {
log::warn!("{:?}", e)
}
let rs = scheduler.timeout(Duration::from_secs(10 * 60), move |x| {
up_status0(
x,
context,
current_device_info,
down_count_watcher,
up_count_watcher,
)
up_status0(x, context, current_device_info)
});
if !rs {
log::info!("定时任务停止");
@@ -61,8 +40,6 @@ fn up_status0(
fn send_up_status_packet(
context: &ChannelContext,
current_device_info: &AtomicCell<CurrentDeviceInfo>,
down_count_watcher: &WatchU64Adder,
up_count_watcher: &WatchSingleU64Adder,
) -> io::Result<()> {
let device_info = current_device_info.load();
if device_info.status.offline() {
@@ -79,8 +56,8 @@ fn send_up_status_packet(
item.next_ip = ip.into();
message.p2p_list.push(item);
}
message.up_stream = up_count_watcher.get();
message.down_stream = down_count_watcher.get();
message.up_stream = context.up_traffic_meter.as_ref().map_or(0, |v| v.total());
message.down_stream = context.down_traffic_meter.as_ref().map_or(0, |v| v.total());
message.nat_type = protobuf::EnumOrUnknown::new(if context.is_cone() {
PunchNatType::Cone
} else {
@@ -99,6 +76,6 @@ fn send_up_status_packet(
net_packet.set_source(device_info.virtual_ip);
net_packet.set_destination(device_info.virtual_gateway);
net_packet.set_payload(&buf)?;
context.send_default(net_packet.buffer(), device_info.connect_server)?;
context.send_default(&net_packet, device_info.connect_server)?;
Ok(())
}
+48 -7
View File
@@ -1,11 +1,13 @@
use crossbeam_utils::atomic::AtomicCell;
use std::net::{Ipv4Addr, SocketAddr};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
pub mod callback;
mod extension;
pub mod handshaker;
pub mod maintain;
pub mod recv_data;
pub mod registrar;
#[cfg(feature = "integrated_tun")]
pub mod tun_tap;
const SELF_IP: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 2);
@@ -20,12 +22,6 @@ pub fn now_time() -> u64 {
}
}
/// 是否在一个网段
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(virtual_netmask.octets())
== u32::from_be_bytes(virtual_network.octets())
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PeerDeviceInfo {
pub virtual_ip: Ipv4Addr,
@@ -33,6 +29,7 @@ pub struct PeerDeviceInfo {
pub status: PeerDeviceStatus,
pub client_secret: bool,
pub client_secret_hash: Vec<u8>,
pub wireguard: bool,
}
impl PeerDeviceInfo {
@@ -42,6 +39,7 @@ impl PeerDeviceInfo {
status: u8,
client_secret: bool,
client_secret_hash: Vec<u8>,
wireguard: bool,
) -> Self {
Self {
virtual_ip,
@@ -49,6 +47,7 @@ impl PeerDeviceInfo {
status: PeerDeviceStatus::from(status),
client_secret,
client_secret_hash,
wireguard,
}
}
}
@@ -63,6 +62,14 @@ pub struct BaseConfigInfo {
pub device_id: String,
pub server_addr: String,
pub name_servers: Vec<String>,
pub mtu: u32,
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
pub tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub device_name: Option<String>,
pub allow_wire_guard: bool,
}
impl BaseConfigInfo {
@@ -75,6 +82,14 @@ impl BaseConfigInfo {
device_id: String,
server_addr: String,
name_servers: Vec<String>,
mtu: u32,
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap: bool,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name: Option<String>,
allow_wire_guard: bool,
) -> Self {
Self {
name,
@@ -85,6 +100,14 @@ impl BaseConfigInfo {
device_id,
server_addr,
name_servers,
mtu,
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
device_name,
allow_wire_guard,
}
}
}
@@ -99,6 +122,9 @@ impl PeerDeviceStatus {
pub fn is_online(&self) -> bool {
self == &PeerDeviceStatus::Online
}
pub fn is_offline(&self) -> bool {
self == &PeerDeviceStatus::Offline
}
}
impl Into<u8> for PeerDeviceStatus {
@@ -212,9 +238,24 @@ impl CurrentDeviceInfo {
pub fn virtual_gateway(&self) -> Ipv4Addr {
self.virtual_gateway
}
#[inline]
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
&self.virtual_gateway == ip || ip == &GATEWAY_IP
}
#[inline]
pub fn not_in_network(&self, ip: Ipv4Addr) -> bool {
u32::from(ip) & u32::from(self.virtual_netmask) != u32::from(self.virtual_network)
}
pub fn is_server_addr(&self, addr: SocketAddr) -> bool {
if self.connect_server == addr {
return true;
}
let f = |ip: IpAddr| match ip {
IpAddr::V4(v4) => Some(v4),
IpAddr::V6(v6) => v6.to_ipv4(),
};
addr.port() == self.connect_server.port() && f(addr.ip()) == f(self.connect_server.ip())
}
}
pub fn change_status(
current_device: &AtomicCell<CurrentDeviceInfo>,
+62 -39
View File
@@ -1,10 +1,11 @@
use parking_lot::RwLock;
use protobuf::Message;
use anyhow::anyhow;
use std::collections::HashMap;
use std::io;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::Arc;
use parking_lot::RwLock;
use protobuf::Message;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
@@ -14,6 +15,7 @@ use crate::channel::punch::NatInfo;
use crate::channel::{Route, RouteKey};
use crate::cipher::Cipher;
use crate::external_route::AllowExternalRoute;
use crate::handle::extension::handle_extension_tail;
use crate::handle::maintain::PunchSender;
use crate::handle::recv_data::PacketHandler;
use crate::handle::CurrentDeviceInfo;
@@ -26,32 +28,33 @@ use crate::protocol::control_packet::ControlPacket;
use crate::protocol::{
control_packet, ip_turn_packet, other_turn_packet, NetPacket, Protocol, MAX_TTL,
};
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
use tun::device::IFace;
use crate::tun_tap_device::vnt_device::DeviceWrite;
/// 处理来源于客户端的包
#[derive(Clone)]
pub struct ClientPacketHandler {
device: DeviceAdapter,
pub struct ClientPacketHandler<Device> {
device: Device,
client_cipher: Cipher,
punch_sender: PunchSender,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
nat_test: NatTest,
route: AllowExternalRoute,
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
ip_proxy_map: Option<IpProxyMap>,
}
impl ClientPacketHandler {
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
pub fn new(
device: DeviceAdapter,
device: Device,
client_cipher: Cipher,
punch_sender: PunchSender,
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
nat_test: NatTest,
route: AllowExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map: Option<IpProxyMap>,
) -> Self {
Self {
device,
@@ -60,24 +63,37 @@ impl ClientPacketHandler {
peer_nat_info_map,
nat_test,
route,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
}
}
}
impl PacketHandler for ClientPacketHandler {
impl<Device: DeviceWrite> PacketHandler for ClientPacketHandler<Device> {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
mut extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
) -> io::Result<()> {
) -> anyhow::Result<()> {
self.client_cipher.decrypt_ipv4(&mut net_packet)?;
context
.route_table
.update_read_time(&net_packet.source(), &route_key);
//处理扩展
let net_packet = if net_packet.is_extension() {
//这样重用数组,减少一次数据拷贝
if handle_extension_tail(&mut net_packet, &mut extend)? {
extend
} else {
net_packet
}
} else {
net_packet
};
match net_packet.protocol() {
Protocol::Service => {}
Protocol::Error => {}
@@ -96,14 +112,14 @@ impl PacketHandler for ClientPacketHandler {
}
}
impl ClientPacketHandler {
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
fn ip_turn(
&self,
mut net_packet: NetPacket<&mut [u8]>,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
route_key: RouteKey,
) -> io::Result<()> {
) -> anyhow::Result<()> {
let destination = net_packet.destination();
let source = net_packet.source();
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
@@ -124,7 +140,7 @@ impl ClientPacketHandler {
net_packet.set_destination(source);
//不管加不加密,和接收到的数据长度都一致
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_by_key(net_packet.buffer(), route_key)?;
context.send_by_key(&net_packet, route_key)?;
return Ok(());
}
}
@@ -169,6 +185,7 @@ impl ClientPacketHandler {
_ => {}
}
#[cfg(feature = "ip_proxy")]
#[cfg(feature = "integrated_tun")]
if let Some(ip_proxy_map) = &self.ip_proxy_map {
if ip_proxy_map.recv_handle(&mut ipv4, source, destination)? {
return Ok(());
@@ -177,6 +194,9 @@ impl ClientPacketHandler {
}
self.device.write(net_packet.payload())?;
}
ip_turn_packet::Protocol::WGIpv4 => {
// WG客户端的数据不会直接发过来,不用处理
}
ip_turn_packet::Protocol::Ipv4Broadcast => {
//客户端不帮忙转发广播包,所以不会出现这种类型的数据
}
@@ -190,19 +210,23 @@ impl ClientPacketHandler {
current_device: &CurrentDeviceInfo,
mut net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::Result<()> {
) -> anyhow::Result<()> {
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
let source = net_packet.source();
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
ControlPacket::PingPacket(_) => {
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
net_packet.set_source(current_device.virtual_ip);
net_packet.set_destination(source);
net_packet.first_set_ttl(MAX_TTL);
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_by_key(net_packet.buffer(), route_key)?;
let route = Route::from_default_rt(route_key, metric);
context.route_table.add_route_if_absent(source, route);
if context.route_table.add_route_if_absent(source, route)
|| net_packet.source() < current_device.virtual_ip
{
//在路由表中,或者来源比自己小,就需要回复,注意不能调换顺序
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
net_packet.set_source(current_device.virtual_ip);
net_packet.set_destination(source);
net_packet.first_set_ttl(MAX_TTL);
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_by_key(&net_packet, route_key)?;
}
}
ControlPacket::PongPacket(pong_packet) => {
let current_time = crate::handle::now_time() as u16;
@@ -221,7 +245,7 @@ impl ClientPacketHandler {
//忽略掉来源于自己的包
if self
.nat_test
.is_local_address(route_key.is_tcp(), route_key.addr)
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
{
return Ok(());
}
@@ -232,9 +256,10 @@ impl ClientPacketHandler {
net_packet.set_destination(source);
net_packet.first_set_ttl(1);
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_by_key(net_packet.buffer(), route_key)?;
let route = Route::from_default_rt(route_key, 1);
context.route_table.add_route_if_absent(source, route);
context.send_by_key(&net_packet, route_key)?;
// 收到PunchRequest就添加路由,会导致单向通信的问题,删掉试试
// let route = Route::from_default_rt(route_key, 1);
// context.route_table.add_route_if_absent(source, route);
}
ControlPacket::PunchResponse => {
log::info!("PunchResponse={:?},source={}", route_key, source);
@@ -243,7 +268,7 @@ impl ClientPacketHandler {
}
if self
.nat_test
.is_local_address(route_key.is_tcp(), route_key.addr)
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
{
return Ok(());
}
@@ -263,7 +288,7 @@ impl ClientPacketHandler {
addr_packet.set_ipv4(ipv4);
addr_packet.set_port(route_key.addr.port());
self.client_cipher.encrypt_ipv4(&mut packet)?;
context.send_by_key(packet.buffer(), route_key)?;
context.send_by_key(&packet, route_key)?;
}
std::net::IpAddr::V6(_) => {}
},
@@ -277,17 +302,15 @@ impl ClientPacketHandler {
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if context.use_channel_type().is_only_relay() {
return Ok(());
}
let source = net_packet.source();
match other_turn_packet::Protocol::from(net_packet.transport_protocol()) {
other_turn_packet::Protocol::Punch => {
let mut punch_info =
PunchInfo::parse_from_bytes(net_packet.payload()).map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("PunchInfo {:?}", e))
})?;
let mut punch_info = PunchInfo::parse_from_bytes(net_packet.payload())
.map_err(|e| anyhow!("PunchInfo {:?}", e))?;
let public_ips = punch_info
.public_ip_list
.iter()
@@ -347,9 +370,9 @@ impl ClientPacketHandler {
punch_reply.ipv6 = ipv6.octets().to_vec();
punch_reply.ipv6_port = nat_info.udp_ports[0] as u32;
}
let bytes = punch_reply.write_to_bytes().map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("punch_reply {:?}", e))
})?;
let bytes = punch_reply
.write_to_bytes()
.map_err(|e| anyhow!("punch_reply {:?}", e))?;
let mut punch_packet =
NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
punch_packet.set_default_version();
@@ -361,7 +384,7 @@ impl ClientPacketHandler {
punch_packet.set_payload(&bytes)?;
self.client_cipher.encrypt_ipv4(&mut punch_packet)?;
if self.punch_sender.send(true, source, peer_nat_info) {
context.send_by_key(punch_packet.buffer(), route_key)?;
context.send_by_key(&punch_packet, route_key)?;
}
} else {
self.punch_sender.send(false, source, peer_nat_info);
+65 -29
View File
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use std::thread;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::{Mutex, RwLock};
@@ -24,39 +24,63 @@ use crate::handle::{BaseConfigInfo, CurrentDeviceInfo, PeerDeviceInfo, SELF_IP};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::nat::NatTest;
use crate::protocol::NetPacket;
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
use crate::util::U64Adder;
use crate::protocol::{NetPacket, HEAD_LEN};
use crate::tun_tap_device::vnt_device::DeviceWrite;
mod client;
mod server;
mod turn;
#[derive(Clone)]
pub struct RecvDataHandler<Call> {
pub struct RecvDataHandler<Call, Device> {
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
turn: TurnPacketHandler,
client: ClientPacketHandler,
server: ServerPacketHandler<Call>,
counter: U64Adder,
client: ClientPacketHandler<Device>,
server: ServerPacketHandler<Call, Device>,
nat_test: NatTest,
}
impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
fn handle(&mut self, buf: &mut [u8], route_key: RouteKey, context: &ChannelContext) {
if let Err(e) = self.handle0(buf, route_key, context) {
log::error!("[{}]-{:?}", thread::current().name().unwrap_or(""), e);
impl<Call: VntCallback, Device: DeviceWrite> RecvChannelHandler for RecvDataHandler<Call, Device> {
fn handle(
&self,
buf: &mut [u8],
extend: &mut [u8],
route_key: RouteKey,
context: &ChannelContext,
) {
if buf.len() < HEAD_LEN {
return;
}
//判断stun响应包
if route_key.protocol().is_udp() {
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, extend, route_key, context) {
log::error!(
"[{}]-{:?}-{:?}",
thread::current().name().unwrap_or(""),
route_key.addr,
e
);
}
}
}
impl<Call: VntCallback> RecvDataHandler<Call> {
impl<Call: VntCallback, Device: DeviceWrite> RecvDataHandler<Call, Device> {
pub fn new(
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
client_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: DeviceAdapter,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device: Device,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
@@ -64,9 +88,12 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
external_route: ExternalRoute,
route: AllowExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
counter: U64Adder,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map: Option<IpProxyMap>,
handshake: Handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
) -> Self {
let server = ServerPacketHandler::new(
#[cfg(feature = "server_encrypt")]
@@ -74,20 +101,23 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
server_cipher,
current_device.clone(),
device.clone(),
device_list,
device_map,
config_info,
nat_test.clone(),
callback,
external_route.clone(),
handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper,
);
let client = ClientPacketHandler::new(
device.clone(),
client_cipher,
punch_sender,
peer_nat_info_map,
nat_test,
nat_test.clone(),
route,
#[cfg(feature = "integrated_tun")]
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
);
@@ -97,20 +127,21 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
turn,
client,
server,
counter,
nat_test,
}
}
fn handle0(
&mut self,
&self,
buf: &mut [u8],
extend: &mut [u8],
route_key: RouteKey,
context: &ChannelContext,
) -> io::Result<()> {
// 统计流量
self.counter.add(buf.len() as _);
) -> anyhow::Result<()> {
let net_packet = NetPacket::new(buf)?;
let extend = NetPacket::unchecked(extend);
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
log::warn!("丢弃过时包:{:?}", net_packet.head());
log::warn!("丢弃过时包:{:?} {}", net_packet.head(), route_key.addr);
return Ok(());
}
let current_device = self.current_device.load();
@@ -122,20 +153,24 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|| dest.is_unspecified()
|| dest == current_device.broadcast_ip
{
// 统计流量
if let Some(down_traffic_meter) = &context.down_traffic_meter {
down_traffic_meter.add_traffic(net_packet.source(), net_packet.data_len())
}
//发给自己的包
if net_packet.is_gateway() {
//服务端-客户端包
self.server
.handle(net_packet, route_key, context, &current_device)
.handle(net_packet, extend, route_key, context, &current_device)
} else {
//客户端-客户端包
self.client
.handle(net_packet, route_key, context, &current_device)
.handle(net_packet, extend, route_key, context, &current_device)
}
} else {
//转发包
self.turn
.handle(net_packet, route_key, context, &current_device)
.handle(net_packet, extend, route_key, context, &current_device)
}
}
}
@@ -144,8 +179,9 @@ pub trait PacketHandler {
fn handle(
&self,
net_packet: NetPacket<&mut [u8]>,
extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
) -> io::Result<()>;
) -> anyhow::Result<()>;
}
+136 -108
View File
@@ -1,3 +1,5 @@
use anyhow::anyhow;
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
@@ -23,52 +25,50 @@ use crate::handle::callback::{ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo,
use crate::handle::handshaker;
use crate::handle::handshaker::Handshake;
use crate::handle::recv_data::PacketHandler;
use crate::handle::{
registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, GATEWAY_IP,
};
use crate::handle::{registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
use crate::nat::NatTest;
use crate::proto::message::{DeviceList, HandshakeResponse, RegistrationResponse};
use crate::protocol::body::ENCRYPTION_RESERVED;
use crate::protocol::control_packet::ControlPacket;
use crate::protocol::error_packet::InErrorPacket;
use crate::protocol::{ip_turn_packet, service_packet, NetPacket, Protocol, MAX_TTL};
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
use crate::tun_tap_device::vnt_device::DeviceWrite;
use crate::{proto, PeerClientInfo};
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
use tun::device::IFace;
/// 处理来源于服务端的包
#[derive(Clone)]
pub struct ServerPacketHandler<Call> {
pub struct ServerPacketHandler<Call, Device> {
#[cfg(feature = "server_encrypt")]
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: DeviceAdapter,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device: Device,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
#[cfg(feature = "server_encrypt")]
up_key_time: Arc<AtomicCell<Instant>>,
#[cfg(not(target_os = "android"))]
route_record: Arc<Mutex<Vec<(Ipv4Addr, Ipv4Addr)>>>,
external_route: ExternalRoute,
handshake: Handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
}
impl<Call> ServerPacketHandler<Call> {
impl<Call, Device> ServerPacketHandler<Call, Device> {
pub fn new(
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
server_cipher: Cipher,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
device: DeviceAdapter,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device: Device,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
config_info: BaseConfigInfo,
nat_test: NatTest,
callback: Call,
external_route: ExternalRoute,
handshake: Handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
) -> Self {
Self {
#[cfg(feature = "server_encrypt")]
@@ -76,28 +76,42 @@ impl<Call> ServerPacketHandler<Call> {
server_cipher,
current_device,
device,
device_list,
device_map,
config_info,
nat_test,
callback,
#[cfg(feature = "server_encrypt")]
up_key_time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
#[cfg(not(target_os = "android"))]
route_record: Arc::new(Mutex::default()),
up_key_time: Arc::new(AtomicCell::new(
Instant::now()
.checked_sub(Duration::from_secs(60))
.unwrap_or(Instant::now()),
)),
external_route,
handshake,
#[cfg(feature = "integrated_tun")]
tun_device_helper,
}
}
}
impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandler<Call, Device> {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
_extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if !current_device.is_server_addr(route_key.addr) {
//拦截不是服务端的流量
log::info!(
"route_key={:?},不是来源于服务端地址{}",
route_key,
current_device.connect_server
);
return Ok(());
}
context
.route_table
.update_read_time(&net_packet.source(), &route_key);
@@ -127,7 +141,7 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
self.config_info.token.clone(),
key,
)?;
context.send_by_key(packet.buffer(), route_key)?;
context.send_by_key(&packet, route_key)?;
}
}
}
@@ -135,10 +149,8 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
} else if net_packet.protocol() == Protocol::Service
&& net_packet.transport_protocol() == service_packet::Protocol::HandshakeResponse.into()
{
let response =
HandshakeResponse::parse_from_bytes(net_packet.payload()).map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("HandshakeResponse {:?}", e))
})?;
let response = HandshakeResponse::parse_from_bytes(net_packet.payload())
.map_err(|e| anyhow!("HandshakeResponse {:?}", e))?;
log::info!("握手响应:{:?},{}", route_key, response);
//如果开启了加密,则发送加密握手请求
#[cfg(feature = "server_encrypt")]
@@ -153,7 +165,7 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
key,
)?;
drop(guard);
context.send_by_key(packet.buffer(), route_key)?;
context.send_by_key(&packet, route_key)?;
return Ok(());
}
log::warn!(
@@ -188,11 +200,12 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
self.config_info.token.clone(),
key,
)?;
context.send_by_key(packet.buffer(), route_key)?;
context.send_by_key(&packet, route_key)?;
self.rsa_cipher.lock().replace(rsa_cipher);
}
return Ok(());
}
#[cfg(feature = "server_encrypt")]
if let Ok(rsa_cipher) = RsaCipher::new(&response.public_key) {
self.rsa_cipher.lock().replace(rsa_cipher);
}
@@ -234,6 +247,11 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
_ => {}
}
}
ip_turn_packet::Protocol::WGIpv4 => {
if self.config_info.allow_wire_guard {
self.device.write(net_packet.payload())?;
}
}
ip_turn_packet::Protocol::Ipv4Broadcast => {}
ip_turn_packet::Protocol::Unknown(_) => {}
}
@@ -245,14 +263,14 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
}
}
impl<Call: VntCallback> ServerPacketHandler<Call> {
impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
fn service(
&self,
context: &ChannelContext,
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::Result<()> {
) -> anyhow::Result<()> {
match service_packet::Protocol::from(net_packet.transport_protocol()) {
service_packet::Protocol::RegistrationResponse => {
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())
@@ -304,81 +322,86 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
if old.virtual_ip != Ipv4Addr::UNSPECIFIED {
log::info!("ip发生变化,old:{:?},response={:?}", old, response);
}
#[cfg(target_os = "android")]
let device_config = crate::handle::callback::DeviceConfig::new(
#[cfg(feature = "integrated_tun")]
#[cfg(target_os = "windows")]
self.config_info.tap,
#[cfg(feature = "integrated_tun")]
#[cfg(any(
target_os = "windows",
target_os = "linux",
target_os = "macos"
))]
self.config_info.device_name.clone(),
self.config_info.mtu,
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
self.external_route.to_route(),
);
#[cfg(not(feature = "integrated_tun"))]
self.callback.create_device(device_config);
#[cfg(feature = "integrated_tun")]
{
let device_config = crate::handle::callback::DeviceConfig::new(
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
self.external_route.to_route(),
);
let device_fd = self.callback.generate_tun(device_config);
if device_fd == 0 {
self.callback.error(ErrorInfo::new_msg(
ErrorType::Unknown,
"device_fd == 0".into(),
));
} else {
let device = Arc::new(tun::Device::new(device_fd as _)?);
if let Err(e) = self.device.start(device) {
self.tun_device_helper.stop();
#[cfg(any(
target_os = "windows",
target_os = "linux",
target_os = "macos"
))]
match crate::tun_tap_device::create_device(device_config) {
Ok(device) => {
use tun::device::IFace;
let tun_info = crate::handle::callback::DeviceInfo::new(
device.name().unwrap_or("unknown".into()),
device.version().unwrap_or("unknown".into()),
);
log::info!("tun信息{:?}", tun_info);
self.callback.create_tun(tun_info);
self.tun_device_helper
.start(device, self.config_info.allow_wire_guard)?;
}
Err(e) => {
log::error!("{:?}", e);
self.callback.error(e);
}
}
#[cfg(target_os = "android")]
{
let device_config = crate::handle::callback::DeviceConfig::new(
self.config_info.mtu,
virtual_ip,
virtual_netmask,
virtual_gateway,
virtual_network,
self.external_route.to_route(),
);
let device_fd = self.callback.generate_tun(device_config);
if device_fd == 0 {
self.callback.error(ErrorInfo::new_msg(
ErrorType::Unknown,
format!("{:?}", e),
"device_fd == 0".into(),
));
}
}
}
#[cfg(not(target_os = "android"))]
{
if let Err(e) = self.device.set_ip(virtual_ip, virtual_netmask) {
log::error!("LocalIpExists {:?}", e);
self.callback.error(ErrorInfo::new_msg(
ErrorType::LocalIpExists,
format!("set_ip {:?}", e),
));
return Ok(());
}
let mut guard = self.route_record.lock();
for (dest, mask) in guard.drain(..) {
if let Err(e) = self.device.delete_route(dest, mask) {
log::warn!("删除路由失败 ={:?}", e);
}
}
if let Err(e) =
self.device.add_route(virtual_network, virtual_netmask, 1)
{
log::warn!("添加默认路由失败 ={:?}", e);
} else {
guard.push((virtual_network, virtual_netmask));
}
if let Err(e) =
self.device
.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1)
{
log::warn!("添加广播路由失败 ={:?}", e);
} else {
guard.push((Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST));
}
if let Err(e) = self.device.add_route(
Ipv4Addr::from([224, 0, 0, 0]),
Ipv4Addr::from([240, 0, 0, 0]),
1,
) {
log::warn!("添加组播路由失败 ={:?}", e);
} else {
guard.push((
Ipv4Addr::from([224, 0, 0, 0]),
Ipv4Addr::from([240, 0, 0, 0]),
));
}
for (dest, mask) in self.external_route.to_route() {
if let Err(e) = self.device.add_route(dest, mask, 1) {
log::warn!("添加路由失败 ={:?}", e);
} else {
guard.push((dest, mask));
match tun::Device::new(device_fd as _) {
Ok(device) => {
if let Err(e) =
self.tun_device_helper.start(Arc::new(device))
{
self.callback.error(ErrorInfo::new_msg(
ErrorType::Unknown,
format!("{:?}", e),
));
}
}
Err(e) => {
self.callback.error(ErrorInfo::new_msg(
ErrorType::Unknown,
format!("{:?}", e),
));
}
}
}
}
}
@@ -419,14 +442,18 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
info.device_status as u8,
info.client_secret,
info.client_secret_hash,
info.wireguard,
)
})
.collect();
{
let mut dev = self.device_list.lock();
let mut dev = self.device_map.lock();
//这里可能会收到旧的消息,但是随着时间推移总会收到新的
dev.0 = epoch;
dev.1 = ip_list.clone();
dev.1.clear();
for info in ip_list.clone() {
dev.1.insert(info.virtual_ip, info);
}
}
self.callback.peer_client_list(
ip_list
@@ -439,7 +466,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
&self,
current_device: &CurrentDeviceInfo,
context: &ChannelContext,
) -> io::Result<()> {
) -> anyhow::Result<()> {
if current_device.status.online() {
log::info!("已连接的不需要注册,{:?}", self.config_info);
return Ok(());
@@ -468,7 +495,8 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
)?;
log::info!("发送注册请求,{:?}", self.config_info);
//注册请求只发送到默认通道
context.send_default(response.buffer(), current_device.connect_server)
context.send_default(&response, current_device.connect_server)?;
Ok(())
}
fn error(
&self,
@@ -489,7 +517,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
self.callback.error(err);
//掉线epoch要归零
{
let mut dev = self.device_list.lock();
let mut dev = self.device_map.lock();
dev.0 = 0;
drop(dev);
}
@@ -526,7 +554,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
current_device: &CurrentDeviceInfo,
net_packet: NetPacket<&mut [u8]>,
route_key: RouteKey,
) -> io::Result<()> {
) -> anyhow::Result<()> {
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
ControlPacket::PongPacket(pong_packet) => {
let current_time = crate::handle::now_time() as u16;
@@ -537,12 +565,12 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
let rt = (current_time - pong_packet.time()) as i64;
let route = Route::from(route_key, metric, rt);
context.route_table.add_route(net_packet.source(), route);
let epoch = self.device_list.lock().0;
let epoch = self.device_map.lock().0;
if pong_packet.epoch() != epoch {
//纪元不一致,可能有新客户端连接,向服务端拉取客户端列表
let mut poll_device = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
poll_device.set_source(current_device.virtual_ip);
poll_device.set_destination(GATEWAY_IP);
poll_device.set_destination(current_device.virtual_gateway);
poll_device.set_default_version();
poll_device.set_gateway_flag(true);
poll_device.first_set_ttl(MAX_TTL);
@@ -551,7 +579,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
.set_transport_protocol(service_packet::Protocol::PullDeviceList.into());
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
//发送到默认服务端即可
context.send_default(poll_device.buffer(), current_device.connect_server)?;
context.send_default(&poll_device, current_device.connect_server)?;
}
}
ControlPacket::AddrResponse(addr_packet) => {
+10 -2
View File
@@ -3,6 +3,7 @@ use crate::channel::RouteKey;
use crate::handle::recv_data::PacketHandler;
use crate::handle::CurrentDeviceInfo;
use crate::protocol::NetPacket;
use anyhow::Context;
/// 处理客户端中转包
#[derive(Clone)]
@@ -18,13 +19,18 @@ impl PacketHandler for TurnPacketHandler {
fn handle(
&self,
mut net_packet: NetPacket<&mut [u8]>,
_extend: NetPacket<&mut [u8]>,
route_key: RouteKey,
context: &ChannelContext,
_current_device: &CurrentDeviceInfo,
) -> std::io::Result<()> {
) -> anyhow::Result<()> {
// ttl减一
let ttl = net_packet.incr_ttl();
if ttl > 0 {
if net_packet.is_gateway() {
// 暂时不转发服务端包
return Ok(());
}
let destination = net_packet.destination();
if let Some(route) = context.route_table.route_one(&destination) {
if route.addr == route_key.addr {
@@ -33,7 +39,9 @@ impl PacketHandler for TurnPacketHandler {
return Ok(());
}
if route.metric <= ttl {
return context.send_by_key(net_packet.buffer(), route.route_key());
return context
.send_by_key(&net_packet, route.route_key())
.context("转发失败");
}
}
//其他没有路由的不转发
+5 -5
View File
@@ -1,4 +1,4 @@
use std::io;
use anyhow::anyhow;
use std::net::Ipv4Addr;
use protobuf::Message;
@@ -19,7 +19,7 @@ pub fn registration_request_packet(
is_fast: bool,
allow_ip_change: bool,
client_secret_hash: Option<&[u8]>,
) -> io::Result<NetPacket<Vec<u8>>> {
) -> anyhow::Result<NetPacket<Vec<u8>>> {
let mut request = RegistrationRequest::new();
request.token = token;
request.device_id = device_id;
@@ -36,9 +36,9 @@ pub fn registration_request_packet(
.client_secret_hash
.extend_from_slice(client_secret_hash);
}
let bytes = request.write_to_bytes().map_err(|e| {
io::Error::new(io::ErrorKind::Other, format!("RegistrationRequest {:?}", e))
})?;
let bytes = request
.write_to_bytes()
.map_err(|e| anyhow!("RegistrationRequest {:?}", e))?;
let buf = vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED];
let mut net_packet = NetPacket::new_encrypt(buf)?;
net_packet.set_destination(GATEWAY_IP);
-30
View File
@@ -1,30 +0,0 @@
use std::sync::mpsc::{sync_channel, Receiver, SendError, SyncSender};
pub fn channel_group<T>(size: usize, bound: usize) -> (GroupSyncSender<T>, Vec<Receiver<T>>) {
let mut senders = Vec::with_capacity(size);
let mut receivers = Vec::with_capacity(size);
for _ in 0..size {
let (s, r) = sync_channel(bound);
senders.push(s);
receivers.push(r);
}
(
GroupSyncSender {
count: 0,
base: senders,
},
receivers,
)
}
pub struct GroupSyncSender<T> {
count: usize,
base: Vec<SyncSender<T>>,
}
impl<T> GroupSyncSender<T> {
pub fn send(&mut self, t: T) -> Result<(), SendError<T>> {
self.count += 1;
self.base[self.count % self.base.len()].send(t)
}
}
+32 -176
View File
@@ -1,187 +1,43 @@
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(());
}
#[cfg(unix)]
mod unix;
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());
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::sync::Arc;
#[cfg(unix)]
pub(crate) use unix::*;
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)
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
pub(crate) use windows::*;
/// 仅仅是停止tun,不停止vnt
#[derive(Clone, Default)]
pub struct DeviceStop {
f: Arc<Mutex<Option<Box<dyn FnOnce() + Send>>>>,
stopped: Arc<AtomicCell<bool>>,
}
/// 实现一个原地发送,必须保证是如下结构
/// |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(());
impl DeviceStop {
pub fn set_stop_fn<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
self.f.lock().replace(Box::new(f));
}
if dest_ip.is_multicast() {
//当作广播处理
dest_ip = Ipv4Addr::BROADCAST;
net_packet.set_destination(Ipv4Addr::BROADCAST);
}
if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip {
// 广播 发送到直连目标
client_cipher.encrypt_ipv4(&mut net_packet)?;
broadcast(
server_cipher,
context,
&mut net_packet,
&current_device,
device_list,
)?;
return Ok(());
}
if !check_dest(
dest_ip,
current_device.virtual_netmask,
current_device.virtual_network,
) {
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
//路由的目标不能是自己
if r_dest_ip == src_ip {
return Ok(());
}
//需要修改目的地址
dest_ip = r_dest_ip;
net_packet.set_destination(r_dest_ip);
} else {
return Ok(());
pub fn stop(&self) {
if let Some(f) = self.f.lock().take() {
f()
}
}
#[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)?;
pub fn stopped(&self) {
self.stopped.store(true);
}
pub fn is_stopped(&self) -> bool {
self.stopped.load()
}
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(),
)
}
+240 -193
View File
@@ -1,27 +1,35 @@
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
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::channel::sender::{send_to_wg, send_to_wg_broadcast};
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::channel_group::{channel_group, GroupSyncSender};
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
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 {
#[cfg(feature = "ip_proxy")]
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::StopManager;
fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyhow::Result<()> {
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);
@@ -36,43 +44,6 @@ fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> io::R
Ok(())
}
/// 接收tun数据,并且转发到udp上
fn handle(
context: &ChannelContext,
data: &mut [u8],
len: usize,
device_writer: &Device,
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<()> {
//忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了
let ipv4_packet = match IpV4Packet::new(&mut data[12..len]) {
Ok(packet) => packet,
Err(_) => return Ok(()),
};
let src_ip = ipv4_packet.source_ip();
let dest_ip = ipv4_packet.destination_ip();
if src_ip == dest_ip {
return icmp(&device_writer, ipv4_packet);
}
return crate::handle::tun_tap::base_handle(
context,
data,
len,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
proxy_map,
client_cipher,
server_cipher,
device_list,
);
}
pub fn start(
stop_manager: StopManager,
context: ChannelContext,
@@ -82,162 +53,238 @@ pub fn start(
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
parallel: usize,
mut up_counter: SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_stop: DeviceStop,
allow_wire_guard: bool,
) -> 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);
thread::Builder::new()
.name("tunHandlerS".into())
.spawn(move || {
if let Err(e) = crate::handle::tun_tap::start_simple(
stop_manager,
&context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
device_stop,
allow_wire_guard,
) {
log::warn!("stop:{}", 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() {
let context = context.clone();
let device = device.clone();
let current_device = current_device.clone();
let ip_route = ip_route.clone();
#[cfg(feature = "ip_proxy")]
let ip_proxy_map = ip_proxy_map.clone();
let client_cipher = client_cipher.clone();
let server_cipher = server_cipher.clone();
let device_list = device_list.clone();
thread::Builder::new()
.name(format!("tunHandler-{}", index))
.spawn(move || {
while let Ok((mut buf, len)) = receiver.recv() {
#[cfg(not(target_os = "macos"))]
let start = 0;
#[cfg(target_os = "macos")]
let start = 4;
match handle(
&context,
&mut buf[start..],
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)
}
}
}
})?;
}
thread::Builder::new()
.name("tunHandlerM".into())
.spawn(move || {
if let Err(e) = 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(
stop_manager,
&context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
&mut up_counter,
device_list,
) {
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>)>>,
) -> io::Result<()> {
let mut buf = [0; 1024 * 16];
loop {
if stop_manager.is_stop() {
return Ok(());
fn broadcast(
server_cipher: &Cipher,
sender: &ChannelContext,
net_packet: &mut NetPacket<&mut [u8]>,
current_device: &CurrentDeviceInfo,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
) -> anyhow::Result<()> {
let list: Vec<Ipv4Addr> = device_map
.lock()
.1
.values()
.filter(|info| !info.wireguard && info.status.is_online())
.map(|info| info.virtual_ip)
.collect();
if list.is_empty() {
return Ok(());
}
const MAX_COUNT: usize = 8;
let mut p2p_ips = Vec::with_capacity(8);
let mut relay = false;
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, route.route_key()).is_ok() {
p2p_ips.push(peer_ip);
continue;
}
}
relay = true;
}
if !overflow && !relay {
//全部p2p,不需要服务器中转
return Ok(());
}
if current_device.status.offline() {
//离线的不再转发
return Ok(());
}
if p2p_ips.is_empty() {
//都没有p2p则直接由服务器转发
sender.send_default(&net_packet, current_device.connect_server)?;
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, current_device.connect_server)?;
Ok(())
}
/// 接收tun数据,并且转发到udp上
/// 实现一个原地发送,必须保证是如下结构
/// |12字节开头|ip报文|至少1024字节结尾|
///
pub(crate) fn handle(
context: &ChannelContext,
buf: &mut [u8],
data_len: usize, //数据总长度=12+ip包长度
extend: &mut [u8],
device_writer: &Device,
current_device: CurrentDeviceInfo,
ip_route: &ExternalRoute,
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
client_cipher: &Cipher,
server_cipher: &Cipher,
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
compressor: &Compressor,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
//忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了
let ipv4_packet = match IpV4Packet::new(&mut buf[12..data_len]) {
Ok(packet) => packet,
Err(_) => return Ok(()),
};
let src_ip = ipv4_packet.source_ip();
let dest_ip = ipv4_packet.destination_ip();
if src_ip == dest_ip {
return icmp(&device_writer, ipv4_packet);
}
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)?;
let mut out = NetPacket::unchecked(extend);
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, current_device.connect_server)?;
}
return Ok(());
}
if !dest_ip.is_multicast() && !dest_ip.is_broadcast() && current_device.broadcast_ip != dest_ip
{
if current_device.not_in_network(dest_ip) {
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)?;
}
}
if dest_ip.is_multicast() {
//当作广播处理
dest_ip = Ipv4Addr::BROADCAST;
net_packet.set_destination(Ipv4Addr::BROADCAST);
}
let is_broadcast = dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip;
if allow_wire_guard {
if is_broadcast {
// wg客户端和vnt客户端分开广播
let exists_wg = device_map
.lock()
.1
.values()
.any(|v| v.status.is_online() && v.wireguard);
if exists_wg {
send_to_wg_broadcast(context, &net_packet, server_cipher, &current_device)?;
}
} else {
// 如果是wg客户端则发到vnts转发
let guard = device_map.lock();
if let Some(peer_info) = guard.1.get(&dest_ip) {
if peer_info.status.is_offline() {
return Ok(());
}
if peer_info.wireguard {
drop(guard);
send_to_wg(context, &mut net_packet, server_cipher, &current_device)?;
return Ok(());
}
}
}
}
}
fn start_multi(
stop_manager: StopManager,
device: Arc<Device>,
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
up_counter: &mut SingleU64Adder,
) -> io::Result<()> {
loop {
if stop_manager.is_stop() {
return Ok(());
}
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(());
}
let mut net_packet = if compressor.compress(&net_packet, &mut out)? {
out.set_default_version();
out.set_protocol(protocol::Protocol::IpTurn);
out.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
out.first_set_ttl(6);
out.set_source(src_ip);
out.set_destination(dest_ip);
out
} else {
net_packet
};
if is_broadcast {
// 广播 发送到直连目标
client_cipher.encrypt_ipv4(&mut net_packet)?;
broadcast(
server_cipher,
context,
&mut net_packet,
&current_device,
device_map,
)?;
return Ok(());
}
client_cipher.encrypt_ipv4(&mut net_packet)?;
context.send_ipv4_by_id(
&net_packet,
&dest_ip,
current_device.connect_server,
current_device.status.online(),
)?;
Ok(())
}
+154
View File
@@ -0,0 +1,154 @@
use crate::channel::context::ChannelContext;
use crate::channel::BUFFER_SIZE;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::util::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::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
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,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_stop: DeviceStop,
allow_wire_guard: bool,
) -> anyhow::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 || {
if let Err(e) = waker.wake() {
log::warn!("{:?}", e);
}
})?
};
let worker_cell = Arc::new(AtomicCell::new(Some(worker)));
let _worker_cell = worker_cell.clone();
device_stop.set_stop_fn(move || {
if let Some(worker) = _worker_cell.take() {
worker.stop_self()
}
});
if let Err(e) = start_simple0(
poll,
context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
allow_wire_guard,
) {
log::error!("{:?}", e);
};
device_stop.stopped();
if let Some(worker) = worker_cell.take() {
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,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
let fd = device.as_tun_fd();
fd.set_nonblock()?;
SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?;
let mut events = Events::with_capacity(4);
#[cfg(not(target_os = "macos"))]
let start = 12;
#[cfg(target_os = "macos")]
let start = 12 - 4;
loop {
if let Err(e) = poll.poll(&mut events, None) {
crate::ignore_io_interrupted(e)?;
continue;
}
for event in events.iter() {
if event.token() == STOP {
return Ok(());
}
let mut retries = 0;
loop {
let len = match fd.read(&mut buf[start..]) {
Ok(len) => len + start,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
retries += 1;
if retries < 8 {
continue;
}
break;
}
Err(e)?
}
};
// buf是重复利用的,需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(
context,
&mut buf,
len,
&mut extend,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
&device_map,
&compressor,
allow_wire_guard,
) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
}
}
}
}
}
}
+114
View File
@@ -0,0 +1,114 @@
use crate::channel::context::ChannelContext;
use crate::channel::BUFFER_SIZE;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::util::StopManager;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::Ipv4Addr;
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,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_stop: DeviceStop,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let worker = {
let device = device.clone();
stop_manager.add_listener("tun_device".into(), move || {
if let Err(e) = device.shutdown() {
log::warn!("{:?}", e);
}
})?
};
let worker_cell = Arc::new(AtomicCell::new(Some(worker)));
{
let worker_cell = worker_cell.clone();
device_stop.set_stop_fn(move || {
if let Some(worker) = worker_cell.take() {
worker.stop_self()
}
});
}
if let Err(e) = start_simple0(
context,
device,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
allow_wire_guard,
) {
log::error!("{:?}", e);
}
device_stop.stopped();
if let Some(worker) = worker_cell.take() {
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,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
loop {
let len = device.read(&mut buf[12..])? + 12;
//单线程的
// buf是重复利用的,需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(
context,
&mut buf,
len,
&mut extend,
&device,
current_device.load(),
&ip_route,
#[cfg(feature = "ip_proxy")]
&ip_proxy_map,
&client_cipher,
&server_cipher,
&device_map,
&compressor,
allow_wire_guard,
) {
Ok(_) => {}
Err(e) => {
log::warn!("tun/tap {:?}", e)
}
}
}
}
+42 -91
View File
@@ -1,12 +1,12 @@
use anyhow::Context;
use std::collections::HashMap;
use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
use mio::net::UdpSocket;
use mio::{Events, Interest, Poll, Token, Waker};
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use packet::icmp::icmp;
use packet::icmp::icmp::HeaderOther;
@@ -18,7 +18,6 @@ use crate::handle::CurrentDeviceInfo;
use crate::ip_proxy::ProxyHandler;
use crate::protocol;
use crate::protocol::{NetPacket, MAX_TTL};
use crate::util::StopManager;
#[derive(Clone)]
pub struct IcmpProxy {
icmp_socket: Arc<std::net::UdpSocket>,
@@ -27,48 +26,50 @@ pub struct IcmpProxy {
}
impl IcmpProxy {
pub fn new(
pub async fn new(
context: ChannelContext,
stop_manager: StopManager,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
client_cipher: Cipher,
) -> io::Result<Self> {
) -> anyhow::Result<Self> {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let icmp_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::RAW,
Some(socket2::Protocol::ICMPV4),
)?;
)
.context("new Socket RAW ICMPV4 failed")?;
#[cfg(target_os = "android")]
let icmp_socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::DGRAM,
Some(socket2::Protocol::ICMPV4),
)?;
)
.context("new Socket DGRAM ICMPV4 failed")?;
let addr: SocketAddrV4 = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0);
icmp_socket.bind(&socket2::SockAddr::from(addr))?;
icmp_socket
.bind(&socket2::SockAddr::from(addr))
.context("bind Socket ICMPV4 failed")?;
icmp_socket.set_nonblocking(true)?;
let std_socket: std::net::UdpSocket = icmp_socket.into();
let mio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?);
let tokio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?)?;
let nat_map: Arc<Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("icmpProxy".into())
.spawn(move || {
if let Err(e) = icmp_proxy(
mio_icmp_socket,
nat_map,
context,
stop_manager,
current_device,
client_cipher,
) {
log::warn!("icmp_proxy:{:?}", e);
}
})
.expect("icmpProxy");
tokio::spawn(async {
if let Err(e) = icmp_proxy(
tokio_icmp_socket,
nat_map,
context,
current_device,
client_cipher,
)
.await
{
log::warn!("icmp_proxy:{:?}", e);
}
});
}
Ok(Self {
icmp_socket: Arc::new(std_socket),
@@ -77,78 +78,21 @@ 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,
&mut buf,
&nat_map,
&context,
&current_device,
&client_cipher,
),
NOTIFY => {
return Ok(());
}
_ => {}
}
}
}
}
fn readable_handle(
icmp_socket: &UdpSocket,
buf: &mut [u8],
nat_map: &Mutex<HashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
context: &ChannelContext,
current_device: &AtomicCell<CurrentDeviceInfo>,
client_cipher: &Cipher,
) {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
let start = 12;
#[cfg(target_os = "android")]
let start = 12 + 20;
loop {
let (len, addr) = match icmp_socket.recv_from(&mut buf[start..]) {
Ok(rs) => rs,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::warn!("icmp_socket {:?}", e);
return;
}
};
let (len, addr) = icmp_socket.recv_from(&mut buf[start..]).await?;
if let IpAddr::V4(peer_ip) = addr.ip() {
#[cfg(target_os = "android")]
{
@@ -165,7 +109,7 @@ fn readable_handle(
ipv4.set_source_ip(peer_ip);
}
recv_handle(
buf,
&mut buf,
start + len,
peer_ip,
&nat_map,
@@ -176,6 +120,7 @@ fn readable_handle(
}
}
}
fn recv_handle(
buf: &mut [u8],
data_len: usize,
@@ -210,7 +155,7 @@ fn recv_handle(
return;
}
if let Err(e) = context.send_ipv4_by_id(
net_packet.buffer(),
&net_packet,
&dest_ip,
current_device.connect_server,
current_device.status.online(),
@@ -219,11 +164,17 @@ fn recv_handle(
}
}
}
_ => {}
h => {
log::debug!("不支持的icmp代理 {:?},{:?}", peer_ip, h)
}
},
Err(_) => {}
Err(e) => {
log::warn!("icmp {:?}", e)
}
},
Err(_) => {}
Err(e) => {
log::warn!("icmp {:?}", e)
}
}
}
+40 -7
View File
@@ -1,6 +1,6 @@
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::{io, thread};
use crossbeam_utils::atomic::AtomicCell;
@@ -10,11 +10,13 @@ use packet::ip::ipv4::packet::IpV4Packet;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::handle::CurrentDeviceInfo;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
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;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub mod icmp_proxy;
pub mod tcp_proxy;
pub mod udp_proxy;
@@ -31,6 +33,7 @@ pub trait ProxyHandler {
#[derive(Clone)]
pub struct IpProxyMap {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
icmp_proxy: IcmpProxy,
tcp_proxy: TcpProxy,
udp_proxy: UdpProxy,
@@ -38,16 +41,44 @@ 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> {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
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 {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
icmp_proxy,
tcp_proxy,
udp_proxy,
@@ -64,6 +95,7 @@ impl ProxyHandler for IpProxyMap {
match ipv4.protocol() {
ipv4::protocol::Protocol::Tcp => self.tcp_proxy.recv_handle(ipv4, source, destination),
ipv4::protocol::Protocol::Udp => self.udp_proxy.recv_handle(ipv4, source, destination),
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
ipv4::protocol::Protocol::Icmp => {
self.icmp_proxy.recv_handle(ipv4, source, destination)
}
@@ -84,6 +116,7 @@ impl ProxyHandler for IpProxyMap {
match ipv4.protocol() {
ipv4::protocol::Protocol::Tcp => self.tcp_proxy.send_handle(ipv4),
ipv4::protocol::Protocol::Udp => self.udp_proxy.send_handle(ipv4),
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
ipv4::protocol::Protocol::Icmp => self.icmp_proxy.send_handle(ipv4),
_ => Ok(()),
}
+60 -368
View File
@@ -1,28 +1,16 @@
use std::io::{Read, Write};
use std::net::{Ipv4Addr, Shutdown, SocketAddrV4};
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use anyhow::Context;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::Arc;
use std::time::Duration;
use std::{collections::HashMap, io, net::SocketAddr, thread};
use std::{collections::HashMap, io, net::SocketAddr};
use bytes::{BufMut, BytesMut};
use mio::net::TcpStream;
use mio::{net::TcpListener, Events, Interest, Poll, Registry, Token, Waker};
use parking_lot::Mutex;
use tokio::net::{TcpListener, TcpSocket, TcpStream};
use packet::ip::ipv4::packet::IpV4Packet;
use packet::tcp::tcp::TcpPacket;
use crate::ip_proxy::ProxyHandler;
use crate::util::StopManager;
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
#[derive(Clone)]
pub struct TcpProxy {
@@ -31,21 +19,16 @@ pub struct TcpProxy {
}
impl TcpProxy {
pub fn new(stop_manager: StopManager) -> io::Result<Self> {
pub async fn new() -> anyhow::Result<Self> {
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0).parse().unwrap())?;
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0))
.await
.context("TcpProxy bind failed")?;
let port = tcp_listener.local_addr()?.port();
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("tcpProxy".into())
.spawn(move || {
if let Err(e) = tcp_proxy(tcp_listener, nat_map, stop_manager) {
log::warn!("tcp_proxy:{:?}", e);
}
})
.expect("tcpProxy");
tokio::spawn(tcp_proxy(tcp_listener, nat_map));
}
Ok(Self { port, nat_map })
}
@@ -93,365 +76,74 @@ impl ProxyHandler for TcpProxy {
}
}
fn tcp_proxy(
mut tcp_listener: TcpListener,
async fn tcp_proxy(
tcp_listener: TcpListener,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
stop_manager: StopManager,
) -> io::Result<()> {
let mut poll = Poll::new()?;
poll.registry()
.register(&mut tcp_listener, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let mut tcp_map: HashMap<usize, ProxyValue> = HashMap::with_capacity(16);
let mut mapping: HashMap<usize, usize> = HashMap::with_capacity(16);
let stop = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let _stop = stop.clone();
let _worker = stop_manager.add_listener("tcp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop tcp_proxy:{:?}", e);
}
})?;
loop {
poll.poll(&mut events, None)?;
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => {
accept_handle(
poll.registry(),
&tcp_listener,
&nat_map,
&mut tcp_map,
&mut mapping,
);
}
NOTIFY => {
return Ok(());
}
Token(index) => {
let (val, src_index) = if let Some(v) = tcp_map.get_mut(&index) {
(v, index)
} else {
if let Some(dest_index) = mapping.get(&index) {
if let Some(v) = tcp_map.get_mut(dest_index) {
(v, *dest_index)
} else {
continue;
}
} else {
continue;
}
};
let (stream1, stream2, buf1, buf2, state1, state2) = val.as_mut(index);
if event.is_readable() {
if let Err(_) = readable_handle(stream1, stream2, buf1, state2) {
*state1 |= READ_CLOSED;
}
}
if event.is_writable() {
let read = buf2.len() >= BUF_LEN;
if let Err(_) = writable_handle(stream1, buf2) {
*state1 |= WRITE_CLOSED;
} else if read {
if readable_handle(stream2, stream1, buf2, state1).is_err() {
*state2 |= READ_CLOSED;
}
}
}
if event.is_read_closed() || event.is_error() {
*state1 |= READ_CLOSED;
}
if event.is_write_closed() || event.is_error() {
*state1 |= WRITE_CLOSED;
}
if is_write_closed(*state1) {
let _ = stream1.shutdown(Shutdown::Write);
let _ = stream2.shutdown(Shutdown::Read);
}
if is_read_closed(*state1) {
let _ = stream1.shutdown(Shutdown::Read);
if buf1.is_empty() {
let _ = stream2.shutdown(Shutdown::Write);
}
}
if (is_both_closed(*state1) && buf1.is_empty())
|| (is_both_closed(*state2) && buf2.is_empty())
|| (is_write_closed(*state1) && is_write_closed(*state2)
|| (is_read_closed(*state1)
&& is_read_closed(*state2)
&& buf1.is_empty()
&& buf2.is_empty()))
{
close(src_index, &mut tcp_map, &mut mapping);
}
}
}
}
}
}
fn accept_handle(
registry: &Registry,
tcp_listener: &TcpListener,
nat_map: &Mutex<HashMap<SocketAddrV4, SocketAddrV4>>,
tcp_map: &mut HashMap<usize, ProxyValue>,
mapping: &mut HashMap<usize, usize>,
) {
loop {
match tcp_listener.accept() {
Ok((mut src_stream, addr)) => {
#[cfg(windows)]
let src_fd = src_stream.as_raw_socket() as usize;
#[cfg(unix)]
let src_fd = src_stream.as_raw_fd() as usize;
if src_fd == SERVER_VAL || src_fd == NOTIFY_VAL {
log::error!("fd错误:{:?}", src_fd);
continue;
}
let addr = match addr {
SocketAddr::V4(addr) => addr,
SocketAddr::V6(_) => {
// 忽略ipv6
continue;
}
};
let _ = src_stream.set_nodelay(false);
if let Some(dest_addr) = nat_map.lock().get(&addr).cloned() {
match tcp_connect(addr.port(), dest_addr.into()) {
Ok(mut dest_stream) => {
#[cfg(windows)]
let dest_fd = dest_stream.as_raw_socket() as usize;
#[cfg(unix)]
let dest_fd = dest_stream.as_raw_fd() as usize;
if dest_fd == SERVER_VAL || dest_fd == NOTIFY_VAL {
log::error!("fd错误:{:?}", dest_fd);
continue;
}
if let Err(e) = registry.register(
&mut src_stream,
Token(src_fd),
Interest::READABLE.add(Interest::WRITABLE),
) {
log::error!("register src_stream:{:?}", e);
continue;
}
if let Err(e) = registry.register(
&mut dest_stream,
Token(dest_fd),
Interest::READABLE.add(Interest::WRITABLE),
) {
log::error!("register dest_stream:{:?}", e);
continue;
}
tcp_map.insert(
src_fd,
ProxyValue::new(src_stream, dest_stream, src_fd, dest_fd),
);
mapping.insert(dest_fd, src_fd);
}
Err(e) => {
log::error!("connect:{:?} {}->{}", e, addr, dest_addr);
}
match tcp_listener.accept().await {
Ok((tcp_stream, sender_addr)) => match sender_addr {
SocketAddr::V4(sender_addr) => {
if let Some(dest_addr) = nat_map.lock().get(&sender_addr).cloned() {
tokio::spawn(async move {
let peer_tcp_stream =
match tcp_connect(sender_addr.port(), dest_addr.into()).await {
Ok(peer_tcp_stream) => peer_tcp_stream,
Err(e) => {
log::warn!(
"tcp代理异常:{:?},来源:{},目标:{}",
e,
sender_addr,
dest_addr
);
return;
}
};
proxy(sender_addr, dest_addr, tcp_stream, peer_tcp_stream).await
});
} else {
log::warn!("tcp代理异常: 来源:{},未找到目标", sender_addr);
}
}
}
SocketAddr::V6(_) => {}
},
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("accept:{:?}", e);
log::warn!("tcp代理监听:{:?}", e);
}
}
}
}
fn tcp_connect(src_port: u16, addr: SocketAddr) -> io::Result<TcpStream> {
let socket = socket2::Socket::new(
socket2::Domain::IPV4,
socket2::Type::STREAM,
Some(socket2::Protocol::TCP),
)?;
/// 优先使用来源端口建立tcp连接
async fn tcp_connect(src_port: u16, addr: SocketAddr) -> anyhow::Result<TcpStream> {
let socket = TcpSocket::new_v4()?;
if socket
.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
.is_err()
{
socket.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
}
if let Err(e) = socket.set_tcp_keepalive(
&socket2::TcpKeepalive::new()
.with_time(Duration::from_secs(120))
.with_interval(Duration::from_secs(10)),
) {
log::warn!("set_tcp_keepalive err {:?}", e);
socket.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
}
let _ = socket.set_nodelay(false);
socket.connect_timeout(&addr.into(), Duration::from_secs(3))?;
socket.set_nonblocking(true)?;
Ok(TcpStream::from_std(socket.into()))
let tcp_stream = tokio::time::timeout(Duration::from_secs(5), socket.connect(addr))
.await
.with_context(|| format!("TCP connection timeout {}", addr))?
.with_context(|| format!("TCP connection target failed {}", addr))?;
Ok(tcp_stream)
}
#[derive(Debug)]
struct ProxyValue {
src_stream: TcpStream,
dest_stream: TcpStream,
src_fd: usize,
dest_fd: usize,
src_buf: BytesMut,
dest_buf: BytesMut,
src_state: u8,
dest_state: u8,
}
const BUF_LEN: usize = 65536;
impl ProxyValue {
fn new(src_stream: TcpStream, dest_stream: TcpStream, src_fd: usize, dest_fd: usize) -> Self {
Self {
src_stream,
dest_stream,
src_fd,
dest_fd,
src_buf: BytesMut::with_capacity(BUF_LEN),
dest_buf: BytesMut::with_capacity(BUF_LEN),
src_state: NORMAL,
dest_state: NORMAL,
}
}
fn as_mut(
&mut self,
index: usize,
) -> (
&mut TcpStream,
&mut TcpStream,
&mut BytesMut,
&mut BytesMut,
&mut u8,
&mut u8,
) {
if index == self.src_fd {
(
&mut self.src_stream,
&mut self.dest_stream,
&mut self.src_buf,
&mut self.dest_buf,
&mut self.src_state,
&mut self.dest_state,
)
} else {
(
&mut self.dest_stream,
&mut self.src_stream,
&mut self.dest_buf,
&mut self.src_buf,
&mut self.dest_state,
&mut self.src_state,
)
}
}
}
fn readable_handle(
stream1: &mut TcpStream,
stream2: &mut TcpStream,
mid_buf: &mut BytesMut,
state2: &mut u8,
) -> io::Result<()> {
let mut buf = [0; BUF_LEN];
loop {
if mid_buf.len() >= BUF_LEN {
// 达到上限不再继续读取
return Ok(());
}
match stream1.read(&mut buf) {
Ok(len) => {
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
let mut buf = &buf[..len];
if mid_buf.is_empty() {
// 直接写入,避免在buf中过渡
while !buf.is_empty() {
match stream2.write(buf) {
Ok(end) => {
if end == 0 {
*state2 |= WRITE_CLOSED;
return Err(io::Error::from(io::ErrorKind::WriteZero));
}
buf = &buf[end..];
}
Err(e) => {
if e.kind() != io::ErrorKind::WouldBlock {
*state2 |= WRITE_CLOSED;
return Err(e);
}
break;
}
}
}
if buf.is_empty() {
continue;
}
}
mid_buf.reserve(buf.len());
mid_buf.put_slice(buf);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
Ok(())
}
fn writable_handle(stream: &mut TcpStream, mid_buf: &mut BytesMut) -> io::Result<()> {
while !mid_buf.is_empty() {
match stream.write(&mid_buf) {
Ok(len) => {
let _ = mid_buf.split_to(len);
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
}
}
Ok(())
}
fn close(
index: usize,
tcp_map: &mut HashMap<usize, ProxyValue>,
mapping: &mut HashMap<usize, usize>,
async fn proxy(
sender_addr: SocketAddrV4,
dest_addr: SocketAddrV4,
client: TcpStream,
server: TcpStream,
) {
if let Some(val) = tcp_map.remove(&index) {
let _ = val.src_stream.shutdown(Shutdown::Both);
let _ = val.dest_stream.shutdown(Shutdown::Both);
mapping.remove(&val.src_fd);
mapping.remove(&val.dest_fd);
let (mut client_read, mut client_write) = client.into_split();
let (mut server_read, mut server_write) = server.into_split();
tokio::spawn(async move {
if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await {
log::warn!("client tcp proxy {}->{},{:?}", sender_addr, dest_addr, e);
}
});
if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await {
log::warn!("server tcp proxy {}->{},{:?}", sender_addr, dest_addr, e);
}
}
const NORMAL: u8 = 0b00;
const READ_CLOSED: u8 = 0b01;
const WRITE_CLOSED: u8 = 0b10;
const BOTH_CLOSED: u8 = 0b11;
fn is_read_closed(state: u8) -> bool {
(state & READ_CLOSED == READ_CLOSED) || is_both_closed(state)
}
fn is_write_closed(state: u8) -> bool {
(state & WRITE_CLOSED == WRITE_CLOSED) || is_both_closed(state)
}
fn is_both_closed(state: u8) -> bool {
state & BOTH_CLOSED == BOTH_CLOSED
}
+97 -240
View File
@@ -1,30 +1,17 @@
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use std::net::{Ipv4Addr, SocketAddrV4};
#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::{collections::HashMap, io, net::SocketAddr, rc::Rc, thread};
use std::{collections::HashMap, io, net::SocketAddr};
use mio::{net::UdpSocket, Events, Interest, Poll, Token};
use mio::{Registry, Waker};
use parking_lot::Mutex;
use tokio::net::UdpSocket;
use packet::ip::ipv4::packet::IpV4Packet;
use packet::udp::udp::UdpPacket;
use crate::ip_proxy::ProxyHandler;
use crate::util::{Scheduler, StopManager};
const SERVER_VAL: usize = 0;
const SERVER: Token = Token(SERVER_VAL);
const NOTIFY_VAL: usize = 1;
const NOTIFY: Token = Token(NOTIFY_VAL);
// 开了ip代理后使用mstsc,mstsc会误以为在真实局域网,从而不维护udp心跳,导致断连,所以这里尽量长一点过期时间
const NAT_TIMEOUT: Duration = Duration::from_secs(20 * 60);
const NAT_FAST_TIMEOUT: Duration = Duration::from_secs(5 * 60);
const NAT_MAX: usize = 5_000;
#[derive(Clone)]
pub struct UdpProxy {
@@ -33,21 +20,20 @@ pub struct UdpProxy {
}
impl UdpProxy {
pub fn new(scheduler: Scheduler, stop_manager: StopManager) -> io::Result<Self> {
pub async fn new() -> anyhow::Result<Self> {
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
Arc::new(Mutex::new(HashMap::with_capacity(16)));
let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0).parse().unwrap())?;
let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0))
.await
.context("UdpProxy bind failed")?;
let port = udp.local_addr()?.port();
{
let nat_map = nat_map.clone();
thread::Builder::new()
.name("udpProxy".into())
.spawn(move || {
if let Err(e) = udp_proxy(udp, nat_map, scheduler, stop_manager) {
log::warn!("udp_proxy:{:?}", e);
}
})
.expect("udpProxy");
tokio::spawn(async {
if let Err(e) = udp_proxy(udp, nat_map).await {
log::warn!("udp_proxy:{:?}", e);
}
});
}
Ok(Self { port, nat_map })
}
@@ -95,230 +81,101 @@ impl ProxyHandler for UdpProxy {
}
}
fn udp_proxy(
mut udp: UdpSocket,
async fn udp_proxy(
udp: UdpSocket,
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
scheduler: Scheduler,
stop_manager: StopManager,
) -> io::Result<()> {
let mut poll = Poll::new()?;
let mut buf = [0u8; 65536];
poll.registry()
.register(&mut udp, SERVER, Interest::READABLE)?;
let mut events = Events::with_capacity(32);
let mut buf = [0; 65536];
let mut token_map: HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)> =
HashMap::with_capacity(64);
let mut udp_map: HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)> = HashMap::with_capacity(64);
let mut timeout = false;
let waker = Arc::new(Waker::new(poll.registry(), NOTIFY)?);
let stop = waker.clone();
let _worker = stop_manager.add_listener("udp_proxy".into(), move || {
if let Err(e) = stop.wake() {
log::warn!("stop udp_proxy:{:?}", e);
}
})?;
let inner_map: Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
Arc::new(Mutex::new(HashMap::with_capacity(64)));
let udp_socket = Arc::new(udp);
loop {
let mut check = false;
if token_map.is_empty() {
poll.poll(&mut events, None)?;
} else {
//所有事件 50分钟超时
if let Err(e) = poll.poll(&mut events, Some(Duration::from_secs(50 * 60))) {
if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock {
log::warn!(
"超时清理所有udp映射 {},token_map={},udp_map={}",
e,
token_map.len(),
udp_map.len()
);
token_map.clear();
udp_map.clear();
continue;
match udp_socket.recv_from(&mut buf).await {
Ok((len, sender_addr)) => match sender_addr {
SocketAddr::V4(sender_addr) => {
if let Err(e) =
udp_proxy0(&buf[..len], sender_addr, &inner_map, &nat_map, &udp_socket)
.await
{
log::warn!("udp proxy {} {:?}", sender_addr, e);
}
}
return Err(e);
SocketAddr::V6(_) => {}
},
Err(e) => {
log::warn!("udp代理异常:{:?}", e);
}
}
if stop_manager.is_stop() {
return Ok(());
}
for event in events.iter() {
match event.token() {
SERVER => server_handle(
poll.registry(),
&udp,
&nat_map,
&mut token_map,
&mut udp_map,
&mut buf,
),
NOTIFY => {
check = true;
}
token => {
if let Err(e) = readable_handle(&udp, &mut token_map, &token, &mut buf) {
log::error!("发送目标失败:{:?}", e);
if let Some((_, src_addr, _)) = token_map.remove(&token) {
udp_map.remove(&src_addr);
};
}
}
async fn udp_proxy0(
buf: &[u8],
sender_addr: SocketAddrV4,
inner_map: &Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
map: &Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
udp_socket: &Arc<UdpSocket>,
) -> io::Result<()> {
let option = inner_map.lock().get(&sender_addr).cloned();
if let Some((udp, time)) = option {
time.store(Instant::now());
udp.send(buf).await?;
} else {
let option = map.lock().get(&sender_addr).cloned();
if let Some(dest_addr) = option {
//先使用相同的端口,冲突了再随机端口
let peer_udp_socket =
match UdpSocket::bind(format!("0.0.0.0:{}", sender_addr.port())).await {
Ok(udp) => udp,
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
};
peer_udp_socket.connect(dest_addr).await?;
peer_udp_socket.send(buf).await?;
let peer_udp_socket = Arc::new(peer_udp_socket);
let inner_map = inner_map.clone();
let time = Arc::new(AtomicCell::new(Instant::now()));
inner_map
.lock()
.insert(sender_addr, (peer_udp_socket.clone(), time.clone()));
let udp_socket = udp_socket.clone();
let map = map.clone();
tokio::spawn(async move {
let mut buf = [0u8; 65536];
loop {
match tokio::time::timeout(
Duration::from_secs(600),
peer_udp_socket.recv(&mut buf),
)
.await
{
Ok(rs) => match rs {
Ok(len) => match udp_socket.send_to(&buf[..len], sender_addr).await {
Ok(_) => {}
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e);
break;
}
},
Err(e) => {
log::warn!("udp proxy {}->{} {:?}", sender_addr, dest_addr, e);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!("udp proxy timeout {}->{}", sender_addr, dest_addr);
break;
}
}
}
}
}
}
if check {
//超时校验
if token_map.len() > NAT_MAX / 2 {
check_handle(&mut token_map, &mut udp_map, NAT_FAST_TIMEOUT)
} else {
check_handle(&mut token_map, &mut udp_map, NAT_TIMEOUT)
}
timeout = false;
}
if !token_map.is_empty() && !timeout {
//注册超时监听
timeout = true;
let waker = waker.clone();
scheduler.timeout(NAT_FAST_TIMEOUT, move |_| {
let _ = waker.wake();
inner_map.lock().remove(&sender_addr);
map.lock().remove(&sender_addr);
});
}
}
}
fn check_handle(
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
udp_map: &mut HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)>,
timeout: Duration,
) {
let mut remove_list = Vec::new();
for (token, (_, addr, time)) in token_map.iter() {
if time.elapsed() > timeout {
if let Some((_, time)) = udp_map.get(addr) {
if time.elapsed() > timeout {
//映射超时,需要移除
remove_list.push(*token);
}
}
}
}
for token in remove_list {
if let Some((_, src_addr, _)) = token_map.remove(&token) {
udp_map.remove(&src_addr);
log::warn!(
"超时清理udp映射 {},token_map={},udp_map={}",
src_addr,
token_map.len(),
udp_map.len()
);
}
}
}
fn server_handle(
registry: &Registry,
udp: &UdpSocket,
nat_map: &Mutex<HashMap<SocketAddrV4, SocketAddrV4>>,
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
udp_map: &mut HashMap<SocketAddrV4, (Rc<UdpSocket>, Instant)>,
buf: &mut [u8],
) {
loop {
let (len, src_addr) = match udp.recv_from(buf) {
Ok((len, src_addr)) => match src_addr {
SocketAddr::V4(addr) => (len, addr),
SocketAddr::V6(_) => {
continue;
}
},
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
log::error!("接收数据失败:{:?}", e);
break;
}
};
if let Some((dest_udp, time)) = udp_map.get_mut(&src_addr) {
//发送失败就当丢包了
let _ = dest_udp.send(&buf[..len]);
*time = Instant::now();
} else if let Some(dest_addr) = nat_map.lock().get(&src_addr).cloned() {
if token_map.len() >= NAT_MAX {
log::error!(
"UDP NAT_MAX:src_addr={:?},dest_addr={:?}",
src_addr,
dest_addr
);
continue;
}
match udp_connect(src_addr.port(), dest_addr.into()) {
Ok((token_val, mut dest_udp)) => {
let token = Token(token_val);
if let Err(e) = registry.register(&mut dest_udp, token, Interest::READABLE) {
log::error!("register失败:{:?},addr={:?}", e, dest_addr);
continue;
}
let _ = dest_udp.send(&buf[..len]);
let dest_udp = Rc::new(dest_udp);
token_map.insert(token, (dest_udp.clone(), src_addr, Instant::now()));
udp_map.insert(src_addr, (dest_udp, Instant::now()));
}
Err(e) => {
log::error!("绑定目标地址失败:{:?}", e);
continue;
}
};
}
}
}
/// 得到一个 fd不为SERVER_VAL或者NOTYFY_VAL的socket
fn udp_connect(src_port: u16, addr: SocketAddr) -> io::Result<(usize, UdpSocket)> {
loop {
let udp = if let Ok(udp) =
UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
{
udp
} else {
UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?
};
#[cfg(windows)]
let fd = udp.as_raw_socket() as usize;
#[cfg(unix)]
let fd = udp.as_raw_fd() as usize;
if fd == SERVER_VAL || fd == NOTIFY_VAL {
continue;
}
// 只接收目标的数据
udp.connect(addr)?;
return Ok((fd, udp));
}
}
fn readable_handle(
udp: &UdpSocket,
token_map: &mut HashMap<Token, (Rc<UdpSocket>, SocketAddrV4, Instant)>,
token: &Token,
buf: &mut [u8],
) -> io::Result<()> {
if let Some((dest_udp, src_addr, time)) = token_map.get_mut(&token) {
loop {
let len = match dest_udp.recv(buf) {
Ok(rs) => rs,
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
break;
}
return Err(e);
}
};
if len == 0 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
let _ = udp.send_to(&buf[..len], (*src_addr).into());
}
*time = Instant::now();
}
Ok(())
}
+19 -4
View File
@@ -3,14 +3,29 @@ pub const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub mod channel;
pub mod cipher;
pub mod core;
pub mod external_route;
mod external_route;
pub mod handle;
#[cfg(feature = "ip_proxy")]
pub mod ip_proxy;
mod ip_proxy;
pub mod nat;
pub mod proto;
#[cfg(feature = "port_mapping")]
mod port_mapping;
mod proto;
pub mod protocol;
pub mod tun_tap_device;
mod tun_tap_device;
pub use tun_tap_device::*;
pub mod util;
pub use handle::callback::*;
pub mod compression;
pub use packet;
pub(crate) fn ignore_io_interrupted(e: std::io::Error) -> std::io::Result<()> {
if e.kind() == std::io::ErrorKind::Interrupted {
log::warn!("ignore_io_interrupted");
Ok(())
} else {
Err(e)
}
}
+165 -11
View File
@@ -1,15 +1,19 @@
use anyhow::{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;
use std::time::{Duration, Instant};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use rand::prelude::SliceRandom;
use rand::Rng;
use crate::channel::punch::{NatInfo, NatType};
use crate::proto::message::PunchNatType;
#[cfg(feature = "upnp")]
use crate::util::UPnP;
mod stun;
@@ -45,12 +49,62 @@ pub fn local_ipv6_() -> io::Result<Ipv6Addr> {
pub fn local_ipv6() -> Option<Ipv6Addr> {
match local_ipv6_() {
Ok(ipv6) => Some(ipv6),
Ok(ipv6) => {
if is_ipv6_global(&ipv6) {
return Some(ipv6);
}
}
Err(e) => {
log::warn!("获取ipv6失败:{:?}", e);
None
}
}
None
}
pub const fn is_ipv4_global(ipv4: &Ipv4Addr) -> bool {
!(ipv4.octets()[0] == 0 // "This network"
|| ipv4.is_private()
|| ipv4.octets()[0] == 100 && (ipv4.octets()[1] & 0b1100_0000 == 0b0100_0000)//ipv4.is_shared()
|| ipv4.is_loopback()
|| ipv4.is_link_local()
// addresses reserved for future protocols (`192.0.0.0/24`)
// .9 and .10 are documented as globally reachable so they're excluded
|| (
ipv4.octets()[0] == 192 && ipv4.octets()[1] == 0 && ipv4.octets()[2] == 0
&& ipv4.octets()[3] != 9 && ipv4.octets()[3] != 10
)
|| ipv4.is_documentation()
|| ipv4.octets()[0] == 198 && (ipv4.octets()[1] & 0xfe) == 18//ipv4.is_benchmarking()
|| ipv4.octets()[0] & 240 == 240 && !ipv4.is_broadcast()//ipv4.is_reserved()
|| ipv4.is_broadcast())
}
pub const fn is_ipv6_global(ipv6addr: &Ipv6Addr) -> bool {
!(ipv6addr.is_unspecified()
|| ipv6addr.is_loopback()
// IPv4-mapped Address (`::ffff:0:0/96`)
|| matches!(ipv6addr.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|| matches!(ipv6addr.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
// Discard-Only Address Block (`100::/64`)
|| matches!(ipv6addr.segments(), [0x100, 0, 0, 0, _, _, _, _])
// IETF Protocol Assignments (`2001::/23`)
|| (matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
// Port Control Protocol Anycast (`2001:1::1`)
u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|| u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
// AMT (`2001:3::/32`)
|| matches!(ipv6addr.segments(), [0x2001, 3, _, _, _, _, _, _])
// AS112-v6 (`2001:4:112::/48`)
|| matches!(ipv6addr.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
// ORCHIDv2 (`2001:20::/28`)
|| matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
))
|| (ipv6addr.segments()[0] == 0x2001) && (ipv6addr.segments()[1] == 0xdb8)//ipv6addr.is_documentation()
|| (ipv6addr.segments()[0] & 0xfe00) == 0xfc00//ipv6addr.is_unique_local()
|| (ipv6addr.segments()[0] & 0xffc0) == 0xfe80) //ipv6addr.is_unicast_link_local())
}
#[derive(Clone)]
@@ -60,6 +114,8 @@ pub struct NatTest {
time: Arc<AtomicCell<Instant>>,
udp_ports: Vec<u16>,
tcp_port: u16,
#[cfg(feature = "upnp")]
upnp: UPnP,
}
impl From<NatType> for PunchNatType {
@@ -83,14 +139,12 @@ impl Into<NatType> for PunchNatType {
impl NatTest {
pub fn new(
_channel_num: usize,
mut stun_server: Vec<String>,
stun_server: Vec<String>,
local_ipv4: Option<Ipv4Addr>,
ipv6: Option<Ipv6Addr>,
udp_ports: Vec<u16>,
tcp_port: u16,
) -> NatTest {
let server = stun_server[0].clone();
stun_server.resize(3, server);
let ports = vec![0; udp_ports.len()];
let nat_info = NatInfo::new(
Vec::new(),
@@ -103,14 +157,27 @@ impl NatTest {
NatType::Cone,
);
let info = Arc::new(Mutex::new(nat_info));
#[cfg(feature = "upnp")]
let upnp = UPnP::default();
#[cfg(feature = "upnp")]
for port in &udp_ports {
upnp.add_udp_port(*port);
}
#[cfg(feature = "upnp")]
upnp.add_tcp_port(tcp_port);
let instant = Instant::now();
NatTest {
stun_server,
info,
time: Arc::new(AtomicCell::new(
Instant::now().sub(Duration::from_secs(100)),
instant
.checked_sub(Duration::from_secs(100))
.unwrap_or(instant),
)),
udp_ports,
tcp_port,
#[cfg(feature = "upnp")]
upnp,
}
}
pub fn can_update(&self) -> bool {
@@ -182,7 +249,7 @@ impl NatTest {
}
false
}
pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) {
pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
let mut guard = self.info.lock();
guard.update_addr(index, ip, port)
}
@@ -190,8 +257,17 @@ impl NatTest {
&self,
local_ipv4: Option<Ipv4Addr>,
ipv6: Option<Ipv6Addr>,
) -> io::Result<NatInfo> {
let (nat_type, public_ips, port_range) = stun::stun_test_nat(self.stun_server.clone())?;
) -> anyhow::Result<NatInfo> {
let mut stun_server = self.stun_server.clone();
if stun_server.len() > 5 {
stun_server.shuffle(&mut rand::thread_rng());
stun_server.truncate(5);
log::info!("stun_server truncate {:?}", stun_server);
}
let (nat_type, public_ips, port_range) = stun::stun_test_nat(stun_server)?;
if public_ips.is_empty() {
Err(anyhow!("public_ips.is_empty"))?
}
let mut guard = self.info.lock();
guard.nat_type = nat_type;
guard.public_ips = public_ips;
@@ -201,4 +277,82 @@ impl NatTest {
Ok(guard.clone())
}
#[cfg(feature = "upnp")]
pub fn reset_upnp(&self) {
let local_ipv4 = self.info.lock().local_ipv4.clone();
if let Some(local_ipv4) = local_ipv4 {
self.upnp.reset(local_ipv4)
}
}
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 buf[0] == 0x01 && buf[1] == 0x01 {
if let Some(addr) = stun::recv_stun_response(buf) {
if let Err(e) = self.recv_data_(index, source_addr, addr) {
log::warn!("{:?}", e);
}
}
Ok(true)
} else {
Ok(false)
}
}
fn recv_data_(
&self,
index: usize,
source_addr: SocketAddr,
addr: SocketAddr,
) -> anyhow::Result<()> {
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() {
ip
} else {
return Ok(());
}
}
};
'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 {
if is_ipv4_global(addr.ip()) {
if self.update_addr(index, *addr.ip(), addr.port()) {
log::info!("回应地址{:?},来源stun {:?}", addr, source_addr)
}
}
}
}
Ok(())
}
}
+96 -69
View File
@@ -1,23 +1,20 @@
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 {
let stun_servers = stun_servers.clone();
let handle = std::thread::spawn(move || stun_test_nat0(stun_servers));
th.push(handle);
}
let mut nat_type = NatType::Cone;
let mut port_range = 0;
let mut hash_set = HashSet::new();
for x in th {
match x.join().unwrap() {
for _ in 0..2 {
let stun_servers = stun_servers.clone();
match stun_test_nat0(stun_servers) {
Ok((nat_type_t, ip_list_t, port_range_t)) => {
if nat_type_t == NatType::Symmetric {
nat_type = NatType::Symmetric;
@@ -36,26 +33,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,81 +55,82 @@ 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))
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()
}
if max_port < addr.port() {
max_port = addr.port()
}
}
}
if hash_set.is_empty() {
Ok((nat_type, vec![], 0))
} else {
Ok((
nat_type,
hash_set.into_iter().collect(),
max_port - min_port,
))
}
}
fn test_nat(
udp: &UdpSocket,
stun_server: &String,
) -> io::Result<(SocketAddr, NatType, Vec<Ipv4Addr>, u16)> {
fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketAddr>> {
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(_) => {}
let tid = rand::thread_rng().next_u64() as u128;
let mut addr = HashSet::new();
let (mapped_addr1, changed_addr1) = test_nat_(&udp, stun_server, true, true, tid)?;
if mapped_addr1.is_ipv4() {
addr.insert(mapped_addr1);
}
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;
}
if let Some(changed_addr1) = changed_addr1 {
if udp.connect(changed_addr1).is_ok() {
match test_nat_(&udp, stun_server, false, false, tid + 1) {
Ok((mapped_addr2, _)) => {
if mapped_addr2.is_ipv4() {
addr.insert(mapped_addr1);
}
IpAddr::V6(_) => {}
}
port_range = mapped_addr2.port().abs_diff(mapped_addr1.port());
}
Err(e) => {
log::warn!("stun {} error {:?} ", stun_server, e);
Err(e) => {
log::warn!("stun {} error {:?} ", stun_server, e);
}
}
}
}
log::warn!(
"stun {} mapped_addr {:?} nat_type {:?}",
log::info!(
"stun {} mapped_addr {:?} changed_addr {:?}",
stun_server,
mapped_addr1,
nat_type
addr,
changed_addr1,
);
Ok((
mapped_addr1,
nat_type,
hash_set.into_iter().collect(),
port_range,
))
Ok(addr)
}
fn test_nat_(
udp: &UdpSocket,
stun_server: &String,
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) {
Ok(rs) => rs,
Err(e) => {
log::warn!("stun error {:?}", e);
log::warn!("stun {} error {:?}", stun_server, e);
continue;
}
};
@@ -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,39 @@ 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> {
let msg = stun_format::Msg::from(buf);
if let Some(tid) = msg.tid() {
if tid & TAG != TAG {
return None;
}
}
for x in msg.attrs_iter() {
match x {
Attr::MappedAddress(addr) => {
return Some(stun_addr(addr));
}
Attr::XorMappedAddress(addr) => {
return Some(stun_addr(addr));
}
_ => {}
}
}
None
}
+100
View File
@@ -0,0 +1,100 @@
use std::net::SocketAddr;
use std::str::FromStr;
use std::thread;
use anyhow::Context;
use crate::util::StopManager;
mod tcp_mapping;
mod udp_mapping;
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String)>> {
let mut rs = Vec::with_capacity(vec.len());
for x in vec {
let string = x.trim().to_lowercase();
if let Some(udp_mapping) = string.strip_prefix("udp:") {
let mut split = udp_mapping.split("-");
let bind_addr = split.next().with_context(|| {
format!(
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
let bind_addr = SocketAddr::from_str(bind_addr)
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
let dest = split.next().with_context(|| {
format!(
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
rs.push((false, bind_addr, dest.to_string()));
continue;
}
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
let mut split = tcp_mapping.split("-");
let bind_addr = split.next().with_context(|| {
format!(
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
let bind_addr = SocketAddr::from_str(bind_addr)
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
let dest = split.next().with_context(|| {
format!(
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
x
)
})?;
rs.push((true, bind_addr, dest.to_string()));
continue;
}
Err(anyhow::anyhow!(
"port_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
x
))?;
}
Ok(rs)
}
pub fn start_port_mapping(
stop_manager: StopManager,
vec: Vec<(bool, SocketAddr, String)>,
) -> anyhow::Result<()> {
if vec.is_empty() {
return Ok(());
}
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_name("portMapping")
.build()?;
runtime.block_on(start_port_mapping0(vec))?;
let (sender, receiver) = tokio::sync::oneshot::channel::<()>();
let worker = stop_manager.add_listener("portMapping".into(), move || {
let _ = sender.send(());
})?;
thread::Builder::new()
.name("portMapping".into())
.spawn(move || {
runtime.block_on(async {
let _ = receiver.await;
});
runtime.shutdown_background();
drop(worker);
})?;
Ok(())
}
async fn start_port_mapping0(vec: Vec<(bool, SocketAddr, String)>) -> anyhow::Result<()> {
for (is_tcp, bind_addr, destination) in vec {
if is_tcp {
tcp_mapping::tcp_mapping(bind_addr, destination).await?;
} else {
udp_mapping::udp_mapping(bind_addr, destination).await?;
}
}
Ok(())
}
+53
View File
@@ -0,0 +1,53 @@
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(async move {
if let Err(e) = tcp_mapping_(bind_addr, tcp_listener, destination).await {
log::warn!("tcp_mapping {:?}", e);
}
});
Ok(())
}
async fn tcp_mapping_(
bind_addr: SocketAddr,
tcp_listener: TcpListener,
destination: String,
) -> anyhow::Result<()> {
loop {
let (tcp_stream, _) = tcp_listener.accept().await?;
let destination = destination.clone();
tokio::spawn(async move {
if let Err(e) = copy(tcp_stream, &destination).await {
log::warn!("tcp port mapping {}->{} {:?}", bind_addr, destination, e);
}
});
}
}
async fn copy(source_tcp: TcpStream, destination: &String) -> anyhow::Result<()> {
let dest_tcp = TcpStream::connect(destination)
.await
.with_context(|| format!("TCP connection target failed {:?}", destination))?;
let _ = source_tcp.set_nodelay(true);
let _ = dest_tcp.set_nodelay(true);
let destination = dest_tcp.peer_addr()?;
let (mut client_read, mut client_write) = source_tcp.into_split();
let (mut server_read, mut server_write) = dest_tcp.into_split();
tokio::spawn(async move {
if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await {
log::warn!("client tcp proxy ->{:},{:?}", destination, e);
}
});
if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await {
log::warn!("server tcp proxy ->{:?},{:?}", destination, e);
}
Ok(())
}
+107
View File
@@ -0,0 +1,107 @@
use anyhow::Context;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::net::UdpSocket;
pub async fn udp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> {
let udp = UdpSocket::bind(bind_addr)
.await
.with_context(|| format!("port proxy UDP binding {:?} failed", bind_addr))?;
let udp = Arc::new(udp);
let inner_map: Arc<Mutex<HashMap<SocketAddr, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
Arc::new(Mutex::new(HashMap::with_capacity(64)));
tokio::spawn(async move {
let mut buf = [0; 65536];
loop {
match udp.recv_from(&mut buf).await {
Ok((len, src_addr)) => {
if let Err(e) =
udp_mapping0(&buf[..len], src_addr, &inner_map, &udp, &destination).await
{
log::warn!("udp port mapping {}->{} {:?}", src_addr, destination, e);
}
}
Err(e) => {
log::warn!("port proxy UDP {:?}", e);
}
}
}
});
Ok(())
}
async fn udp_mapping0(
buf: &[u8],
src_addr: SocketAddr,
inner_map: &Arc<Mutex<HashMap<SocketAddr, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
udp_socket: &Arc<UdpSocket>,
destination: &String,
) -> anyhow::Result<()> {
let option = inner_map.lock().get(&src_addr).cloned();
if let Some((udp, time)) = option {
time.store(Instant::now());
udp.send(buf).await?;
} else {
let dest_udp = UdpSocket::bind("0.0.0.0:0").await?;
dest_udp.connect(destination).await?;
dest_udp.send(buf).await?;
let destination_addr = dest_udp.peer_addr()?;
let udp_socket = udp_socket.clone();
let inner_map = inner_map.clone();
let dest_udp = Arc::new(dest_udp);
let time = Arc::new(AtomicCell::new(Instant::now()));
inner_map
.lock()
.insert(src_addr, (dest_udp.clone(), time.clone()));
tokio::spawn(async move {
let mut buf = [0u8; 65536];
loop {
match tokio::time::timeout(Duration::from_secs(600), dest_udp.recv(&mut buf)).await
{
Ok(rs) => match rs {
Ok(len) => match udp_socket.send_to(&buf[..len], src_addr).await {
Ok(_) => {}
Err(e) => {
log::warn!(
"udp port mapping {}->{} {:?}",
src_addr,
destination_addr,
e
);
break;
}
},
Err(e) => {
log::warn!(
"udp port mapping {}->{} {:?}",
src_addr,
destination_addr,
e
);
break;
}
},
Err(_) => {
if time.load().elapsed() > Duration::from_secs(580) {
//超时关闭
log::warn!(
"udp port mapping timeout {}->{} ",
src_addr,
destination_addr
);
break;
}
}
}
}
inner_map.lock().remove(&src_addr);
});
}
Ok(())
}
+255
View File
@@ -4,6 +4,261 @@ pub const ENCRYPTION_RESERVED: usize = 16 + 32 + 12;
pub const AES_GCM_ENCRYPTION_RESERVED: usize = 32;
pub const RSA_ENCRYPTION_RESERVED: usize = 32;
pub const RANDOM_RESERVED: usize = 4;
pub const FINGER_RESERVED: usize = 12;
pub const TAG_RESERVED: usize = 16;
/*
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
pub trait SecretTail {
fn buffer(&self) -> &[u8];
fn exist_finger(&self) -> bool;
fn random_buf(&self) -> &[u8] {
let buf = self.buffer();
let mut end = buf.len();
if self.exist_finger() {
end -= FINGER_RESERVED;
}
&buf[end - RANDOM_RESERVED..end]
}
fn finger(&self) -> &[u8] {
if self.exist_finger() {
let buf = self.buffer();
let end = buf.len();
&buf[end - FINGER_RESERVED..end]
} else {
&[]
}
}
}
pub trait SecretTailMut: SecretTail {
fn buffer_mut(&mut self) -> &mut [u8];
fn set_random(&mut self, random: &[u8]) {
let f = self.exist_finger();
let buf = self.buffer_mut();
let mut end = buf.len();
if f {
end -= FINGER_RESERVED;
}
buf[end - RANDOM_RESERVED..end].copy_from_slice(random);
}
fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
if self.exist_finger() {
if finger.len() != FINGER_RESERVED {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"finger.len != 12",
));
}
let buf = self.buffer_mut();
let end = buf.len();
buf[end - FINGER_RESERVED..end].copy_from_slice(finger);
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"not exist finger",
))
}
}
}
/* aead加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| tag(32) |
| tag(32) |
| tag(32) |
| tag(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
finger用于快速校验数据是否被修改使tokenfinger
()
*/
pub struct AEADSecretBody<B> {
buffer: B,
exist_finger: bool,
}
impl<B: AsRef<[u8]>> AEADSecretBody<B> {
pub fn new(buffer: B, exist_finger: bool) -> io::Result<AEADSecretBody<B>> {
let len = buffer.as_ref().len();
let min_len = if exist_finger {
TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED
} else {
TAG_RESERVED + RANDOM_RESERVED
};
// 不能大于udp最大载荷长度
if len < min_len || len > 65535 - 20 - 8 - 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("AEADSecretBody length overflow {}", len),
));
}
Ok(AEADSecretBody {
buffer,
exist_finger,
})
}
pub fn data(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len() - TAG_RESERVED - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&self.buffer.as_ref()[..end]
}
pub fn tag(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&self.buffer.as_ref()[end - TAG_RESERVED..end]
}
}
impl<B: AsRef<[u8]>> SecretTail for AEADSecretBody<B> {
#[inline]
fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
#[inline]
fn exist_finger(&self) -> bool {
self.exist_finger
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretTailMut for AEADSecretBody<B> {
#[inline]
fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer.as_mut()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> AEADSecretBody<B> {
/// 数据部分
pub fn data_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED - TAG_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&mut self.buffer.as_mut()[..end]
}
/// 数据和tag部分
pub fn data_tag_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&mut self.buffer.as_mut()[..end]
}
pub fn set_tag(&mut self, tag: &[u8]) -> io::Result<()> {
if tag.len() != 16 {
return Err(io::Error::new(io::ErrorKind::InvalidData, "tag.len != 16"));
}
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
self.buffer.as_mut()[end - TAG_RESERVED..end].copy_from_slice(tag);
Ok(())
}
}
/* 带随机数的加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| finger(32) |
| finger(32) |
| finger(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
finger用于快速校验数据是否被修改使tokenfinger
()
*/
pub struct IVSecretBody<B> {
buffer: B,
exist_finger: bool,
}
impl<B: AsRef<[u8]>> IVSecretBody<B> {
pub fn new(buffer: B, exist_finger: bool) -> io::Result<IVSecretBody<B>> {
let len = buffer.as_ref().len();
let min_len = if exist_finger {
FINGER_RESERVED + RANDOM_RESERVED
} else {
RANDOM_RESERVED
};
// 不能大于udp最大载荷长度
if len < min_len || len > 65535 - 20 - 8 - 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("IVSecretBody length overflow {}", len),
));
}
Ok(IVSecretBody {
buffer,
exist_finger,
})
}
pub fn data(&self) -> &[u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&self.buffer.as_ref()[..end]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> IVSecretBody<B> {
pub fn data_mut(&mut self) -> &mut [u8] {
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
if self.exist_finger {
end -= FINGER_RESERVED;
}
&mut self.buffer.as_mut()[..end]
}
}
impl<B: AsRef<[u8]>> SecretTail for IVSecretBody<B> {
#[inline]
fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
#[inline]
fn exist_finger(&self) -> bool {
self.exist_finger
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretTailMut for IVSecretBody<B> {
#[inline]
fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer.as_mut()
}
}
/* aes_gcm加密数据体
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+141
View File
@@ -0,0 +1,141 @@
/* 扩展协议
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (n) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| (n) | type(8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type决定
*/
use anyhow::anyhow;
use std::io;
use crate::protocol::NetPacket;
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum ExtensionTailType {
Compression,
Unknown(u8),
}
impl From<u8> for ExtensionTailType {
fn from(value: u8) -> Self {
if value == 0 {
ExtensionTailType::Compression
} else {
ExtensionTailType::Unknown(value)
}
}
}
pub enum ExtensionTailPacket<B> {
Compression(CompressionExtensionTail<B>),
Unknown,
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
/// 分离尾部数据
pub fn split_tail_packet(&mut self) -> anyhow::Result<ExtensionTailPacket<&[u8]>> {
if self.is_extension() {
let payload = self.payload();
if let Some(v) = payload.last() {
return match ExtensionTailType::from(*v) {
ExtensionTailType::Compression => {
let data_len = self.data_len - 4;
self.set_data_len(data_len)?;
self.set_extension_flag(false);
Ok(ExtensionTailPacket::Compression(
CompressionExtensionTail::new(
&self.raw_buffer()[data_len..data_len + 4],
),
))
}
ExtensionTailType::Unknown(e) => Err(anyhow!("unknown extension {}", e)),
};
}
}
Err(anyhow!("not extension"))
}
/// 追加压缩扩展
pub fn append_compression_extension_tail(
&mut self,
) -> io::Result<CompressionExtensionTail<&mut [u8]>> {
let len = self.data_len;
//增加数据长度
self.set_data_len(self.data_len + 4)?;
self.set_extension_flag(true);
let mut tail = CompressionExtensionTail::new(&mut self.buffer_mut()[len..]);
tail.init();
return Ok(tail);
}
}
/* 扩展协议
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| algorithm(8) | | type(8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type决定
*/
/// 压缩扩展
pub struct CompressionExtensionTail<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> CompressionExtensionTail<B> {
pub fn new(buffer: B) -> CompressionExtensionTail<B> {
assert_eq!(buffer.as_ref().len(), 4);
CompressionExtensionTail { buffer }
}
}
impl<B: AsRef<[u8]>> CompressionExtensionTail<B> {
pub fn algorithm(&self) -> CompressionAlgorithm {
self.buffer.as_ref()[0].into()
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> CompressionExtensionTail<B> {
pub fn init(&mut self) {
self.buffer.as_mut().fill(0);
}
pub fn set_algorithm(&mut self, algorithm: CompressionAlgorithm) {
self.buffer.as_mut()[0] = algorithm.into()
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum CompressionAlgorithm {
#[cfg(feature = "lz4_compress")]
Lz4,
#[cfg(feature = "zstd_compress")]
Zstd,
Unknown(u8),
}
impl From<u8> for CompressionAlgorithm {
fn from(value: u8) -> Self {
match value {
#[cfg(feature = "lz4_compress")]
1 => CompressionAlgorithm::Lz4,
#[cfg(feature = "zstd_compress")]
2 => CompressionAlgorithm::Zstd,
v => CompressionAlgorithm::Unknown(v),
}
}
}
impl From<CompressionAlgorithm> for u8 {
fn from(value: CompressionAlgorithm) -> Self {
match value {
#[cfg(feature = "lz4_compress")]
CompressionAlgorithm::Lz4 => 1,
#[cfg(feature = "zstd_compress")]
CompressionAlgorithm::Zstd => 2,
CompressionAlgorithm::Unknown(val) => val,
}
}
}
+8 -3
View File
@@ -1,9 +1,12 @@
#![allow(dead_code)]
use std::io;
use std::net::Ipv4Addr;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Protocol {
Ipv4,
WGIpv4,
Ipv4Broadcast,
Unknown(u8),
}
@@ -12,16 +15,18 @@ impl From<u8> for Protocol {
fn from(value: u8) -> Self {
match value {
4 => Protocol::Ipv4,
5 => Protocol::WGIpv4,
201 => Protocol::Ipv4Broadcast,
val => Protocol::Unknown(val),
}
}
}
impl Into<u8> for Protocol {
fn into(self) -> u8 {
match self {
impl From<Protocol> for u8 {
fn from(val: Protocol) -> Self {
match val {
Protocol::Ipv4 => 4,
Protocol::WGIpv4 => 5,
Protocol::Ipv4Broadcast => 201,
Protocol::Unknown(val) => val,
}
+29 -7
View File
@@ -6,7 +6,7 @@ use std::{fmt, io};
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|e |s |u |u| (4) | (8) | (8) | ttl(4) | (4) |
|e |s |x |u| (4) | (8) | (8) | ttl(4) | (4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -14,13 +14,14 @@ use std::{fmt, io};
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
e为是否加密标志s为服务端通信包标志u未使用
e为是否加密标志s为服务端通信包标志x扩展标志u未使用
*/
pub const HEAD_LEN: usize = 12;
pub mod body;
pub mod control_packet;
pub mod error_packet;
pub mod extension;
pub mod ip_turn_packet;
pub mod other_turn_packet;
pub mod service_packet;
@@ -101,6 +102,10 @@ pub struct NetPacket<B> {
}
impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn unchecked(buffer: B) -> Self {
let data_len = buffer.as_ref().len();
Self { data_len, buffer }
}
pub fn new(buffer: B) -> io::Result<NetPacket<B>> {
let data_len = buffer.as_ref().len();
Self::new0(data_len, buffer)
@@ -123,15 +128,15 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
"length overflow",
));
}
// 不能大于udp最大载荷长度
if data_len < 12 || data_len > 65535 - 20 - 8 {
if data_len < 12 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"length overflow",
"data_len too short",
));
}
Ok(NetPacket { data_len, buffer })
}
#[inline]
pub fn buffer(&self) -> &[u8] {
&self.buffer.as_ref()[..self.data_len]
}
@@ -158,6 +163,10 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn is_gateway(&self) -> bool {
self.buffer.as_ref()[0] & 0x40 == 0x40
}
/// 扩展协议
pub fn is_extension(&self) -> bool {
self.buffer.as_ref()[0] & 0x20 == 0x20
}
pub fn version(&self) -> Version {
Version::from(self.buffer.as_ref()[0] & 0x0F)
}
@@ -190,6 +199,9 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
pub fn head_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..12]
}
pub fn buffer_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..self.data_len]
}
@@ -202,12 +214,18 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
}
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
if is_gateway {
// 后面的版本再改为0x40,改了之后不兼容1.2.5之前的版本
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x40
} else {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
};
}
pub fn set_extension_flag(&mut self, is_extension: bool) {
if is_extension {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x20
} else {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xDF
};
}
pub fn set_default_version(&mut self) {
let v: u8 = Version::V2.into();
self.buffer.as_mut()[0] = (self.buffer.as_ref()[0] & 0xF0) | (0x0F & v);
@@ -264,6 +282,10 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
self.data_len = data_len;
Ok(())
}
pub fn set_payload_len(&mut self, payload_len: usize) -> io::Result<()> {
let data_len = HEAD_LEN + payload_len;
self.set_data_len(data_len)
}
pub fn set_data_len_max(&mut self) {
self.data_len = self.buffer.as_ref().len();
}
+50 -16
View File
@@ -1,16 +1,57 @@
use crate::{DeviceConfig, ErrorInfo, ErrorType};
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun::device::IFace;
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"))]
pub fn create_device(config: DeviceConfig) -> Result<Arc<Device>, ErrorInfo> {
let device = match create_device0(&config) {
Ok(device) => device,
Err(e) => {
return Err(ErrorInfo::new_msg(
ErrorType::Unknown,
format!("create device {:?}", e),
));
}
};
if let Err(e) = device.set_ip(config.virtual_ip, config.virtual_netmask) {
log::error!("LocalIpExists {:?}", e);
return Err(ErrorInfo::new_msg(
ErrorType::LocalIpExists,
format!("set_ip {:?}", e),
));
}
if let Err(e) = device.add_route(config.virtual_network, config.virtual_netmask, 1) {
log::warn!("添加默认路由失败 ={:?}", e);
}
if let Err(e) = device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1) {
log::warn!("添加广播路由失败 ={:?}", e);
}
if let Err(e) = device.add_route(
Ipv4Addr::from([224, 0, 0, 0]),
Ipv4Addr::from([240, 0, 0, 0]),
1,
) {
log::warn!("添加组播路由失败 ={:?}", e);
}
for (dest, mask) in config.external_route {
if let Err(e) = device.add_route(dest, mask, 1) {
log::warn!("添加路由失败 ={:?}", e);
}
}
Ok(device)
}
fn create_device0(config: &DeviceConfig) -> io::Result<Arc<Device>> {
#[cfg(target_os = "windows")]
let default_name: &str = if config.tap {
DEFAULT_TAP_NAME
} else {
@@ -21,11 +62,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())?);
@@ -37,14 +78,7 @@ pub fn create_device(config: &crate::core::Config) -> io::Result<Arc<Device>> {
.unwrap_or(default_name.to_string()),
config.tap,
)?);
let mtu = config.mtu.unwrap_or_else(|| {
if config.password.is_none() {
1450
} else {
1410
}
});
device.set_mtu(mtu)?;
device.set_mtu(config.mtu)?;
Ok(device)
}
+5
View File
@@ -1,6 +1,11 @@
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
#[cfg(feature = "integrated_tun")]
pub use create_device::create_device;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
#[cfg(feature = "integrated_tun")]
mod create_device;
#[cfg(feature = "integrated_tun")]
pub mod tun_create_helper;
pub mod vnt_device;
+89 -79
View File
@@ -1,73 +1,65 @@
use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::sync::Arc;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::Mutex;
use tun::device::IFace;
use tun::Device;
use crate::channel::context::ChannelContext;
use crate::cipher::Cipher;
use crate::compression::Compressor;
use crate::external_route::ExternalRoute;
use crate::handle::tun_tap::DeviceStop;
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
#[cfg(feature = "ip_proxy")]
use crate::ip_proxy::IpProxyMap;
use crate::util::{SingleU64Adder, StopManager};
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
use crate::tun_tap_device::vnt_device::DeviceWrite;
use crate::util::StopManager;
#[repr(transparent)]
#[derive(Clone)]
pub struct DeviceAdapter {
tun: Arc<Device>,
}
impl DeviceAdapter {
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub fn new(tun: Arc<Device>) -> Self {
Self { tun }
}
#[cfg(target_os = "android")]
pub fn new(tun_device_helper: TunDeviceHelper) -> Self {
Self {
tun: Arc::new(Mutex::new(None)),
tun_device_helper,
}
}
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
impl std::ops::Deref for DeviceAdapter {
type Target = Arc<Device>;
fn deref(&self) -> &Self::Target {
&self.tun
}
}
#[cfg(target_os = "android")]
#[derive(Clone)]
#[derive(Clone, Default)]
pub struct DeviceAdapter {
tun: Arc<Mutex<Option<Arc<Device>>>>,
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)
pub fn insert(&self, device: Arc<Device>) {
let r = self.tun.lock().replace(device);
assert!(r.is_none());
}
/// 要保证先remove 再insert
pub fn remove(&self) {
drop(self.tun.lock().take());
}
}
impl DeviceWrite for DeviceAdapter {
#[inline]
fn write(&self, buf: &[u8]) -> io::Result<usize> {
if let Some(tun) = self.tun.lock().as_ref() {
tun.write(buf)
} else {
Err(io::Error::new(io::ErrorKind::Other, "not tun device"))
Err(io::Error::new(io::ErrorKind::NotFound, "not tun device"))
}
}
pub fn start(&self, device: Arc<Device>) -> io::Result<()> {
self.tun_device_helper.start(device.clone())?;
self.tun.lock().replace(device);
Ok(())
fn into_device_adapter(self) -> DeviceAdapter {
self
}
}
#[derive(Clone)]
pub struct TunDeviceHelper {
inner: Arc<AtomicCell<Option<TunDeviceHelperInner>>>,
inner: Arc<Mutex<TunDeviceHelperInner>>,
device_adapter: DeviceAdapter,
device_stop: Arc<Mutex<Option<DeviceStop>>>,
}
#[derive(Clone)]
struct TunDeviceHelperInner {
stop_manager: StopManager,
context: ChannelContext,
@@ -77,9 +69,8 @@ struct TunDeviceHelperInner {
ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
parallel: usize,
up_counter: SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
}
impl TunDeviceHelper {
@@ -91,44 +82,63 @@ impl TunDeviceHelper {
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
client_cipher: Cipher,
server_cipher: Cipher,
parallel: usize,
up_counter: SingleU64Adder,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
compressor: Compressor,
device_adapter: DeviceAdapter,
) -> Self {
let inner = TunDeviceHelperInner {
stop_manager,
context,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
ip_proxy_map,
client_cipher,
server_cipher,
device_map,
compressor,
};
Self {
inner: Arc::new(AtomicCell::new(Some(TunDeviceHelperInner {
stop_manager,
context,
current_device,
ip_route,
ip_proxy_map,
client_cipher,
server_cipher,
parallel,
up_counter,
device_list,
}))),
inner: Arc::new(Mutex::new(inner)),
device_adapter,
device_stop: Default::default(),
}
}
pub fn start(&self, device: Arc<Device>) -> io::Result<()> {
if let Some(inner) = self.inner.take() {
crate::handle::tun_tap::tun_handler::start(
inner.stop_manager,
inner.context,
device,
inner.current_device,
inner.ip_route,
#[cfg(feature = "ip_proxy")]
inner.ip_proxy_map,
inner.client_cipher,
inner.server_cipher,
inner.parallel,
inner.up_counter,
inner.device_list,
)?;
Ok(())
} else {
Err(io::Error::new(io::ErrorKind::Other, "Repeated start"))
pub fn stop(&self) {
//先停止旧的,再启动新的,改变旧网卡的IP太麻烦
if let Some(device_stop) = self.device_stop.lock().take() {
self.device_adapter.remove();
loop {
device_stop.stop();
std::thread::sleep(std::time::Duration::from_millis(300));
//确保停止了
if device_stop.is_stopped() {
break;
}
}
}
}
/// 要保证先stop 再start
pub fn start(&self, device: Arc<Device>, allow_wire_guard: bool) -> io::Result<()> {
self.device_adapter.insert(device.clone());
let device_stop = DeviceStop::default();
let s = self.device_stop.lock().replace(device_stop.clone());
assert!(s.is_none());
let inner = self.inner.lock().clone();
crate::handle::tun_tap::tun_handler::start(
inner.stop_manager,
inner.context,
device,
inner.current_device,
inner.ip_route,
#[cfg(feature = "ip_proxy")]
inner.ip_proxy_map,
inner.client_cipher,
inner.server_cipher,
inner.device_map,
inner.compressor,
device_stop,
allow_wire_guard,
)
}
}
+7
View File
@@ -0,0 +1,7 @@
use std::io;
pub trait DeviceWrite: Clone + Send + Sync + 'static {
fn write(&self, buf: &[u8]) -> io::Result<usize>;
#[cfg(feature = "integrated_tun")]
fn into_device_adapter(self) -> crate::tun_tap_device::tun_create_helper::DeviceAdapter;
}
+9 -114
View File
@@ -1,138 +1,33 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
/// 不安全的并发计数器,谨慎使用
use crossbeam_utils::atomic::AtomicCell;
#[derive(Clone, Default)]
pub struct U64Adder {
global_index: Arc<AtomicUsize>,
inner: Arc<U64AdderInner>,
index: usize,
}
pub struct SingleU64Adder {
inner: Arc<SingleU64AdderInner>,
}
impl SingleU64Adder {
pub fn new() -> Self {
Self {
inner: Arc::new(SingleU64AdderInner::new()),
}
}
pub fn add(&mut self, num: u64) {
self.inner.add(num);
}
pub fn get(&self) -> u64 {
self.inner.get()
}
pub fn watch(&self) -> WatchSingleU64Adder {
WatchSingleU64Adder {
inner: self.inner.clone(),
}
}
}
struct SingleU64AdderInner {
ptr: *mut u64,
}
impl SingleU64AdderInner {
fn new() -> Self {
Self {
ptr: Box::into_raw(Box::new(0)),
}
}
#[inline(always)]
fn add(&self, num: u64) {
unsafe { *self.ptr += num }
}
fn get(&self) -> u64 {
unsafe { *self.ptr }
}
}
impl Drop for SingleU64AdderInner {
fn drop(&mut self) {
unsafe {
let _ = Box::from_raw(self.ptr);
}
}
}
unsafe impl Send for SingleU64AdderInner {}
unsafe impl Sync for SingleU64AdderInner {}
struct U64AdderInner {
base: Vec<SingleU64AdderInner>,
}
impl U64AdderInner {
pub fn get(&self) -> u64 {
let mut count = 0;
for counter in self.base.iter() {
count += counter.get()
}
count
}
count: Arc<AtomicCell<u64>>,
}
impl U64Adder {
/// 计数槽容量
pub fn with_capacity(capacity: usize) -> Self {
let mut base = Vec::with_capacity(capacity);
for _ in 0..capacity {
base.push(SingleU64AdderInner::new())
}
let inner = Arc::new(U64AdderInner { base });
U64Adder {
global_index: Arc::new(AtomicUsize::new(1)),
inner,
index: 0,
}
}
pub fn add(&mut self, num: u64) {
self.inner.base[self.index].add(num);
pub fn add(&self, num: u64) {
self.count.fetch_add(num);
}
pub fn get(&self) -> u64 {
self.inner.get()
self.count.load()
}
pub fn watch(&self) -> WatchU64Adder {
WatchU64Adder {
inner: self.inner.clone(),
}
}
}
impl Clone for U64Adder {
fn clone(&self) -> Self {
let index = self.global_index.fetch_add(1, Ordering::AcqRel);
if index > self.inner.base.len() {
panic!()
}
Self {
global_index: self.global_index.clone(),
inner: self.inner.clone(),
index,
count: self.count.clone(),
}
}
}
#[derive(Clone)]
pub struct WatchU64Adder {
inner: Arc<U64AdderInner>,
count: Arc<AtomicCell<u64>>,
}
impl WatchU64Adder {
pub fn get(&self) -> u64 {
self.inner.get()
}
}
#[derive(Clone)]
pub struct WatchSingleU64Adder {
inner: Arc<SingleU64AdderInner>,
}
impl WatchSingleU64Adder {
pub fn get(&self) -> u64 {
self.inner.get()
self.count.load()
}
}
+27 -13
View File
@@ -41,9 +41,10 @@ pub fn address_choose(addrs: Vec<SocketAddr>) -> anyhow::Result<SocketAddr> {
/// 后续实现选择延迟最低的可用地址,需要服务端配合
/// 现在是选择第一个地址,优先ipv6
fn address_choose0(addrs: Vec<SocketAddr>) -> anyhow::Result<SocketAddr> {
let v4: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv4()).map(|v| *v).collect();
let v6: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv6()).map(|v| *v).collect();
let v4: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv4()).copied().collect();
let v6: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv6()).copied().collect();
let check_addr = |addrs: &Vec<SocketAddr>| -> anyhow::Result<SocketAddr> {
let mut err = Vec::new();
if !addrs.is_empty() {
let udp = if addrs[0].is_ipv6() {
UdpSocket::bind("[::]:0")?
@@ -51,12 +52,14 @@ fn address_choose0(addrs: Vec<SocketAddr>) -> anyhow::Result<SocketAddr> {
UdpSocket::bind("0.0.0.0:0")?
};
for addr in addrs {
if udp.connect(addr).is_ok() {
if let Err(e) = udp.connect(addr) {
err.push((*addr, e));
} else {
return Ok(*addr);
}
}
}
Err(anyhow::anyhow!("Unable to connect to address {:?}", addrs))
Err(anyhow::anyhow!("Unable to connect to address {:?}", err))
};
if v6.is_empty() {
return check_addr(&v4);
@@ -78,9 +81,7 @@ pub fn dns_query_all(
mut name_servers: Vec<String>,
) -> anyhow::Result<Vec<SocketAddr>> {
match SocketAddr::from_str(domain) {
Ok(addr) => {
return Ok(vec![addr]);
}
Ok(addr) => Ok(vec![addr]),
Err(_) => {
let txt_domain = domain
.to_lowercase()
@@ -94,7 +95,6 @@ pub fn dns_query_all(
return Ok(domain
.to_socket_addrs()
.with_context(|| format!("DNS query failed {:?}", domain))?
.into_iter()
.collect());
}
}
@@ -102,10 +102,24 @@ 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(":")
.rfind(':')
.with_context(|| format!("{:?} not port", domain))?;
let host = &domain[..end_index];
let port = u16::from_str(&domain[end_index + 1..])
@@ -205,7 +219,7 @@ fn query<'a>(
domain
));
}
if pkt.answers.len() == 0 {
if pkt.answers.is_empty() {
return Err(anyhow::anyhow!(
"No records received DNS {:?} domain {:?}",
name_server,
@@ -226,8 +240,8 @@ pub fn txt_dns(domain: &str, name_server: String) -> anyhow::Result<Vec<SocketAd
if let RData::TXT(txt) = record.data {
for x in txt.iter() {
let txt = std::str::from_utf8(x).context("record type txt is not string")?;
let addr = SocketAddr::from_str(&txt.to_string())
.context("record type txt is not SocketAddr")?;
let addr =
SocketAddr::from_str(txt).context("record type txt is not SocketAddr")?;
rs.push(addr);
}
}
+5
View File
@@ -0,0 +1,5 @@
mod rate_limiter;
pub use rate_limiter::*;
mod traffic_meter;
pub use traffic_meter::*;
+62
View File
@@ -0,0 +1,62 @@
use parking_lot::Mutex;
use std::sync::Arc;
use std::time::Instant;
#[derive(Clone)]
pub struct ConcurrentRateLimiter {
inner: Arc<Mutex<RateLimiter>>,
}
impl ConcurrentRateLimiter {
pub fn new(capacity: usize, refill_rate: usize) -> Self {
let inner = RateLimiter::new(capacity, refill_rate);
Self {
inner: Arc::new(Mutex::new(inner)),
}
}
pub fn try_acquire(&self) -> bool {
self.inner.lock().try_acquire()
}
}
pub struct RateLimiter {
capacity: usize,
tokens: usize,
refill_rate: usize,
last_refill: Instant,
}
impl RateLimiter {
// 初始化限流器
pub fn new(capacity: usize, refill_rate: usize) -> Self {
Self {
capacity,
tokens: capacity,
refill_rate,
last_refill: Instant::now(),
}
}
// 尝试获取一个令牌
pub fn try_acquire(&mut self) -> bool {
self.refill();
if self.tokens > 0 {
self.tokens -= 1;
true
} else {
false
}
}
// 补充令牌
fn refill(&mut self) {
let now = Instant::now();
let elapsed = now.duration_since(self.last_refill).as_secs() as usize;
let new_tokens = elapsed * self.refill_rate;
if new_tokens > 0 {
self.tokens = std::cmp::min(self.capacity, self.tokens + new_tokens);
self.last_refill = now;
}
}
}
+132
View File
@@ -0,0 +1,132 @@
use parking_lot::Mutex;
use std::collections::{HashMap, VecDeque};
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::{Duration, Instant};
#[derive(Clone)]
pub struct TrafficMeterMultiAddress {
history_capacity: usize,
inner: Arc<Mutex<(u64, HashMap<Ipv4Addr, TrafficMeter>)>>,
}
impl Default for TrafficMeterMultiAddress {
fn default() -> Self {
TrafficMeterMultiAddress::new(100)
}
}
impl TrafficMeterMultiAddress {
pub fn new(history_capacity: usize) -> Self {
let inner = Arc::new(Mutex::new((0, HashMap::new())));
Self {
inner,
history_capacity,
}
}
pub fn add_traffic(&self, ip: Ipv4Addr, amount: usize) {
let mut guard = self.inner.lock();
guard.0 += amount as u64;
guard
.1
.entry(ip)
.or_insert(TrafficMeter::new(self.history_capacity))
.add_traffic(amount)
}
pub fn total(&self) -> u64 {
self.inner.lock().0
}
pub fn get_all(&self) -> (u64, HashMap<Ipv4Addr, u64>) {
let guard = self.inner.lock();
(
guard.0,
guard.1.iter().map(|(ip, t)| (*ip, t.total())).collect(),
)
}
pub fn get_all_history(&self) -> (u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>) {
let guard = self.inner.lock();
(
guard.0,
guard
.1
.iter()
.map(|(ip, t)| (*ip, (t.total(), t.get_history())))
.collect(),
)
}
pub fn get_history(&self, ip: &Ipv4Addr) -> Option<(u64, Vec<usize>)> {
self.inner
.lock()
.1
.get(ip)
.map(|t| (t.total(), t.get_history()))
}
}
#[derive(Clone)]
pub struct ConcurrentTrafficMeter {
inner: Arc<Mutex<TrafficMeter>>,
}
impl ConcurrentTrafficMeter {
pub fn new(history_capacity: usize) -> Self {
let inner = Arc::new(Mutex::new(TrafficMeter::new(history_capacity)));
Self { inner }
}
pub fn add_traffic(&self, amount: usize) {
self.inner.lock().add_traffic(amount)
}
pub fn get_history(&self) -> Vec<usize> {
self.inner.lock().get_history()
}
}
pub struct TrafficMeter {
start_time: Instant,
total: u64,
count: usize,
history_capacity: usize,
history: VecDeque<usize>,
}
impl TrafficMeter {
// 初始化一个新的 TrafficMeter
pub fn new(history_capacity: usize) -> Self {
Self {
start_time: Instant::now(),
total: 0,
count: 0,
history: VecDeque::with_capacity(history_capacity),
history_capacity,
}
}
// 增加流量计数
pub fn add_traffic(&mut self, amount: usize) {
self.total += amount as u64;
self.count += amount;
self.check_time();
}
// 检查时间是否超过一秒,如果是,记录流量并重置计数器和时间
fn check_time(&mut self) {
if self.start_time.elapsed() >= Duration::new(1, 0) {
// 将当前计数添加到历史记录
if self.history.len() >= self.history_capacity {
self.history.pop_front(); // 保持历史记录不超过capacity
}
self.history.push_back(self.count);
// 重置计数器和时间
self.count = 0;
self.start_time = Instant::now();
}
}
pub fn total(&self) -> u64 {
self.total
}
// 获取流量记录
pub fn get_history(&self) -> Vec<usize> {
self.history.iter().cloned().collect()
}
}
+10 -5
View File
@@ -1,12 +1,17 @@
mod notify;
mod result_convert;
pub use result_convert::io_convert;
mod scheduler;
pub use notify::StopManager;
pub use notify::{StopManager, Worker};
pub use scheduler::Scheduler;
mod counter;
pub use counter::*;
// mod counter;
// pub use counter::*;
mod dns_query;
pub use dns_query::*;
#[cfg(feature = "upnp")]
mod upnp;
#[cfg(feature = "upnp")]
pub use upnp::*;
pub mod limit;
+49 -18
View File
@@ -1,8 +1,10 @@
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
use std::thread::Thread;
use std::{io, thread};
use std::time::Duration;
use anyhow::anyhow;
use parking_lot::Mutex;
#[derive(Clone)]
@@ -19,20 +21,23 @@ impl StopManager {
inner: Arc::new(StopManagerInner::new(f)),
}
}
pub fn add_listener<F>(&self, name: String, f: F) -> io::Result<Worker>
pub fn add_listener<F>(&self, name: String, f: F) -> anyhow::Result<Worker>
where
F: FnOnce() + Send + 'static,
{
self.inner.add_listener(name, f)
}
pub fn stop(&self) {
self.inner.stop("");
self.inner.stop();
}
pub fn wait(&self) {
self.inner.wait();
}
pub fn is_stop(&self) -> bool {
self.inner.state.load(Ordering::Acquire)
pub fn wait_timeout(&self, dur: Duration) -> bool {
self.inner.wait_timeout(dur)
}
pub fn is_stopped(&self) -> bool {
self.inner.is_stopped()
}
}
@@ -57,39 +62,36 @@ impl StopManagerInner {
stop_call: Mutex::new(Some(Box::new(f))),
}
}
fn add_listener<F>(self: &Arc<Self>, name: String, f: F) -> io::Result<Worker>
fn add_listener<F>(self: &Arc<Self>, name: String, f: F) -> anyhow::Result<Worker>
where
F: FnOnce() + Send + 'static,
{
if name.is_empty() {
return Err(io::Error::new(io::ErrorKind::Other, "name cannot be empty"));
return Err(anyhow!("name cannot be empty"));
}
let mut guard = self.listeners.lock();
if guard.0 {
return Err(io::Error::new(io::ErrorKind::Other, "stopped"));
return Err(anyhow!("stopped"));
}
for (n, _) in &guard.1 {
if &name == n {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("stop add_listener {:?} name already exists", name),
));
return Err(anyhow!("stop add_listener {:?} name already exists", name));
}
}
guard.1.push((name.clone(), Box::new(f)));
Ok(Worker::new(name, self.clone()))
}
fn stop(&self, skip_name: &str) {
fn stop(&self) {
self.state.store(true, Ordering::Release);
let mut guard = self.listeners.lock();
guard.0 = true;
for (name, listener) in guard.1.drain(..) {
if &name == skip_name {
continue;
}
for (_name, listener) in guard.1.drain(..) {
listener();
}
}
pub fn is_stopped(&self) -> bool {
self.worker_num.load(Ordering::Acquire) == 0
}
fn wait(&self) {
{
let mut guard = self.park_threads.lock();
@@ -103,7 +105,20 @@ 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) {
self.stop();
if let Some(call) = self.stop_call.lock().take() {
call();
}
@@ -122,6 +137,19 @@ impl Worker {
}
fn release0(&self) {
let inner = &self.inner;
let worker_name = &self.name;
{
let mut mutex_guard = inner.listeners.lock();
if let Some(pos) = mutex_guard
.1
.iter()
.position(|(name, _)| name == worker_name)
{
let (_, listener) = mutex_guard.1.remove(pos);
listener();
}
}
let count = inner.worker_num.fetch_sub(1, Ordering::AcqRel);
if count == 1 {
for x in inner.park_threads.lock().drain(..) {
@@ -131,7 +159,10 @@ impl Worker {
}
}
pub fn stop_all(self) {
self.inner.stop(&self.name)
self.inner.stop()
}
pub fn stop_self(self) {
drop(self)
}
}
-10
View File
@@ -1,10 +0,0 @@
use std::fmt::Display;
use std::io;
#[inline]
pub fn io_convert<T, R: Display, F: FnOnce(&io::Error) -> R>(
rs: io::Result<T>,
f: F,
) -> io::Result<T> {
rs.map_err(|e| io::Error::new(e.kind(), format!("{},internal error:{:?}", f(&e), e)))
}
+53 -9
View File
@@ -1,8 +1,10 @@
use crate::util::StopManager;
use crossbeam_utils::atomic::AtomicCell;
use std::collections::BinaryHeap;
use std::sync::mpsc::TrySendError;
use std::sync::Arc;
use std::{
cmp::Ordering,
io,
sync::mpsc::{sync_channel, Receiver, SyncSender},
time::{Duration, Instant},
};
@@ -11,45 +13,62 @@ struct DelayedTask {
f: Box<dyn FnOnce(&Scheduler) + Send>,
next: Instant,
}
impl Eq for DelayedTask {}
impl PartialEq for DelayedTask {
fn eq(&self, other: &Self) -> bool {
self.next.eq(&other.next)
}
}
impl PartialOrd for DelayedTask {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
}
}
impl Ord for DelayedTask {
fn cmp(&self, other: &Self) -> Ordering {
self.next.cmp(&other.next).reverse()
}
}
enum Op {
Task(DelayedTask),
Stop,
}
#[derive(Clone)]
pub struct Scheduler {
sender: SyncSender<Op>,
state: Arc<AtomicCell<SchedulerState>>,
}
#[derive(Copy, Clone, Eq, PartialEq)]
enum SchedulerState {
Running,
ShutdownNow, // 立即停止任务执行,队列中剩余的任务不再执行
_Shutdown, //执行完队列中剩余的任务再停止
}
impl Scheduler {
pub fn new(stop_manager: StopManager) -> io::Result<Self> {
pub fn new(stop_manager: StopManager) -> anyhow::Result<Self> {
let (sender, receiver) = sync_channel::<Op>(32);
let s = Self { sender };
let state = Arc::new(AtomicCell::new(SchedulerState::Running));
let s = Self { sender, state };
let s_inner = s.clone();
let worker = {
let scheduler = s.clone();
stop_manager.add_listener("Scheduler".into(), move || {
scheduler.shutdown();
scheduler.shutdown_now();
})?
};
std::thread::Builder::new()
.name("Scheduler".into())
.spawn(move || {
run(receiver, s_inner);
run(receiver, &s_inner);
s_inner.shutdown_now();
worker.stop_all();
})
.expect("Scheduler");
@@ -59,20 +78,44 @@ impl Scheduler {
where
F: FnOnce(&Scheduler) + Send + 'static,
{
if self.state.load() != SchedulerState::Running {
log::error!("定时任务执行停止");
return false;
}
let task = DelayedTask {
f: Box::new(f),
next: Instant::now().checked_add(time).unwrap(),
};
self.sender.send(Op::Task(task)).is_ok()
// 如果是任务中调用此方法,那这里用send可能会导致整个定时任务阻塞
// 任务总数不能大于或等于通道长度,所以改成try_send快速失败
match self.sender.try_send(Op::Task(task)) {
Ok(_) => true,
Err(e) => {
match e {
TrySendError::Full(_) => {
log::error!("定时任务队列达到上限");
}
TrySendError::Disconnected(_) => {
log::error!("定时任务执行停止 通道关闭");
}
}
false
}
}
}
pub fn shutdown(self) {
pub fn shutdown_now(&self) {
self.state.store(SchedulerState::ShutdownNow);
let _ = self.sender.send(Op::Stop);
}
}
fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
fn run(receiver: Receiver<Op>, s_inner: &Scheduler) {
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
loop {
while let Some(task) = binary_heap.peek() {
if s_inner.state.load() == SchedulerState::ShutdownNow {
return;
}
let now = Instant::now();
if now < task.next {
//需要等待对应时间
@@ -90,7 +133,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
}
} else {
if let Some(task) = binary_heap.pop() {
(task.f)(&s_inner);
(task.f)(s_inner);
}
}
}
@@ -121,6 +164,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
}
}
}
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
return match op {
Op::Task(task) => {
+81
View File
@@ -0,0 +1,81 @@
use igd::{search_gateway, PortMappingProtocol};
use std::net::{Ipv4Addr, SocketAddrV4};
use std::ops::Deref;
use std::sync::Arc;
use parking_lot::Mutex;
#[derive(Clone, Default)]
pub struct UPnP {
inner: Arc<UpnpInner>,
}
impl Deref for UPnP {
type Target = UpnpInner;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[derive(Default)]
pub struct UpnpInner {
list: Mutex<Vec<(PortMappingProtocol, u16)>>,
}
impl UpnpInner {
pub fn add_tcp_port(&self, port: u16) {
self.list.lock().push((PortMappingProtocol::TCP, port));
}
pub fn add_udp_port(&self, port: u16) {
self.list.lock().push((PortMappingProtocol::UDP, port));
}
pub fn reset(&self, local_ip: Ipv4Addr) {
let gateway = match search_gateway(Default::default()) {
Ok(gateway) => gateway,
Err(e) => {
log::warn!("search_gateway {:?}", e);
return;
}
};
let guard = self.list.lock();
// 不支持upnp的情况会阻塞30秒,之后再改这个库
for (protocol, port) in guard.iter() {
let local_addr = SocketAddrV4::new(local_ip, *port);
log::info!("add upnp protocol={} {}", protocol, local_addr);
if let Err(e) = gateway.add_port(*protocol, *port, local_addr, 700, "upnp") {
log::warn!(
"add upnp failed protocol={},port={} err:{:?}",
protocol,
port,
e
);
}
}
}
}
impl Drop for UpnpInner {
fn drop(&mut self) {
// let gateway = match search_gateway(Default::default()) {
// Ok(gateway) => gateway,
// Err(e) => {
// log::warn!("search_gateway {:?}", e);
// return;
// }
// };
//
// let guard = self.list.lock();
// for (protocol, port) in guard.iter() {
// if let Err(e) = gateway.remove_port(*protocol, *port) {
// log::warn!(
// "remove upnp failed protocol={},port={} err:{:?}",
// protocol,
// port,
// e
// );
// }
// }
}
}
+1
View File
@@ -11,6 +11,7 @@ libc = "0.2.153"
log = { version = "0.4.20", features = [] }
rand = "0.8.5"
sha2 = { version = "0.10.6", features = ["oid"] }
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
ioctl = { version = "0.8", package = "ioctl-sys" }
+9 -4
View File
@@ -13,6 +13,11 @@ impl Device {
Ok(Self { fd: Fd::new(fd)? })
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.fd
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
@@ -26,7 +31,7 @@ impl IFace for Device {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
fn set_ip(&self, _address: Ipv4Addr, _mask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
@@ -34,15 +39,15 @@ impl IFace for Device {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn set_mtu(&self, value: u32) -> io::Result<()> {
fn set_mtu(&self, _value: u32) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
fn add_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
fn delete_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr) -> io::Result<()> {
Err(io::Error::from(io::ErrorKind::Unsupported))
}
+3 -1
View File
@@ -3,7 +3,6 @@
/// https://github.com/Tazdevil971/tap-windows
/// https://github.com/nulldotblack/wintun
pub mod device;
mod packet;
#[cfg(target_os = "linux")]
mod linux;
@@ -29,3 +28,6 @@ mod windows;
#[cfg(windows)]
pub use windows::Device;
#[cfg(windows)]
mod packet;
+17 -43
View File
@@ -1,29 +1,27 @@
#![allow(dead_code)]
use std::ffi::{CStr, CString};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
use std::process::Command;
use std::{io, mem, ptr};
use libc::{
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TAP, IFF_TUN,
IFF_UP, IFNAMSIZ, O_RDWR, SOCK_DGRAM,
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TUN, IFF_UP,
IFNAMSIZ, O_RDWR, SOCK_DGRAM,
};
use crate::device::IFace;
use crate::linux::route;
use crate::linux::sys::*;
use crate::packet;
use crate::unix::{exe_cmd, Fd, SockAddr};
pub struct Device {
name: String,
ctl: Fd,
tun: Fd,
mac: Option<[u8; 6]>,
}
impl Device {
pub fn new(name: Option<String>, tap: bool) -> io::Result<Self> {
pub fn new(name: Option<String>) -> io::Result<Self> {
let device = unsafe {
let dev = match name {
Some(name) => {
@@ -50,7 +48,7 @@ impl Device {
);
}
let device_type: c_short = if tap { IFF_TAP } else { IFF_TUN } as c_short;
let device_type: c_short = IFF_TUN as c_short; //if tap { IFF_TAP } else { IFF_TUN } as c_short;
let queues_num = 1;
@@ -73,29 +71,11 @@ impl Device {
let name = CStr::from_ptr(req.ifr_name.as_ptr())
.to_string_lossy()
.to_string();
let mac = if tap {
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
let mac_out = exe_cmd(&get_mac_cmd)?;
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
let mut mac = [0; 6];
let mut split = mac_str.split(":");
for i in 0..6 {
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
}
Some(mac)
} else {
None
};
let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name);
if let Err(e) = exe_cmd(&set_txqueuelen){
log::warn!("{:?}",e);
}
Device {
name,
tun,
ctl,
mac,
let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name);
if let Err(e) = exe_cmd(&set_txqueuelen) {
log::warn!("{:?}", e);
}
Device { name, tun, ctl }
};
device.enabled(true)?;
Ok(device)
@@ -234,6 +214,12 @@ impl Device {
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.tun
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
Ok(String::new())
@@ -286,22 +272,10 @@ impl IFace for Device {
}
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
if self.mac.is_some() {
packet::read_tap(
buf,
|eth_buf| self.tun.read(eth_buf),
|eth_buf| self.tun.write(eth_buf),
)
} else {
self.tun.read(buf)
}
self.tun.read(buf)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
if let Some(mac) = &self.mac {
packet::write_tap(buf, |eth_buf| self.tun.write(eth_buf), mac)
} else {
self.tun.write(buf)
}
self.tun.write(buf)
}
}
+6
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use std::ffi::{c_void, CStr};
use std::net::Ipv4Addr;
use std::os::fd::AsRawFd;
@@ -224,6 +225,11 @@ impl Device {
}
}
}
impl Device {
pub fn as_tun_fd(&self) -> &Fd {
&self.tun
}
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
+1
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use std::{fmt, io};
/// 地址解析协议,由IP地址找到MAC地址
+4 -1
View File
@@ -21,7 +21,10 @@ impl<B: AsRef<[u8]>> EthernetPacket<B> {
let packet = EthernetPacket::unchecked(buffer);
//头部固定14位
if packet.buffer.as_ref().len() < 14 {
Err(io::Error::new(io::ErrorKind::InvalidData,format!("len={}", packet.buffer.as_ref().len())))?;
Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("len={}", packet.buffer.as_ref().len()),
))?;
}
Ok(packet)
+1 -1
View File
@@ -13,7 +13,7 @@ where
let mut eth_buf = [0; 65536];
loop {
let len = read_fn(&mut eth_buf)?;
if len == 0{
if len == 0 {
return Ok(len);
}
//处理arp包
+9 -3
View File
@@ -1,3 +1,4 @@
use libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
use std::io;
use std::os::fd::{AsRawFd, IntoRawFd, RawFd};
@@ -10,6 +11,12 @@ impl Fd {
}
Ok(Fd(value))
}
pub fn set_nonblock(&self) -> io::Result<()> {
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
0 => Ok(()),
_ => Err(io::Error::last_os_error()),
}
}
}
impl Fd {
@@ -51,12 +58,11 @@ impl IntoRawFd for Fd {
}
}
#[cfg(not(target_os = "android"))]
impl Drop for Fd {
fn drop(&mut self) {
unsafe {
if self.0 >= 0 {
libc::close(self.0);
}
libc::close(self.0);
}
}
}
+1
View File
@@ -1,6 +1,7 @@
mod fd;
pub use fd::Fd;
#[cfg(any(target_os = "macos", target_os = "linux"))]
use std::process::Output;
#[cfg(any(target_os = "macos", target_os = "linux"))]
mod sockaddr;
+2 -1
View File
@@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::windows::exe_cmd;
use std::io;
use std::net::Ipv4Addr;
use std::{io, process};
/// 设置网卡名称
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
+2 -5
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use std::io;
use std::net::Ipv4Addr;
use winapi::shared::ifdef::NET_LUID;
@@ -11,8 +12,6 @@ use winapi::um::winnt::{
use crate::device::IFace;
use crate::packet;
use crate::packet::ethernet::protocol::Protocol;
use crate::packet::{arp, ethernet};
use crate::windows::{ctl_code, decode_utf16, encode_utf16, ffi, netsh, route};
/* Present in 8.1 */
@@ -97,7 +96,7 @@ impl Device {
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
// 设置网卡跃点
if let Err(e) = netsh::set_interface_metric(index, 0) {
log::warn!("{:?}",e);
log::warn!("{:?}", e);
}
let device = Self {
handle,
@@ -122,8 +121,6 @@ impl Device {
}
}
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
impl IFace for Device {
fn version(&self) -> io::Result<String> {
let mut version = [0u32; 3];
+42 -23
View File
@@ -1,8 +1,8 @@
use libloading::{Error, Library};
#![allow(dead_code)]
use libloading::Library;
use sha2::Digest;
use std::io;
use std::net::Ipv4Addr;
use rand::Rng;
use winapi::um::winbase;
use winapi::um::{synchapi, winnt};
@@ -77,14 +77,15 @@ impl Device {
));
}
wintun_log::set_default_logger_if_unset(&win_tun);
let _ = Self::delete_for_name(&win_tun, &name_utf16);
let mut guid_bytes: [u8; 16] = [0u8; 16];
rand::thread_rng().fill(&mut guid_bytes);
if Self::delete_for_name(&win_tun, &name_utf16).is_ok() {
std::thread::sleep(std::time::Duration::from_millis(500));
}
let guid_bytes: [u8; 16] = hash_guid(&name);
let guid = u128::from_ne_bytes(guid_bytes);
//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
@@ -100,7 +101,7 @@ impl Device {
));
}
// 开启session
let session = win_tun.WintunStartSession(adapter, MAX_RING_CAPACITY);
let session = win_tun.WintunStartSession(adapter, 4 * 1024 * 1024);
if session.is_null() {
log::error!("session.is_null {:?}", io::Error::last_os_error());
return Err(io::Error::new(
@@ -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),
@@ -151,7 +152,14 @@ impl Device {
Ok(())
}
}
fn hash_guid(input: &str) -> [u8; 16] {
let mut hasher = sha2::Sha256::new();
hasher.update(b"VNT");
hasher.update(input.as_bytes());
hasher.update(b"2024");
let hash: [u8; 32] = hasher.finalize().into();
hash[..16].try_into().unwrap()
}
impl IFace for Device {
fn version(&self) -> io::Result<String> {
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
@@ -171,7 +179,7 @@ impl IFace for Device {
fn shutdown(&self) -> io::Result<()> {
unsafe {
if 0 == synchapi::SetEvent(self.shutdown_event) {
if winapi::shared::minwindef::TRUE == synchapi::SetEvent(self.shutdown_event) {
Ok(())
} else {
Err(io::Error::last_os_error())
@@ -236,7 +244,10 @@ impl Device {
if last_error == winapi::shared::winerror::ERROR_NO_MORE_ITEMS {
Ok(None)
} else {
Err(io::Error::new(io::ErrorKind::Other, "try_receive failed"))
Err(io::Error::new(
io::ErrorKind::Other,
format!("try_receive failed {:?}", io::Error::last_os_error()),
))
}
} else {
Ok(Some(packet::TunPacket {
@@ -253,13 +264,21 @@ impl Device {
loop {
//Try 16 times to receive without blocking so we don't have to issue a syscall to wait
//for the event if packets are being received at a rapid rate
for _i in 0..20 {
match self.try_receive()? {
None => {
continue;
}
Some(packet) => {
return Ok(packet);
for i in 0..20 {
match self.try_receive() {
Ok(data) => match data {
None => {
continue;
}
Some(packet) => {
return Ok(packet);
}
},
Err(e) => {
if i > 10 {
// 某些系统存在错误退出的情况(原因不明),这里尝试忽略部分错误
return Err(e);
}
}
}
}
@@ -283,11 +302,11 @@ impl Device {
if result == winbase::WAIT_OBJECT_0 {
//We have data!
continue;
} else if result == winbase::WAIT_OBJECT_0 + 1 {
} else {
//Shutdown event triggered
return Err(io::Error::new(
io::ErrorKind::Other,
"Shutdown event triggered",
format!("Shutdown event triggered {}", io::Error::last_os_error()),
));
}
}
@@ -335,8 +354,8 @@ impl Drop for Device {
}
self.win_tun.WintunEndSession(self.session);
self.win_tun.WintunCloseAdapter(self.adapter);
if 0 != self.win_tun.WintunDeleteDriver() {
log::warn!("WintunDeleteDriver failed")
if winapi::shared::minwindef::FALSE == self.win_tun.WintunDeleteDriver() {
log::warn!("WintunDeleteDriver failed {:?}", io::Error::last_os_error())
}
}
}
+1
View File
@@ -1,3 +1,4 @@
#![allow(dead_code)]
use log::*;
use crate::windows::tun::wintun_raw;
+2
View File
@@ -1,3 +1,5 @@
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
/* automatically generated by rust-bindgen 0.59.1 */
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]