Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
959f2aa783 | ||
|
|
99b2aa9522 | ||
|
|
561fa9f8fe | ||
|
|
ad9dd6a7f7 | ||
|
|
65758eb94c | ||
|
|
fb7ccf4d11 | ||
|
|
b9fe5e0fe2 | ||
|
|
c3368481ad | ||
|
|
cdf5c3a508 | ||
|
|
f9217625e1 | ||
|
|
323f6c9221 | ||
|
|
2e507f1a9d | ||
|
|
e611d69a25 | ||
|
|
45d8c6717d | ||
|
|
756539c3bd | ||
|
|
3d4fcdbc96 | ||
|
|
3cd19dbc1f | ||
|
|
7b770a1bb0 | ||
|
|
0472b1590e | ||
|
|
81764433d8 | ||
|
|
9ee6e101c4 | ||
|
|
565e80b994 | ||
|
|
7ccc4535e4 | ||
|
|
d1bde297d6 | ||
|
|
c5398a51e8 | ||
|
|
fddb59992b | ||
|
|
665e25b1a3 | ||
|
|
fdb4bb1155 | ||
|
|
f104e191ed | ||
|
|
6311d75ac0 | ||
|
|
c3f134e332 | ||
|
|
5bccdf3bbe | ||
|
|
9e881eeecd | ||
|
|
fbe01d8cbf | ||
|
|
d336d938a9 | ||
|
|
598923c95a | ||
|
|
0afe4c4417 | ||
|
|
dff51caf35 | ||
|
|
7c30f2691a | ||
|
|
c6aca2c2dc | ||
|
|
28ac8cf88e | ||
|
|
62b2af54a2 | ||
|
|
a2d45da44d | ||
|
|
d937f392d3 | ||
|
|
2c9abf314a | ||
|
|
ab7abd0c1f | ||
|
|
71a2e3c592 | ||
|
|
aa6d3a6843 | ||
|
|
9b42c5d092 | ||
|
|
2f7817ce5b | ||
|
|
e7c6bcf9a9 | ||
|
|
b6b8971b12 | ||
|
|
ba4a0e008b | ||
|
|
4baccc5047 | ||
|
|
6cf71c8068 | ||
|
|
8e556a20ee | ||
|
|
5f28a5044a | ||
|
|
16d295bf32 | ||
|
|
32163e077e | ||
|
|
6a5a40a7d3 | ||
|
|
161ecc865c | ||
|
|
1a5d40ff2d | ||
|
|
6b988e0612 | ||
|
|
8d44934382 | ||
|
|
6b140b0f71 | ||
|
|
c2b7b02f3f | ||
|
|
24140c2145 | ||
|
|
a6050e5f59 | ||
|
|
50e97fd95f | ||
|
|
890e5f7391 | ||
|
|
be3bf82e35 | ||
|
|
e8af503130 | ||
|
|
466174ef88 | ||
|
|
ba2c792e2a | ||
|
|
17f3fcf9b0 | ||
|
|
11d1ff4b42 | ||
|
|
b640bc50ef | ||
|
|
4bbd5282ee | ||
|
|
d7fd504f8f | ||
|
|
cf4375b405 | ||
|
|
45da060c1a | ||
|
|
4dc84914dd | ||
|
|
c1ee7ac11c | ||
|
|
409b57c171 | ||
|
|
ff4580b9bf | ||
|
|
6daa75d2f2 | ||
|
|
59f07f2d75 | ||
|
|
44035685c8 | ||
|
|
c8d0f3850f | ||
|
|
b846f54d79 | ||
|
|
bb7b1d23af | ||
|
|
9e700b3094 | ||
|
|
38f28e313c | ||
|
|
63f03fb11f | ||
|
|
cf7854906f | ||
|
|
78ae5f3036 | ||
|
|
c412a256b8 | ||
|
|
94def558fc | ||
|
|
25e9c523d3 | ||
|
|
a009d06000 | ||
|
|
675e0c52ff | ||
|
|
dc4219753a | ||
|
|
c003b9acbb | ||
|
|
f4869ebd1d | ||
|
|
de4f42537d | ||
|
|
b9ebe80ef3 | ||
|
|
ea5ba750d4 | ||
|
|
b594afce16 | ||
|
|
ed3c44d6cf | ||
|
|
35ed7f7e45 | ||
|
|
068580e036 | ||
|
|
ea61b06e58 | ||
|
|
f260c26e4f | ||
|
|
9cea433a8b | ||
|
|
38dce9c13b | ||
|
|
04731f1ce5 | ||
|
|
3ddcb629c0 | ||
|
|
12bd058152 | ||
|
|
c9b1bf5a5e | ||
|
|
18df3c2c92 | ||
|
|
c08b9cefe9 | ||
|
|
258a35740f | ||
|
|
32cfe9a3a8 | ||
|
|
930a4fcf29 | ||
|
|
5a778d5fc3 | ||
|
|
1d64cfc930 | ||
|
|
3eab02bc68 | ||
|
|
dcdd03b746 | ||
|
|
51acb2da9b | ||
|
|
0d2c107e20 | ||
|
|
2089ba7997 | ||
|
|
8a032f86d8 | ||
|
|
5dcda4d088 | ||
|
|
8d76214193 | ||
|
|
24ddf04d7f | ||
|
|
79fa2a0823 | ||
|
|
ddfb5ac943 | ||
|
|
ed622409b0 | ||
|
|
b6beaa09ec | ||
|
|
7840f30b64 | ||
|
|
d7226d8522 | ||
|
|
8d5c9cedb3 | ||
|
|
6f7992ea9f | ||
|
|
5b2c2435d5 | ||
|
|
ebf84db204 | ||
|
|
94e83d80a6 | ||
|
|
bc80d5f641 | ||
|
|
81a5480250 | ||
|
|
e69d416dc4 | ||
|
|
15370203a1 | ||
|
|
8ca09d72bd | ||
|
|
d16cbe4ac6 | ||
|
|
49ac8827cd | ||
|
|
f2f686d31f | ||
|
|
6872ec3618 | ||
|
|
efb7053931 | ||
|
|
80109fd8aa | ||
|
|
b3abb175c1 | ||
|
|
f05577c927 | ||
|
|
c631f2bb0d | ||
|
|
ad5aac7ef5 | ||
|
|
5cd9179ce7 | ||
|
|
af58c3990d | ||
|
|
206c543e8c | ||
|
|
9820c56be6 | ||
|
|
2232965a1d | ||
|
|
6bfadfe5b8 | ||
|
|
c655d9650b | ||
|
|
61086089b3 | ||
|
|
c89d0124a1 | ||
|
|
a1a5839b20 | ||
|
|
c9e3dc83ab | ||
|
|
c179670b14 | ||
|
|
292893e9dd | ||
|
|
d956e493af | ||
|
|
05c85db52a | ||
|
|
49350933c3 | ||
|
|
fa3fed3fbd | ||
|
|
5df9a357ec | ||
|
|
bce9c57e60 | ||
|
|
f39de52c65 | ||
|
|
4001527a87 | ||
|
|
85be89ddf0 |
@@ -0,0 +1,196 @@
|
||||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# necessary for windows
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# test:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - name: Init submodules
|
||||
# uses: snickerbockers/submodules-init@v4
|
||||
# - name: Cargo cache
|
||||
# uses: actions/cache@v2
|
||||
# with:
|
||||
# path: |
|
||||
# ~/.cargo/registry
|
||||
# ./target
|
||||
# key: test-cargo-registry
|
||||
# - name: List
|
||||
# run: find ./
|
||||
# - name: Run tests
|
||||
# run: cargo test --verbose
|
||||
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# a list of all the targets
|
||||
include:
|
||||
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: x86_64-unknown-linux-gnu # tested in a debian container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-unknown-linux-gnu # tested on aws t4g.nano
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: armv7-unknown-linux-gnueabihf # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: arm-unknown-linux-gnueabihf # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: i686-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-latest
|
||||
FEATURES: ring-cipher
|
||||
- TARGET: mipsel-unknown-linux-musl # openwrt
|
||||
OS: ubuntu-latest
|
||||
FEATURES: normal
|
||||
# needs: test
|
||||
runs-on: ${{ matrix.OS }}
|
||||
env:
|
||||
NAME: vnt-cli # change with the name of your project
|
||||
TARGET: ${{ matrix.TARGET }}
|
||||
OS: ${{ matrix.OS }}
|
||||
FEATURES: ${{ matrix.FEATURES }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Init submodules
|
||||
uses: snickerbockers/submodules-init@v4
|
||||
- name: Cargo cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
./target
|
||||
key: build-cargo-registry-${{matrix.TARGET}}
|
||||
- name: List
|
||||
run: find ./
|
||||
- name: Install and configure dependencies
|
||||
run: |
|
||||
# dependencies are only needed on ubuntu as that's the only place where
|
||||
# we make cross-compilation
|
||||
if [[ $OS =~ ^ubuntu.*$ ]]; then
|
||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools gcc-mipsel-linux-gnu
|
||||
fi
|
||||
# some additional configuration for cross-compilation on linux
|
||||
cat >>~/.cargo/config <<EOF
|
||||
[target.x86_64-unknown-linux-musl]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.armv7-unknown-linux-gnueabihf]
|
||||
linker = "arm-linux-gnueabihf-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.armv7-unknown-linux-musleabihf]
|
||||
linker = "arm-linux-gnueabihf-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.arm-unknown-linux-gnueabihf]
|
||||
linker = "arm-linux-gnueabihf-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.arm-unknown-linux-musleabihf]
|
||||
linker = "arm-linux-gnueabihf-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.mipsel-unknown-linux-musl]
|
||||
linker = "mipsel-linux-gnu-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.i686-pc-windows-msvc]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.x86_64-apple-darwin]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.aarch64-apple-darwin]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.i686-unknown-linux-musl]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
EOF
|
||||
- name: Install rust target
|
||||
run: rustup target add $TARGET
|
||||
- name: Run build
|
||||
run: cargo build --package vnt-cli --release --verbose --target $TARGET --features $FEATURES
|
||||
- name: List target
|
||||
run: find ./target
|
||||
- name: Compress
|
||||
run: |
|
||||
mkdir -p ./artifacts
|
||||
# windows is the only OS using a different convention for executable file name
|
||||
if [[ $OS =~ ^windows.*$ ]]; then
|
||||
EXEC=$NAME.exe
|
||||
else
|
||||
EXEC=$NAME
|
||||
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
|
||||
- name: Archive artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: vnt-cli
|
||||
path: |
|
||||
./artifacts
|
||||
# deploys to github releases on tag
|
||||
deploy:
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: vnt-cli
|
||||
path: ./artifacts
|
||||
- name: List
|
||||
run: find ./artifacts
|
||||
- name: Release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.YOURTOKEN }}
|
||||
file: ./artifacts/*.tar.gz
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
+13
-43
@@ -1,44 +1,14 @@
|
||||
[package]
|
||||
name = "switch"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
[workspace]
|
||||
members = ["vnt","common","vnt-cli","vnt-jni"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
packet = { path = "./packet" }
|
||||
bytes = "1.3.0"
|
||||
|
||||
libc = "0.2.137"
|
||||
|
||||
dashmap = "5.4.0"
|
||||
crossbeam = "0.8.2"
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
rsa = "0.7.2"
|
||||
rand = "0.8.5"
|
||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||
#colored = "2.0.0"
|
||||
|
||||
thiserror = "1.0.37"
|
||||
chrono = "0.4.23"
|
||||
lazy_static = "1.4.0"
|
||||
moka = "0.9.6"
|
||||
protobuf = "3.2.0"
|
||||
|
||||
console = "0.15.2"
|
||||
mac_address = "1.1.4"
|
||||
clap = { version = "4.0.32", features = ["derive"] }
|
||||
[target.'cfg(any(unix))'.dependencies]
|
||||
tun = { path = "./rust-tun" }
|
||||
sudo = "0.6.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||
wintun = "0.2.1"
|
||||
libloading = "0.7.4"
|
||||
runas = "0.2.1"
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen = "3.2.0"
|
||||
protoc-bin-vendored = "3.0.0"
|
||||
[profile.release]
|
||||
opt-level = 'z'
|
||||
debug = 0
|
||||
debug-assertions = false
|
||||
strip= "debuginfo"
|
||||
overflow-checks = true
|
||||
lto = true
|
||||
panic = 'abort'
|
||||
incremental = false
|
||||
codegen-units = 1
|
||||
rpath = false
|
||||
|
||||
@@ -1,38 +1,163 @@
|
||||
# switch
|
||||
Virtual Network Tools
|
||||
# Vnt
|
||||
|
||||
将不同网络下的设备虚拟到一个局域网下
|
||||
A virtual network tool (VPN)
|
||||
|
||||
将不同网络下的多个设备虚拟到一个局域网下
|
||||
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
|
||||
### 快速使用:
|
||||
|
||||
### 示例:
|
||||
1. 指定一个token,在多台设备上运行该程序,例如:
|
||||
```shell
|
||||
# linux上
|
||||
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli -k 123456
|
||||
# 在另一台linux上使用nohup后台运行
|
||||
root@izj6cemne76ykdzkataftfz vnt# nohup ./vnt-cli -k 123456 &
|
||||
# windows上
|
||||
D:\vnt\bin_v1>vnt-cli.exe -k 123456
|
||||
```
|
||||
2. 可以执行info命令查看当前设备的虚拟ip
|
||||
```shell
|
||||
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli --info
|
||||
Name: Ubuntu 18.04 (bionic) [64-bit]
|
||||
Virtual ip: 10.26.0.2
|
||||
Virtual gateway: 10.26.0.1
|
||||
Virtual netmask: 255.255.255.0
|
||||
Connection status: Connected
|
||||
NAT type: Cone
|
||||
Relay server: 43.139.56.10:29871
|
||||
Public ips: 120.228.76.75
|
||||
Local ip: 172.25.165.58
|
||||
```
|
||||
3. 也可以执行list命令查看其他设备的虚拟ip
|
||||
```shell
|
||||
root@DESKTOP-0BCHNIO:/opt# ./vnt-cli --list
|
||||
Name Virtual Ip P2P/Relay Rt Status
|
||||
Windows 10.0.22621 (Windows 11 Professional) [64-bit] 10.26.0.3 p2p 2 Online
|
||||
CentOS 7.9.2009 (Core) [64-bit] 10.26.0.4 p2p 35 Online
|
||||
```
|
||||
4. 最后可以用虚拟ip实现设备间相互访问
|
||||
|
||||
- 在一台mac设备上运行,获取到ip 10.13.0.2:
|
||||
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/vnt/dev/documents/img/ssh.jpg">
|
||||
5. 帮助,使用-h命令查看
|
||||
|
||||
<img width="506" alt="图片" src="https://user-images.githubusercontent.com/49143209/210379090-a3f21007-5a12-44d3-81d6-a69495209ea7.png">
|
||||
### 更多玩法
|
||||
|
||||
- 在另一台windows上运行,获取到ip 10.13.0.3:
|
||||
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
|
||||
2. 安装samba服务,共享磁盘
|
||||
3. 搭配公网服务器nginx反向代理,在公网访问内网文件或服务
|
||||
4. 点对网,访问内网其他机器、IP代理(结合启动参数'-i'和'-o')
|
||||
|
||||

|
||||
|
||||
- 此时这两个设备之间就能用ip相互访问了
|
||||
|
||||
<img width="437" alt="图片" src="https://user-images.githubusercontent.com/49143209/210380969-4a7c0f23-1e88-4ab6-9cc2-0c0f086848ac.png">
|
||||
### 使用须知
|
||||
|
||||
- token的作用是标识一个虚拟局域网,当使用公共服务器时,建议使用一个唯一值当token(比如uuid),否则有可能连接到其他人创建的虚拟局域网中
|
||||
- 公共服务器目前的配置是2核4G 4Mbps,有需要再扩展~
|
||||
- 默认使用公共服务器做注册和中继,目前的配置是2核4G 4Mbps,有需要再扩展~
|
||||
- 需要root/管理员权限
|
||||
- vnt-cli需要使用命令行运行
|
||||
- Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli)
|
||||
- 可以自己搭注册和中继服务器([server](https://github.com/lbl8603/vnts))
|
||||
- vnt使用stun服务器探测网络NAT类型,默认使用谷歌和腾讯的stun服务器,也可自己搭建(-e参数指定)
|
||||
|
||||
### 编译
|
||||
|
||||
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
|
||||
|
||||
到项目根目录下执行 cargo build -p vnt-cli
|
||||
|
||||
### 支持平台
|
||||
|
||||
- Mac
|
||||
- Linux
|
||||
- Windows
|
||||
- 依赖 wintun.dll(https://www.wintun.net/)
|
||||
- 使用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
|
||||
- [SwitchApp](https://github.com/lbl8603/SwitchApp)
|
||||
|
||||
### 特性
|
||||
|
||||
- IP层数据转发
|
||||
- tun虚拟网卡
|
||||
- tun虚拟网卡
|
||||
- tap虚拟网卡
|
||||
- NAT穿透
|
||||
- 点对点穿透
|
||||
- 服务端中继转发
|
||||
- 点对点穿透
|
||||
- 服务端中继转发
|
||||
- 客户端中继转发
|
||||
- IP代理
|
||||
- p2p组播/广播
|
||||
- 客户端数据加密
|
||||
- 服务端数据加密
|
||||
### 结构
|
||||
<details> <summary>展开</summary>
|
||||
|
||||
<pre>
|
||||
|
||||
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 |unused| 版本(4) | 协议(8) | 上层协议(8) |初始ttl(4)|生存时间(4) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 源ip地址(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 目的ip地址(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 数据体(n) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
| 指纹(96) |
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
注:
|
||||
1. e为是否加密标志,s为服务端通信包标志,unused占两位未使用;
|
||||
2. 开启加密时,数据体为加密后的密文(加密方式取决于密码长度和加密模式),
|
||||
且会存在指纹,指纹使用sha256生成,用于对数据包完整性和真实性的校验
|
||||
</pre>
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
### Todo
|
||||
- 数据加密
|
||||
- 客户端中继转发
|
||||
|
||||
- 桌面UI(测试中)
|
||||
- 支持Ipv6
|
||||
|
||||
### 常见问题
|
||||
<details> <summary>展开</summary>
|
||||
|
||||
#### 问题1: 设置网络地址失败
|
||||
|
||||
##### 可能原因:
|
||||
|
||||
vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
|
||||
|
||||
##### 解决方法:
|
||||
|
||||
1. 方法一:找到冲突的IP,将其改成别的
|
||||
2. 方法二:自建服务器,指定其他不会冲突的网段
|
||||
3. 方法三:增加参数-d <device-id> ,设置不同的id会让服务端分配不同的IP,从而绕开有冲突的IP
|
||||
|
||||
#### 问题2: windows系统上wintun.dll加载失败
|
||||
|
||||
##### 可能原因:
|
||||
没有下载wintun.dll 或者使用的wintun.dll有问题
|
||||
##### 解决方法:
|
||||
1. 下载最新版的wintun.dll [下载链接](https://www.wintun.net/builds/wintun-0.14.1.zip)
|
||||
2. 解压后找到对应架构的目录,通常是amd64
|
||||
3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下)
|
||||
4. 再次启动vnt-cli
|
||||
|
||||
#### 问题3: 丢包严重,或是不能正常组网通信
|
||||
##### 可能原因:
|
||||
某些宽带下(比如广电宽带)UDP丢包严重
|
||||
##### 解决方法:
|
||||
1. 使用TCP模式中继转发(vnt-cli增加--tcp参数)
|
||||
2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--relay参数)
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
### 交流群
|
||||
|
||||
QQ:1034868233
|
||||
### 其他
|
||||
可使用社区小伙伴搭建的中继服务器
|
||||
1. -s vnt.8443.eu.org:29871
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "1.2.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,79 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
pub fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, String> {
|
||||
let mut in_ips_c = vec![];
|
||||
for x in ips {
|
||||
let mut split = x.split(",");
|
||||
let net = if let Some(net) = split.next() {
|
||||
net
|
||||
} else {
|
||||
return Err("ipv4/mask,ipv4".to_string());
|
||||
};
|
||||
let ip = if let Some(ip) = split.next() {
|
||||
ip
|
||||
} else {
|
||||
return Err("ipv4/mask,ipv4".to_string());
|
||||
};
|
||||
let ip = if let Ok(ip) = ip.parse::<Ipv4Addr>() {
|
||||
ip
|
||||
} else {
|
||||
return Err("not ipv4".to_string());
|
||||
};
|
||||
let mut split = net.split("/");
|
||||
let dest = if let Some(dest) = split.next() {
|
||||
dest
|
||||
} else {
|
||||
return Err("no ipv4/mask".to_string());
|
||||
};
|
||||
let mask = if let Some(mask) = split.next() {
|
||||
mask
|
||||
} else {
|
||||
return Err("no netmask".to_string());
|
||||
};
|
||||
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
|
||||
dest
|
||||
} else {
|
||||
return Err("not ipv4".to_string());
|
||||
};
|
||||
let mask = to_ip(mask)?;
|
||||
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
|
||||
}
|
||||
Ok(in_ips_c)
|
||||
}
|
||||
|
||||
pub fn out_ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32)>, String> {
|
||||
let mut in_ips_c = vec![];
|
||||
for x in ips {
|
||||
let mut split = x.split("/");
|
||||
let dest = if let Some(dest) = split.next() {
|
||||
dest
|
||||
} else {
|
||||
return Err("no ipv4/mask".to_string());
|
||||
};
|
||||
let mask = if let Some(mask) = split.next() {
|
||||
mask
|
||||
} else {
|
||||
return Err("no netmask".to_string());
|
||||
};
|
||||
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
|
||||
dest
|
||||
} else {
|
||||
return Err("not ipv4".to_string());
|
||||
};
|
||||
let mask = to_ip(mask)?;
|
||||
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask));
|
||||
}
|
||||
Ok(in_ips_c)
|
||||
}
|
||||
|
||||
pub fn to_ip(mask: &str) -> Result<u32, String> {
|
||||
if let Ok(m) = mask.parse::<u32>() {
|
||||
let mut mask = 0 as u32;
|
||||
for i in 0..m {
|
||||
mask = mask | (1 << (31 - i));
|
||||
}
|
||||
Ok(mask)
|
||||
} else {
|
||||
Err("not netmask".to_string())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn get_unique_identifier() -> Option<String> {
|
||||
use std::os::windows::process::CommandExt;
|
||||
let output = match Command::new("wmic")
|
||||
.creation_flags(0x08000000)
|
||||
.args(&["csproduct", "get", "UUID"])
|
||||
.output() {
|
||||
Ok(output) => { output }
|
||||
Err(_) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let result = String::from_utf8_lossy(&output.stdout);
|
||||
let identifier = result.lines().nth(1).unwrap_or("").trim();
|
||||
if identifier.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(identifier.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn get_unique_identifier() -> Option<String> {
|
||||
let output = match Command::new("ioreg")
|
||||
.args(&["-rd1", "-c", "IOPlatformExpertDevice"])
|
||||
.output() {
|
||||
Ok(output) => { output }
|
||||
Err(_) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let result = String::from_utf8_lossy(&output.stdout);
|
||||
let identifier = result
|
||||
.lines()
|
||||
.find(|line| line.contains("IOPlatformUUID"))
|
||||
.unwrap_or("").trim();
|
||||
if identifier.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(identifier.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn get_unique_identifier() -> Option<String> {
|
||||
let output = match Command::new("dmidecode")
|
||||
.arg("-s")
|
||||
.arg("system-uuid")
|
||||
.output() {
|
||||
Ok(output) => { output }
|
||||
Err(_) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let result = String::from_utf8_lossy(&output.stdout);
|
||||
let identifier = result.trim().to_string();
|
||||
if identifier.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(identifier.to_string())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod identifier;
|
||||
pub mod args_parse;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -1,25 +0,0 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("the buffer is too small")]
|
||||
SmallBuffer,
|
||||
|
||||
#[error("the packet is invalid")]
|
||||
InvalidPacket,
|
||||
#[error("Unimplemented")]
|
||||
Unimplemented,
|
||||
// #[error("the vaue is invalid for the field")]
|
||||
// InvalidValue,
|
||||
//
|
||||
// #[error("the value has already been defined")]
|
||||
// AlreadyDefined,
|
||||
//
|
||||
// #[error(transparent)]
|
||||
// Io(#[from] io::Error),
|
||||
//
|
||||
// #[error(transparent)]
|
||||
// Nul(#[from] ffi::NulError),
|
||||
}
|
||||
|
||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
@@ -1,40 +0,0 @@
|
||||
syntax = "proto3";
|
||||
message RegistrationRequest{
|
||||
string token = 1;
|
||||
string mac_address = 2;
|
||||
}
|
||||
|
||||
message RegistrationResponse{
|
||||
fixed32 virtual_ip = 1;
|
||||
fixed32 virtual_gateway = 2;
|
||||
fixed32 virtual_netmask = 3;
|
||||
uint32 epoch = 4;
|
||||
repeated fixed32 virtual_ip_list = 5;
|
||||
fixed32 public_ip = 6;
|
||||
uint32 public_port = 7;
|
||||
}
|
||||
|
||||
message DeviceList{
|
||||
uint32 epoch = 1;
|
||||
repeated fixed32 virtual_ip_list = 2;
|
||||
}
|
||||
|
||||
message Punch{
|
||||
fixed32 virtual_ip = 1;
|
||||
repeated fixed32 public_ip_list = 2;
|
||||
uint32 public_port = 3;
|
||||
uint32 public_port_range = 4;
|
||||
NatType nat_type = 5;
|
||||
bool reply = 6;
|
||||
Step step = 7;
|
||||
}
|
||||
enum NatType{
|
||||
Symmetric = 0;
|
||||
Cone = 1;
|
||||
}
|
||||
enum Step{
|
||||
Step1 = 0;
|
||||
Step2 = 1;
|
||||
Step3 = 2;
|
||||
Step4 = 3;
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
TUN interfaces [](https://crates.io/crates/tun)  
|
||||
==============
|
||||
This crate allows the creation and usage of TUN interfaces, the aim is to make this cross-platform.
|
||||
|
||||
Usage
|
||||
-----
|
||||
First, add the following to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tun = "0.5"
|
||||
```
|
||||
|
||||
Next, add this to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate tun;
|
||||
```
|
||||
|
||||
If you want to use the TUN interface with mio/tokio, you need to enable the `async` feature:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tun = { version = "0.5", features = ["async"] }
|
||||
```
|
||||
|
||||
Example
|
||||
-------
|
||||
The following example creates and configures a TUN interface and starts reading
|
||||
packets from it.
|
||||
|
||||
```rust
|
||||
use std::io::Read;
|
||||
|
||||
extern crate tun;
|
||||
|
||||
fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
config.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let mut dev = tun::create(&config).unwrap();
|
||||
let mut buf = [0; 4096];
|
||||
|
||||
loop {
|
||||
let amount = dev.read(&mut buf).unwrap();
|
||||
println!("{:?}", &buf[0 .. amount]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Platforms
|
||||
=========
|
||||
Not every platform is supported.
|
||||
|
||||
Linux
|
||||
-----
|
||||
You will need the `tun` module to be loaded and root is required to create
|
||||
interfaces.
|
||||
|
||||
macOS
|
||||
-----
|
||||
It just werks, but you have to set up routing manually.
|
||||
|
||||
iOS
|
||||
----
|
||||
You can pass the file descriptor of the TUN device to `rust-tun` to create the interface.
|
||||
|
||||
Here is an example to create the TUN device on iOS and pass the `fd` to `rust-tun`:
|
||||
```swift
|
||||
// Swift
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||
let tunnelNetworkSettings = createTunnelSettings() // Configure TUN address, DNS, mtu, routing...
|
||||
setTunnelNetworkSettings(tunnelNetworkSettings) { [weak self] error in
|
||||
let tunFd = self?.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
start_tun(tunFd)
|
||||
}
|
||||
completionHandler(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
#[no_mangle]
|
||||
pub extern "C" fn start_tun(fd: std::os::raw::c_int) {
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let mut cfg = tun::Configuration::default();
|
||||
cfg.raw_fd(fd);
|
||||
let mut tun = tun::create_as_async(&cfg).unwrap();
|
||||
let mut framed = tun.into_framed();
|
||||
while let Some(packet) = framed.next().await {
|
||||
...
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
@@ -1,78 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use packet::{builder::Builder, icmp, ip, Packet};
|
||||
use tun::{self, Configuration, TunPacket};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut config = Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let dev = tun::create_as_async(&config).unwrap();
|
||||
|
||||
let mut framed = dev.into_framed();
|
||||
|
||||
while let Some(packet) = framed.next().await {
|
||||
match packet {
|
||||
Ok(pkt) => match ip::Packet::new(pkt.get_bytes()) {
|
||||
Ok(ip::Packet::V4(pkt)) => match icmp::Packet::new(pkt.payload()) {
|
||||
Ok(icmp) => match icmp.echo() {
|
||||
Ok(icmp) => {
|
||||
let reply = ip::v4::Builder::default()
|
||||
.id(0x42)
|
||||
.unwrap()
|
||||
.ttl(64)
|
||||
.unwrap()
|
||||
.source(pkt.destination())
|
||||
.unwrap()
|
||||
.destination(pkt.source())
|
||||
.unwrap()
|
||||
.icmp()
|
||||
.unwrap()
|
||||
.echo()
|
||||
.unwrap()
|
||||
.reply()
|
||||
.unwrap()
|
||||
.identifier(icmp.identifier())
|
||||
.unwrap()
|
||||
.sequence(icmp.sequence())
|
||||
.unwrap()
|
||||
.payload(icmp.payload())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
framed.send(TunPacket::new(reply)).await.unwrap();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
},
|
||||
Err(err) => println!("Received an invalid packet: {:?}", err),
|
||||
_ => {}
|
||||
},
|
||||
Err(err) => panic!("Error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use bytes::BytesMut;
|
||||
use futures::StreamExt;
|
||||
use packet::{ip::Packet, Error};
|
||||
use tokio_util::codec::{Decoder, FramedRead};
|
||||
|
||||
pub struct IPPacketCodec;
|
||||
|
||||
impl Decoder for IPPacketCodec {
|
||||
type Item = Packet<BytesMut>;
|
||||
type Error = Error;
|
||||
|
||||
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if buf.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let buf = buf.split_to(buf.len());
|
||||
Ok(match Packet::no_payload(buf) {
|
||||
Ok(pkt) => Some(pkt),
|
||||
Err(err) => {
|
||||
println!("error {:?}", err);
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
let dev = tun::create_as_async(&config).unwrap();
|
||||
|
||||
let mut stream = FramedRead::new(dev, IPPacketCodec);
|
||||
|
||||
while let Some(packet) = stream.next().await {
|
||||
match packet {
|
||||
Ok(pkt) => println!("pkt: {:#?}", pkt),
|
||||
Err(err) => panic!("Error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use futures::StreamExt;
|
||||
use packet::ip::Packet;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let dev = tun::create_as_async(&config).unwrap();
|
||||
|
||||
let mut stream = dev.into_framed();
|
||||
|
||||
while let Some(packet) = stream.next().await {
|
||||
match packet {
|
||||
Ok(pkt) => println!("pkt: {:#?}", Packet::unchecked(pkt.get_bytes())),
|
||||
Err(err) => panic!("Error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
fn main() {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.address((10, 0, 0, 1))
|
||||
.netmask((255, 255, 255, 0))
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let mut dev = tun::create(&config).unwrap();
|
||||
let mut buf = [0; 4096];
|
||||
|
||||
loop {
|
||||
let amount = dev.read(&mut buf).unwrap();
|
||||
println!("{:?}", &buf[0..amount]);
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::io;
|
||||
|
||||
use byteorder::{NativeEndian, NetworkEndian, WriteBytesExt};
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use tokio_util::codec::{Decoder, Encoder};
|
||||
|
||||
/// A packet protocol IP version
|
||||
#[derive(Debug)]
|
||||
enum PacketProtocol {
|
||||
IPv4,
|
||||
IPv6,
|
||||
Other(u8),
|
||||
}
|
||||
|
||||
// Note: the protocol in the packet information header is platform dependent.
|
||||
impl PacketProtocol {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn into_pi_field(&self) -> Result<u16, io::Error> {
|
||||
match self {
|
||||
PacketProtocol::IPv4 => Ok(libc::ETH_P_IP as u16),
|
||||
PacketProtocol::IPv6 => Ok(libc::ETH_P_IPV6 as u16),
|
||||
PacketProtocol::Other(_) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"neither an IPv4 or IPv6 packet",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
fn into_pi_field(&self) -> Result<u16, io::Error> {
|
||||
match self {
|
||||
PacketProtocol::IPv4 => Ok(libc::PF_INET as u16),
|
||||
PacketProtocol::IPv6 => Ok(libc::PF_INET6 as u16),
|
||||
PacketProtocol::Other(_) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"neither an IPv4 or IPv6 packet",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A Tun Packet to be sent or received on the TUN interface.
|
||||
#[derive(Debug)]
|
||||
pub struct TunPacket(PacketProtocol, Bytes);
|
||||
|
||||
/// Infer the protocol based on the first nibble in the packet buffer.
|
||||
fn infer_proto(buf: &[u8]) -> PacketProtocol {
|
||||
match buf[0] >> 4 {
|
||||
4 => PacketProtocol::IPv4,
|
||||
6 => PacketProtocol::IPv6,
|
||||
p => PacketProtocol::Other(p),
|
||||
}
|
||||
}
|
||||
|
||||
impl TunPacket {
|
||||
/// Create a new `TunPacket` based on a byte slice.
|
||||
pub fn new(bytes: Vec<u8>) -> TunPacket {
|
||||
let proto = infer_proto(&bytes);
|
||||
TunPacket(proto, Bytes::from(bytes))
|
||||
}
|
||||
|
||||
/// Return this packet's bytes.
|
||||
pub fn get_bytes(&self) -> &[u8] {
|
||||
&self.1
|
||||
}
|
||||
|
||||
pub fn into_bytes(self) -> Bytes {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
/// A TunPacket Encoder/Decoder.
|
||||
pub struct TunPacketCodec(bool, i32);
|
||||
|
||||
impl TunPacketCodec {
|
||||
/// Create a new `TunPacketCodec` specifying whether the underlying
|
||||
/// tunnel Device has enabled the packet information header.
|
||||
pub fn new(pi: bool, mtu: i32) -> TunPacketCodec {
|
||||
TunPacketCodec(pi, mtu)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder for TunPacketCodec {
|
||||
type Item = TunPacket;
|
||||
type Error = io::Error;
|
||||
|
||||
fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if buf.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut pkt = buf.split_to(buf.len());
|
||||
|
||||
// reserve enough space for the next packet
|
||||
if self.0 {
|
||||
buf.reserve(self.1 as usize + 4);
|
||||
} else {
|
||||
buf.reserve(self.1 as usize);
|
||||
}
|
||||
|
||||
// if the packet information is enabled we have to ignore the first 4 bytes
|
||||
if self.0 {
|
||||
let _ = pkt.split_to(4);
|
||||
}
|
||||
|
||||
let proto = infer_proto(pkt.as_ref());
|
||||
Ok(Some(TunPacket(proto, pkt.freeze())))
|
||||
}
|
||||
}
|
||||
|
||||
impl Encoder<TunPacket> for TunPacketCodec {
|
||||
type Error = io::Error;
|
||||
|
||||
fn encode(&mut self, item: TunPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
dst.reserve(item.get_bytes().len() + 4);
|
||||
match item {
|
||||
TunPacket(proto, bytes) if self.0 => {
|
||||
// build the packet information header comprising of 2 u16
|
||||
// fields: flags and protocol.
|
||||
let mut buf = Vec::<u8>::with_capacity(4);
|
||||
|
||||
// flags is always 0
|
||||
buf.write_u16::<NativeEndian>(0).unwrap();
|
||||
// write the protocol as network byte order
|
||||
buf.write_u16::<NetworkEndian>(proto.into_pi_field()?)
|
||||
.unwrap();
|
||||
|
||||
dst.put_slice(&buf);
|
||||
dst.put(bytes);
|
||||
}
|
||||
TunPacket(_, bytes) => dst.put(bytes),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::io;
|
||||
use std::io::{IoSlice, Read, Write};
|
||||
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
use futures_core::ready;
|
||||
use tokio::io::unix::AsyncFd;
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
use tokio_util::codec::Framed;
|
||||
|
||||
use crate::device::Device as D;
|
||||
use crate::platform::{Device, Queue};
|
||||
use crate::r#async::codec::*;
|
||||
|
||||
/// An async TUN device wrapper around a TUN device.
|
||||
pub struct AsyncDevice {
|
||||
inner: AsyncFd<Device>,
|
||||
}
|
||||
|
||||
impl AsyncDevice {
|
||||
/// Create a new `AsyncDevice` wrapping around a `Device`.
|
||||
pub fn new(device: Device) -> io::Result<AsyncDevice> {
|
||||
device.set_nonblock()?;
|
||||
Ok(AsyncDevice {
|
||||
inner: AsyncFd::new(device)?,
|
||||
})
|
||||
}
|
||||
/// Returns a shared reference to the underlying Device object
|
||||
pub fn get_ref(&self) -> &Device {
|
||||
self.inner.get_ref()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying Device object
|
||||
pub fn get_mut(&mut self) -> &mut Device {
|
||||
self.inner.get_mut()
|
||||
}
|
||||
|
||||
/// Consumes this AsyncDevice and return a Framed object (unified Stream and Sink interface)
|
||||
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
|
||||
let pi = self.get_mut().has_packet_information();
|
||||
let codec = TunPacketCodec::new(pi, self.inner.get_ref().mtu().unwrap_or(1504));
|
||||
Framed::new(self, codec)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for AsyncDevice {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf,
|
||||
) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
|
||||
let rbuf = buf.initialize_unfilled();
|
||||
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
|
||||
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for AsyncDevice {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().write(buf)) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().flush()) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_write_vectored(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
bufs: &[IoSlice<'_>],
|
||||
) -> Poll<Result<usize, io::Error>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().write_vectored(bufs)) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// An async TUN device queue wrapper around a TUN device queue.
|
||||
pub struct AsyncQueue {
|
||||
inner: AsyncFd<Queue>,
|
||||
}
|
||||
|
||||
impl AsyncQueue {
|
||||
/// Create a new `AsyncQueue` wrapping around a `Queue`.
|
||||
pub fn new(queue: Queue) -> io::Result<AsyncQueue> {
|
||||
queue.set_nonblock()?;
|
||||
Ok(AsyncQueue {
|
||||
inner: AsyncFd::new(queue)?,
|
||||
})
|
||||
}
|
||||
/// Returns a shared reference to the underlying Queue object
|
||||
pub fn get_ref(&self) -> &Queue {
|
||||
self.inner.get_ref()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the underlying Queue object
|
||||
pub fn get_mut(&mut self) -> &mut Queue {
|
||||
self.inner.get_mut()
|
||||
}
|
||||
|
||||
/// Consumes this AsyncQueue and return a Framed object (unified Stream and Sink interface)
|
||||
pub fn into_framed(mut self) -> Framed<Self, TunPacketCodec> {
|
||||
let pi = self.get_mut().has_packet_information();
|
||||
let codec = TunPacketCodec::new(pi, 1504);
|
||||
Framed::new(self, codec)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for AsyncQueue {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut ReadBuf,
|
||||
) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_read_ready_mut(cx))?;
|
||||
let rbuf = buf.initialize_unfilled();
|
||||
match guard.try_io(|inner| inner.get_mut().read(rbuf)) {
|
||||
Ok(res) => return Poll::Ready(res.map(|n| buf.advance(n))),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for AsyncQueue {
|
||||
fn poll_write(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().write(buf)) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
loop {
|
||||
let mut guard = ready!(self.inner.poll_write_ready_mut(cx))?;
|
||||
match guard.try_io(|inner| inner.get_mut().flush()) {
|
||||
Ok(res) => return Poll::Ready(res),
|
||||
Err(_wb) => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
//! Async specific modules.
|
||||
|
||||
use crate::error;
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::platform::create;
|
||||
|
||||
mod device;
|
||||
pub use self::device::{AsyncDevice, AsyncQueue};
|
||||
|
||||
mod codec;
|
||||
pub use self::codec::{TunPacket, TunPacketCodec};
|
||||
|
||||
/// Create a TUN device with the given name.
|
||||
pub fn create_as_async(configuration: &Configuration) -> Result<AsyncDevice, error::Error> {
|
||||
let device = create(&configuration)?;
|
||||
AsyncDevice::new(device).map_err(|err| err.into())
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::device::Device as D;
|
||||
use crate::error::*;
|
||||
use crate::platform::posix::{self, Fd};
|
||||
|
||||
/// A TUN device for Android.
|
||||
pub struct Device {
|
||||
queue: Queue,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Create a new `Device` for the given `Configuration`.
|
||||
pub fn new(config: &Configuration) -> Result<Self> {
|
||||
let fd = match config.raw_fd {
|
||||
Some(raw_fd) => raw_fd,
|
||||
_ => return Err(Error::InvalidConfig),
|
||||
};
|
||||
let device = {
|
||||
let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?;
|
||||
|
||||
Device {
|
||||
queue: Queue { tun: tun },
|
||||
}
|
||||
};
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
/// Split the interface into a `Reader` and `Writer`.
|
||||
pub fn split(self) -> (posix::Reader, posix::Writer) {
|
||||
let fd = Arc::new(self.queue.tun);
|
||||
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
|
||||
}
|
||||
|
||||
/// Return whether the device has packet information
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.queue.has_packet_information()
|
||||
}
|
||||
|
||||
/// Set non-blocking mode
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.queue.set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Device {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.queue.tun.read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.queue.tun.read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Device {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.queue.tun.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.queue.tun.flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.queue.tun.write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl D for Device {
|
||||
type Queue = Queue;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
return "";
|
||||
}
|
||||
|
||||
fn set_name(&mut self, value: &str) -> Result<()> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn enabled(&mut self, value: bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn address(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destination(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn broadcast(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn netmask(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mtu(&self) -> Result<i32> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_mtu(&mut self, value: i32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
|
||||
if index > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&mut self.queue)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Device {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.queue.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Device {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.queue.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Queue {
|
||||
tun: Fd,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
// on Android this is always the case
|
||||
false
|
||||
}
|
||||
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.tun.set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Queue {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.tun.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Queue {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.tun.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Queue {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.tun.read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.tun.read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Queue {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.tun.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.tun.flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.tun.write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
//! Android specific functionality.
|
||||
|
||||
mod device;
|
||||
pub use self::device::{Device, Queue};
|
||||
|
||||
use crate::configuration::Configuration as C;
|
||||
use crate::error::*;
|
||||
|
||||
/// Android-only interface configuration.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct Configuration {}
|
||||
|
||||
/// Create a TUN device with the given name.
|
||||
pub fn create(configuration: &C) -> Result<Device> {
|
||||
Device::new(&configuration)
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::device::Device as D;
|
||||
use crate::error::*;
|
||||
use crate::platform::posix::{self, Fd};
|
||||
|
||||
/// A TUN device for iOS.
|
||||
pub struct Device {
|
||||
queue: Queue,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Create a new `Device` for the given `Configuration`.
|
||||
pub fn new(config: &Configuration) -> Result<Self> {
|
||||
let fd = match config.raw_fd {
|
||||
Some(raw_fd) => raw_fd,
|
||||
_ => return Err(Error::InvalidConfig),
|
||||
};
|
||||
let mut device = unsafe {
|
||||
let tun = Fd::new(fd).map_err(|_| io::Error::last_os_error())?;
|
||||
|
||||
Device {
|
||||
queue: Queue { tun: tun },
|
||||
}
|
||||
};
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
/// Split the interface into a `Reader` and `Writer`.
|
||||
pub fn split(self) -> (posix::Reader, posix::Writer) {
|
||||
let fd = Arc::new(self.queue.tun);
|
||||
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
|
||||
}
|
||||
|
||||
/// Return whether the device has packet information
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.queue.has_packet_information()
|
||||
}
|
||||
|
||||
/// Set non-blocking mode
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.queue.set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Device {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.queue.tun.read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.queue.tun.read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Device {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.queue.tun.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.queue.tun.flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.queue.tun.write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl D for Device {
|
||||
type Queue = Queue;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
return "";
|
||||
}
|
||||
|
||||
fn set_name(&mut self, value: &str) -> Result<()> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn enabled(&mut self, value: bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn address(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn destination(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn broadcast(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn netmask(&self) -> Result<Ipv4Addr> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mtu(&self) -> Result<i32> {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn set_mtu(&mut self, value: i32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
|
||||
if index > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&mut self.queue)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Device {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.queue.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Device {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.queue.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Queue {
|
||||
tun: Fd,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
// on ios this is always the case
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.tun.set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Queue {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.tun.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Queue {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.tun.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Queue {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.tun.read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.tun.read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Queue {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.tun.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.tun.flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.tun.write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// Version 2, December 2004
|
||||
//
|
||||
// Copyleft (ↄ) meh. <[email protected]> | http://meh.schizofreni.co
|
||||
//
|
||||
// Everyone is permitted to copy and distribute verbatim or modified
|
||||
// copies of this license document, and changing it is allowed as long
|
||||
// as the name is changed.
|
||||
//
|
||||
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
//! iOS specific functionality.
|
||||
|
||||
mod device;
|
||||
pub use self::device::{Device, Queue};
|
||||
|
||||
use crate::configuration::Configuration as C;
|
||||
use crate::error::*;
|
||||
|
||||
/// iOS-only interface configuration.
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
pub struct Configuration {}
|
||||
|
||||
/// Create a TUN device with the given name.
|
||||
pub fn create(configuration: &C) -> Result<Device> {
|
||||
Device::new(&configuration)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Local;
|
||||
|
||||
use crate::DEVICE_LIST;
|
||||
use crate::error::*;
|
||||
use crate::handle::DIRECT_ROUTE_TABLE;
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, Version};
|
||||
use crate::protocol::control_packet::PingPacket;
|
||||
|
||||
pub fn handle_loop(udp: UdpSocket, server_addr: SocketAddr) -> Result<()> {
|
||||
const INTERVAL: u64 = 3000;
|
||||
const MAX_INTERVAL: i64 = 3000 * 3;
|
||||
let mut buf = [0u8; (4 + 8 + 4)];
|
||||
let mut net_packet = NetPacket::new(&mut buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Control);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
|
||||
net_packet.set_ttl(255);
|
||||
loop {
|
||||
let current_time = Local::now().timestamp_millis();
|
||||
{
|
||||
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||
ping.set_time(current_time);
|
||||
let epoch = { DEVICE_LIST.lock().0 };
|
||||
ping.set_epoch(epoch);
|
||||
}
|
||||
let _ = udp.send_to(net_packet.buffer(), server_addr);
|
||||
for x in DIRECT_ROUTE_TABLE.iter() {
|
||||
let virtual_ip = x.key().clone();
|
||||
let route = x.value().clone();
|
||||
drop(x);
|
||||
if current_time - route.recv_time <= MAX_INTERVAL {
|
||||
let _ = udp.send_to(net_packet.buffer(), route.address);
|
||||
} else {
|
||||
DIRECT_ROUTE_TABLE.remove_if(&virtual_ip, |_, route| {
|
||||
current_time - route.recv_time <= MAX_INTERVAL
|
||||
});
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(INTERVAL));
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
use std::net::{ Ipv4Addr, SocketAddr};
|
||||
use std::sync::atomic::AtomicI64;
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Local;
|
||||
use dashmap::DashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use moka::sync::Cache;
|
||||
use parking_lot::{const_mutex, Mutex};
|
||||
|
||||
use crate::proto::message::NatType;
|
||||
|
||||
pub mod heartbeat_handler;
|
||||
pub mod punch_handler;
|
||||
pub mod registration_handler;
|
||||
pub mod tun_handler;
|
||||
pub mod udp_recv_handler;
|
||||
lazy_static! {
|
||||
/// 0. 机器纪元,每一次上线或者下线都会增1,由服务端维护,用于感知网络中机器变化
|
||||
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
||||
/// 1. 网络中的虚拟ip列表
|
||||
pub static ref DEVICE_LIST:Mutex<(u32,Vec<Ipv4Addr>)> = const_mutex((0,Vec::new()));
|
||||
/// 服务器延迟
|
||||
pub static ref SERVER_RT:AtomicI64 = AtomicI64::new(-1);
|
||||
/// id
|
||||
pub static ref ID:AtomicI64 = AtomicI64::new(0);
|
||||
/// 直连路由表
|
||||
pub static ref DIRECT_ROUTE_TABLE:DashMap<Ipv4Addr,Route> = DashMap::new();
|
||||
/// 地址映射
|
||||
pub static ref ADDR_TABLE:Cache<SocketAddr,Ipv4Addr> = Cache::builder()
|
||||
.time_to_idle(Duration::from_secs(60*5)).build();
|
||||
/// 当前设备的nat信息
|
||||
pub static ref NAT_INFO:Mutex<Option<NatInfo>> = const_mutex(None);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NatInfo {
|
||||
public_ips: Vec<u32>,
|
||||
public_port: u16,
|
||||
public_port_range: u16,
|
||||
nat_type: NatType,
|
||||
}
|
||||
|
||||
impl NatInfo {
|
||||
pub fn new(public_ips: Vec<u32>,
|
||||
public_port: u16,
|
||||
public_port_range: u16,
|
||||
nat_type: NatType, ) -> Self {
|
||||
Self {
|
||||
public_ips,
|
||||
public_port,
|
||||
public_port_range,
|
||||
nat_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化nat信息
|
||||
pub fn init_nat_info(public_ip: u32, public_port: u16) {
|
||||
match crate::nat::check::public_ip_list() {
|
||||
Ok((nat_type, ips, port_range)) => {
|
||||
let mut public_ips = Vec::new();
|
||||
public_ips.push(public_ip);
|
||||
for ip in ips {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
if ip != public_ip {
|
||||
public_ips.push(ip);
|
||||
}
|
||||
}
|
||||
let nat_info = NatInfo::new(public_ips,
|
||||
public_port,
|
||||
port_range, nat_type);
|
||||
// println!("nat信息:{:?}",nat_info);
|
||||
let mut nat_info_lock = NAT_INFO.lock();
|
||||
nat_info_lock.replace(nat_info);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("获取nat数据失败,将无法进行udp打洞:{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CurrentDeviceInfo {
|
||||
pub(crate) virtual_ip: Ipv4Addr,
|
||||
pub(crate) virtual_gateway: Ipv4Addr,
|
||||
pub(crate) virtual_netmask: Ipv4Addr,
|
||||
//网络地址
|
||||
pub(crate) virtual_network: Ipv4Addr,
|
||||
//直接广播地址
|
||||
pub(crate) broadcast_address: Ipv4Addr,
|
||||
//链接的服务器地址
|
||||
pub(crate) connect_server: SocketAddr,
|
||||
}
|
||||
|
||||
impl CurrentDeviceInfo {
|
||||
pub fn new(virtual_ip: Ipv4Addr, virtual_gateway: Ipv4Addr, virtual_netmask: Ipv4Addr, connect_server: SocketAddr) -> Self {
|
||||
let broadcast_address = (!u32::from_be_bytes(virtual_netmask.octets()))
|
||||
| u32::from_be_bytes(virtual_gateway.octets());
|
||||
let broadcast_address = Ipv4Addr::from(broadcast_address);
|
||||
let virtual_network = u32::from_be_bytes(virtual_netmask.octets())
|
||||
& u32::from_be_bytes(virtual_gateway.octets());
|
||||
let virtual_network = Ipv4Addr::from(virtual_network);
|
||||
Self {
|
||||
virtual_ip,
|
||||
virtual_netmask,
|
||||
virtual_gateway,
|
||||
virtual_network,
|
||||
broadcast_address,
|
||||
connect_server,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct Route {
|
||||
pub(crate) address: SocketAddr,
|
||||
//用心跳探测延迟,收包时更新
|
||||
pub(crate) delay: i64,
|
||||
//收包时更新,如果太久没有收到消息则剔除
|
||||
pub(crate) recv_time: i64,
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub fn new(address: SocketAddr) -> Self {
|
||||
Self {
|
||||
address,
|
||||
delay: -1,
|
||||
recv_time: Local::now().timestamp_millis(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,354 +0,0 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossbeam::channel::{Receiver, RecvTimeoutError, Sender, SendError, TrySendError};
|
||||
use dashmap::DashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::{CurrentDeviceInfo, DEVICE_LIST, NAT_INFO, NatInfo};
|
||||
use crate::error::*;
|
||||
use crate::handle::DIRECT_ROUTE_TABLE;
|
||||
use crate::proto::message::{NatType, Punch, Step};
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, turn_packet, Version};
|
||||
use crate::protocol::control_packet::PunchRequestPacket;
|
||||
use crate::protocol::turn_packet::TurnPacket;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref STEP_MAP:DashMap<Ipv4Addr,Step> = DashMap::new();
|
||||
}
|
||||
/// 每一种类型一个通道,减少相互干扰
|
||||
pub fn bounded() -> (PunchSender, ConeReceiver, ReqSymmetricReceiver, ResSymmetricReceiver) {
|
||||
let (cone_sender, cone_receiver) = crossbeam::channel::bounded(3);
|
||||
let (req_symmetric_sender, req_symmetric_receiver) = crossbeam::channel::bounded(1);
|
||||
let (res_symmetric_sender, res_symmetric_receiver) = crossbeam::channel::bounded(1);
|
||||
(PunchSender::new(cone_sender, req_symmetric_sender, res_symmetric_sender),
|
||||
ConeReceiver(cone_receiver), ReqSymmetricReceiver(req_symmetric_receiver),
|
||||
ResSymmetricReceiver(res_symmetric_receiver))
|
||||
}
|
||||
|
||||
pub struct ConeReceiver(Receiver<Punch>);
|
||||
|
||||
pub struct ReqSymmetricReceiver(Receiver<Punch>);
|
||||
|
||||
pub struct ResSymmetricReceiver(Receiver<Punch>);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PunchSender {
|
||||
cone_sender: Sender<Punch>,
|
||||
req_symmetric_sender: Sender<Punch>,
|
||||
res_symmetric_sender: Sender<Punch>,
|
||||
}
|
||||
|
||||
impl PunchSender {
|
||||
pub fn new(cone_sender: Sender<Punch>,
|
||||
req_symmetric_sender: Sender<Punch>,
|
||||
res_symmetric_sender: Sender<Punch>, ) -> Self {
|
||||
Self {
|
||||
cone_sender,
|
||||
req_symmetric_sender,
|
||||
res_symmetric_sender,
|
||||
}
|
||||
}
|
||||
pub fn send(&self, punch: Punch) -> std::result::Result<(), SendError<Punch>> {
|
||||
match punch.nat_type.enum_value_or_default() {
|
||||
NatType::Symmetric => {
|
||||
if punch.reply {
|
||||
// 为true表示回应,也就是主动发起的打洞操作
|
||||
self.res_symmetric_sender.send(punch)
|
||||
} else {
|
||||
self.req_symmetric_sender.send(punch)
|
||||
}
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.cone_sender.send(punch)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn try_send(&self, punch: Punch) -> std::result::Result<(), TrySendError<Punch>> {
|
||||
match punch.nat_type.enum_value_or_default() {
|
||||
NatType::Symmetric => {
|
||||
if punch.reply {
|
||||
// 为true表示回应,也就是主动发起的打洞操作
|
||||
self.res_symmetric_sender.try_send(punch)
|
||||
} else {
|
||||
self.req_symmetric_sender.try_send(punch)
|
||||
}
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.cone_sender.try_send(punch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(udp: &UdpSocket, punch_list: Vec<Punch>, buf: &[u8]) -> Result<()> {
|
||||
let mut counter = 0u64;
|
||||
for punch in punch_list {
|
||||
let dest = Ipv4Addr::from(punch.virtual_ip);
|
||||
if DIRECT_ROUTE_TABLE.contains_key(&dest) {
|
||||
continue;
|
||||
}
|
||||
// println!("punch {:?}", punch);
|
||||
match punch.nat_type.enum_value_or_default() {
|
||||
NatType::Symmetric => {
|
||||
match punch.step.enum_value_or_default() {
|
||||
Step::Step1 | Step::Step2 | Step::Step3 => {
|
||||
//预测范围发送
|
||||
for pub_ip in punch.public_ip_list {
|
||||
let pub_ip = Ipv4Addr::from(pub_ip);
|
||||
for range in 0..punch.public_port_range + 1 {
|
||||
let right_port = ((punch.public_port + range) & 0xFFFF) as u16;
|
||||
let left_port = ((0xFFFF + punch.public_port - range) & 0xFFFF) as u16;
|
||||
if right_port != 0 {
|
||||
// println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)));
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
if left_port != 0 && range != 0 {
|
||||
// println!("{:?}", SocketAddr::V4(SocketAddrV4::new(pub_ip, right_port)));
|
||||
if left_port == right_port {
|
||||
break;
|
||||
}
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(pub_ip, left_port)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Step::Step4 => {
|
||||
//全范围发送
|
||||
for pub_ip in punch.public_ip_list {
|
||||
let pub_ip = Ipv4Addr::from(pub_ip);
|
||||
for port in 1..0xFFFF {
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(pub_ip, port)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NatType::Cone => {
|
||||
for pub_ip in punch.public_ip_list {
|
||||
udp.send_to(
|
||||
buf,
|
||||
SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::from(pub_ip),
|
||||
punch.public_port as u16,
|
||||
)),
|
||||
)?;
|
||||
select_sleep(&mut counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 给对称nat发送打洞数据包
|
||||
pub fn req_symmetric_handle_loop(
|
||||
receiver: ReqSymmetricReceiver,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let receiver = receiver.0;
|
||||
handle_loop(receiver, udp, cur_info)
|
||||
}
|
||||
|
||||
/// 给对称nat发送打洞数据包,处理主动发起的打洞操作
|
||||
pub fn res_symmetric_handle_loop(
|
||||
receiver: ResSymmetricReceiver,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let receiver = receiver.0;
|
||||
let mut buf = [0u8; 12];
|
||||
let mut packet = NetPacket::new(&mut buf)?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_ttl(255);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
{
|
||||
let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?;
|
||||
punch_packet.set_source(cur_info.virtual_ip);
|
||||
}
|
||||
loop {
|
||||
match receiver.recv_timeout(Duration::from_secs(30)) {
|
||||
Ok(punch) => {
|
||||
let mut list = Vec::new();
|
||||
list.push(punch);
|
||||
loop {
|
||||
match receiver.try_recv() {
|
||||
Ok(punch) => {
|
||||
list.push(punch);
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for punch in &list {
|
||||
let dest = Ipv4Addr::from(punch.virtual_ip);
|
||||
match punch.step.enum_value_or_default() {
|
||||
Step::Step1 => {
|
||||
STEP_MAP.insert(dest, Step::Step2);
|
||||
}
|
||||
Step::Step2 => {
|
||||
STEP_MAP.insert(dest, Step::Step3);
|
||||
}
|
||||
Step::Step3 => {
|
||||
STEP_MAP.insert(dest, Step::Step4);
|
||||
}
|
||||
Step::Step4 => {
|
||||
STEP_MAP.insert(dest, Step::Step1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Err(e) = handle(&udp, list, packet.buffer()) {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
}
|
||||
Err(RecvTimeoutError::Timeout) => {
|
||||
punch_request_handle(&udp, &cur_info)?;
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(Error::Stop("打洞线程通道关闭".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 给锥形nat发送打洞数据包
|
||||
pub fn cone_handle_loop(
|
||||
receiver: ConeReceiver,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let receiver = receiver.0;
|
||||
handle_loop(receiver, udp, cur_info)
|
||||
}
|
||||
|
||||
pub fn handle_loop(
|
||||
receiver: Receiver<Punch>,
|
||||
udp: UdpSocket,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut buf = [0u8; 12];
|
||||
let mut packet = NetPacket::new(&mut buf)?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_ttl(255);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
{
|
||||
let mut punch_packet = PunchRequestPacket::new(packet.payload_mut())?;
|
||||
punch_packet.set_source(cur_info.virtual_ip);
|
||||
}
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
Ok(punch) => {
|
||||
let mut list = Vec::new();
|
||||
list.push(punch);
|
||||
loop {
|
||||
match receiver.try_recv() {
|
||||
Ok(punch) => {
|
||||
list.push(punch);
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Err(e) = handle(&udp, list, packet.buffer()) {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(Error::Stop("打洞线程通道关闭".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn select_sleep(counter: &mut u64) {
|
||||
*counter += 1;
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
// if *counter > 1 {
|
||||
// if cone_nat {
|
||||
// thread::sleep(Duration::from_millis(2));
|
||||
// } else {
|
||||
// if (*counter) & 10 == 10 {
|
||||
// thread::sleep(Duration::from_millis(1));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
fn punch_request_handle(udp: &UdpSocket, cur_info: &CurrentDeviceInfo) -> Result<()> {
|
||||
let nat_info_lock = NAT_INFO.lock();
|
||||
let nat_info = nat_info_lock.clone();
|
||||
drop(nat_info_lock);
|
||||
if let Some(nat_info) = nat_info {
|
||||
if let Err(e) = send_punch(&udp,
|
||||
&cur_info,
|
||||
nat_info) {
|
||||
println!("发送打洞数据失败 :{:?}", e);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Stop("未初始化nat信息".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn send_punch(udp: &UdpSocket, cur_info: &CurrentDeviceInfo, nat_info: NatInfo) -> Result<()> {
|
||||
let lock = DEVICE_LIST.lock();
|
||||
let list = lock.1.clone();
|
||||
drop(lock);
|
||||
for ip in list {
|
||||
//只向ip比自己大的发起打洞,避免双方同时发起打洞浪费流量
|
||||
if ip > cur_info.virtual_ip && !DIRECT_ROUTE_TABLE.contains_key(&ip) {
|
||||
let step = if let Some(step) = STEP_MAP.get(&ip) {
|
||||
*step
|
||||
} else {
|
||||
Step::Step1
|
||||
};
|
||||
let bytes = punch_packet(cur_info.virtual_ip,
|
||||
nat_info.clone(), ip, step)?;
|
||||
udp.send_to(&bytes, cur_info.connect_server)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn punch_packet(virtual_ip: Ipv4Addr, nat_info: NatInfo, dest: Ipv4Addr, step: Step) -> Result<Vec<u8>> {
|
||||
let mut punch_reply = Punch::new();
|
||||
punch_reply.reply = false;
|
||||
punch_reply.virtual_ip = u32::from_be_bytes(virtual_ip.octets());
|
||||
punch_reply.step = protobuf::EnumOrUnknown::new(step);
|
||||
punch_reply.public_ip_list = nat_info.public_ips;
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(nat_info.nat_type);
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into());
|
||||
net_packet.set_ttl(255);
|
||||
let mut turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
turn_packet.set_source(virtual_ip);
|
||||
turn_packet.set_destination(dest);
|
||||
turn_packet.set_payload(&bytes);
|
||||
Ok(net_packet.into_buffer())
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use chrono::Local;
|
||||
use parking_lot::RwLock;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
||||
use crate::protocol::{error_packet, NetPacket, Protocol, service_packet, Version};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref REQUEST:RwLock<Option<(String,String)>> = parking_lot::const_rwlock(None);
|
||||
static ref REGISTRATION_TIME:AtomicI64=AtomicI64::new(0);
|
||||
}
|
||||
|
||||
///向中继服务器注册,token标识一个虚拟网关,mac_address防止多次注册时得到的ip不一致
|
||||
pub fn registration(
|
||||
udp: &UdpSocket,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
mac_address: String,
|
||||
) -> Result<RegistrationResponse> {
|
||||
// todo 和服务器通信加密
|
||||
let request_packet = registration_request_packet(token.clone(), mac_address.clone())?;
|
||||
let buf = request_packet.buffer();
|
||||
let mut counter = 0;
|
||||
let mut recv_buf = [0u8; 10240];
|
||||
udp.set_read_timeout(Some(Duration::from_millis(500)))?;
|
||||
loop {
|
||||
counter += 1;
|
||||
if counter & 10 == 10 {
|
||||
return Err(Error::Stop("注册请求超时".to_string()));
|
||||
}
|
||||
udp.send_to(buf, server_address)?;
|
||||
let (len, addr) = match udp.recv_from(&mut recv_buf) {
|
||||
Ok(ok) => ok,
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::WouldBlock || e.kind() == io::ErrorKind::TimedOut {
|
||||
continue;
|
||||
}
|
||||
return Err(Error::Io(e));
|
||||
}
|
||||
};
|
||||
if server_address != addr {
|
||||
continue;
|
||||
}
|
||||
let net_packet = NetPacket::new(&recv_buf[..len])?;
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response =
|
||||
RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
let _ = REQUEST.write().replace((token, mac_address));
|
||||
udp.set_read_timeout(None)?;
|
||||
return Ok(response);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Protocol::Error => {
|
||||
match error_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
error_packet::Protocol::TokenError => {
|
||||
return Err(Error::Stop("token错误".to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn registration_request_packet(token: String, mac_address: String) -> Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = RegistrationRequest::new();
|
||||
request.token = token;
|
||||
request.mac_address = mac_address;
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let buf = vec![0u8; 4 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into());
|
||||
net_packet.set_ttl(255);
|
||||
net_packet.set_payload(&bytes);
|
||||
Ok(net_packet)
|
||||
}
|
||||
|
||||
pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result<()> {
|
||||
let last = REGISTRATION_TIME.load(Ordering::Relaxed);
|
||||
let new = Local::now().timestamp_millis();
|
||||
if new - last < 2000
|
||||
|| REGISTRATION_TIME
|
||||
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
//短时间不重复注册
|
||||
return Ok(());
|
||||
}
|
||||
let lock = REQUEST.read();
|
||||
let option = lock.clone();
|
||||
drop(lock);
|
||||
if let Some((token, mac_address)) = option {
|
||||
let request_packet = registration_request_packet(token, mac_address)?;
|
||||
udp.send_to(request_packet.buffer(), server_address)?;
|
||||
REGISTRATION_TIME.store(Local::now().timestamp_millis(), Ordering::Relaxed);
|
||||
return Ok(());
|
||||
}
|
||||
return Err(Error::Stop("注册信息不存在".to_string()));
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/// 接收tun数据,并且转发到udp上
|
||||
use std::net::{IpAddr, Ipv4Addr, UdpSocket};
|
||||
|
||||
use chrono::Local;
|
||||
use packet::icmp::icmp::IcmpPacket;
|
||||
use packet::icmp::Kind;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::handle::{CurrentDeviceInfo, DIRECT_ROUTE_TABLE};
|
||||
use crate::protocol::{NetPacket, Protocol, Version};
|
||||
use crate::protocol::turn_packet::TurnPacket;
|
||||
use crate::tun_device::TunReader;
|
||||
|
||||
/// 是否在一个网段
|
||||
fn check_dest(dest: Ipv4Addr, cur_info: &CurrentDeviceInfo) -> bool {
|
||||
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(cur_info.virtual_netmask.octets())
|
||||
== u32::from_be_bytes(cur_info.virtual_network.octets())
|
||||
}
|
||||
|
||||
fn icmp(udp: &UdpSocket, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
|
||||
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
let src = ipv4_packet.source_ip();
|
||||
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||
ipv4_packet.set_destination_ip(src);
|
||||
ipv4_packet.update_checksum();
|
||||
let mut addr = udp.local_addr()?;
|
||||
addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
udp.send_to(ipv4_packet.buffer, addr)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn handle(
|
||||
udp: &UdpSocket,
|
||||
data: &mut [u8],
|
||||
cur_info: &CurrentDeviceInfo,
|
||||
net_packet: &mut NetPacket<Vec<u8>>,
|
||||
) -> Result<()> {
|
||||
let data_len = data.len();
|
||||
let ipv4_packet = match IpV4Packet::new(data) {
|
||||
Ok(ipv4_packet) => ipv4_packet,
|
||||
Err(packet::error::Error::Unimplemented) => {
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => Err(e)?,
|
||||
};
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
let dest_ip = ipv4_packet.destination_ip();
|
||||
// if dest_ip == cur_info.broadcast_address {
|
||||
// // 启动服务后会收到对137端口的广播
|
||||
// // 137端口是在局域网中提供计算机的名字或IP地址查询服务
|
||||
// return Ok(());
|
||||
// }
|
||||
if src_ip != cur_info.virtual_ip || !check_dest(dest_ip, &cur_info) {
|
||||
return Ok(());
|
||||
}
|
||||
if src_ip == dest_ip {
|
||||
return icmp(&udp, ipv4_packet);
|
||||
}
|
||||
let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
ipv4_turn_packet.set_source(src_ip);
|
||||
ipv4_turn_packet.set_destination(dest_ip);
|
||||
ipv4_turn_packet.set_payload(ipv4_packet.buffer);
|
||||
//优先发到直连到地址
|
||||
if let Some(route) = DIRECT_ROUTE_TABLE.get(&dest_ip) {
|
||||
let current_time = Local::now().timestamp_millis();
|
||||
if current_time - route.recv_time < 3_000 {
|
||||
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], route.address)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], cur_info.connect_server)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn handle_loop(
|
||||
udp: UdpSocket,
|
||||
tun_reader: TunReader,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||
net_packet.set_ttl(255);
|
||||
loop {
|
||||
let mut data = tun_reader.next()?;
|
||||
match handle(&udp, data.bytes_mut(), &cur_info, &mut net_packet) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix))]
|
||||
pub fn handle_loop(
|
||||
udp: UdpSocket,
|
||||
mut tun_reader: TunReader,
|
||||
cur_info: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||
net_packet.set_transport_protocol(0);
|
||||
net_packet.set_ttl(255);
|
||||
let mut buf = [0u8; 1500];
|
||||
loop {
|
||||
let data = tun_reader.read(&mut buf)?;
|
||||
match handle(&udp, data, &cur_info, &mut net_packet) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use chrono::Local;
|
||||
use crossbeam::channel::{Receiver, Sender, TrySendError};
|
||||
use packet::icmp::{icmp, Kind};
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::CurrentDeviceInfo;
|
||||
use crate::error::*;
|
||||
use crate::handle::{ADDR_TABLE, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, Route, SERVER_RT};
|
||||
use crate::handle::punch_handler::PunchSender;
|
||||
use crate::handle::registration_handler::fast_registration;
|
||||
use crate::proto::message::{DeviceList, Punch, RegistrationResponse};
|
||||
use crate::protocol::{control_packet, NetPacket, Protocol, service_packet, turn_packet, Version};
|
||||
use crate::protocol::control_packet::{ControlPacket, PunchResponsePacket};
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::protocol::turn_packet::TurnPacket;
|
||||
use crate::tun_device::TunWriter;
|
||||
|
||||
pub fn recv_loop(
|
||||
udp: UdpSocket,
|
||||
server_addr: SocketAddr,
|
||||
other_sender: Sender<(SocketAddr, Vec<u8>)>,
|
||||
mut tun_writer: TunWriter,
|
||||
current_device: CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut buf = [0u8; 65536];
|
||||
let mut local_addr = udp.local_addr()?;
|
||||
local_addr.set_ip(std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
loop {
|
||||
match udp.recv_from(&mut buf) {
|
||||
Ok((len, addr)) => {
|
||||
if addr == local_addr {
|
||||
//本地的包直接再发到网卡,这个主要用于处理当前虚拟ip的icmp ping
|
||||
if let Ok(ip) = IpV4Packet::new(&buf[..len]) {
|
||||
if ip.destination_ip() == current_device.virtual_ip {
|
||||
let _ = tun_writer.write(&buf[..len]);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
match recv_handle(
|
||||
&udp,
|
||||
addr,
|
||||
&mut buf[..len],
|
||||
&server_addr,
|
||||
&other_sender,
|
||||
&mut tun_writer,
|
||||
¤t_device,
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(Error::Stop(str)) => {
|
||||
return Err(Error::Stop(str));
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn recv_handle(
|
||||
udp: &UdpSocket,
|
||||
recv_addr: SocketAddr,
|
||||
buf: &mut [u8],
|
||||
_server_addr: &SocketAddr,
|
||||
other_sender: &Sender<(SocketAddr, Vec<u8>)>,
|
||||
tun_writer: &mut TunWriter,
|
||||
current_device: &CurrentDeviceInfo,
|
||||
) -> Result<()> {
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
match net_packet.protocol() {
|
||||
Protocol::Ipv4Turn => {
|
||||
let mut ipv4_turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
let source = ipv4_turn_packet.source();
|
||||
let destination = ipv4_turn_packet.destination();
|
||||
let mut ipv4 = IpV4Packet::new(ipv4_turn_packet.payload_mut())?;
|
||||
if ipv4.source_ip() == source
|
||||
&& ipv4.destination_ip() == destination
|
||||
&& current_device.virtual_ip == ipv4.destination_ip()
|
||||
{
|
||||
if ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
|
||||
if icmp_packet.kind() == Kind::EchoRequest {
|
||||
//开启ping
|
||||
icmp_packet.set_kind(Kind::EchoReply);
|
||||
icmp_packet.update_checksum();
|
||||
ipv4.set_source_ip(destination);
|
||||
ipv4.set_destination_ip(source);
|
||||
ipv4.update_checksum();
|
||||
ipv4_turn_packet.set_source(destination);
|
||||
ipv4_turn_packet.set_destination(source);
|
||||
udp.send_to(net_packet.buffer(), recv_addr)?;
|
||||
} else {
|
||||
tun_writer.write(ipv4_turn_packet.payload())?;
|
||||
}
|
||||
} else {
|
||||
tun_writer.write(ipv4_turn_packet.payload())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::UnKnow(_) => {}
|
||||
_ => {
|
||||
//发送到子线程处理
|
||||
let v = net_packet.buffer().to_vec();
|
||||
match other_sender.try_send((recv_addr, v)) {
|
||||
Ok(_) => {}
|
||||
Err(TrySendError::Disconnected(_)) => {
|
||||
return Err(Error::Stop("处理线程停止".to_string()));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("子线程处理 :{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn other_loop(
|
||||
udp: UdpSocket,
|
||||
receiver: Receiver<(SocketAddr, Vec<u8>)>,
|
||||
current_device: CurrentDeviceInfo,
|
||||
sender: PunchSender,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
let (peer_addr, buf) = receiver.recv()?;
|
||||
match other_handle(&udp, buf, peer_addr, ¤t_device, &sender) {
|
||||
Ok(_) => {}
|
||||
Err(Error::Stop(str)) => {
|
||||
return Err(Error::Stop(str));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn other_handle(
|
||||
udp: &UdpSocket,
|
||||
buf: Vec<u8>,
|
||||
peer_addr: SocketAddr,
|
||||
current_device: &CurrentDeviceInfo,
|
||||
sender: &PunchSender,
|
||||
) -> Result<()> {
|
||||
let server_addr = current_device.connect_server;
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
if peer_addr != current_device.connect_server {
|
||||
return Ok(());
|
||||
}
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationRequest => {}
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
crate::handle::init_nat_info(response.public_ip, response.public_port as u16);
|
||||
//todo 重连之后ip可能会发生改变(目前2分钟内未重连则会释放ip),需要更新本地ip(或者保证重连ip不变)
|
||||
}
|
||||
service_packet::Protocol::UpdateDeviceList => {
|
||||
let device_list = DeviceList::parse_from_bytes(net_packet.payload())?;
|
||||
let ip_list: Vec<Ipv4Addr> = device_list
|
||||
.virtual_ip_list
|
||||
.iter()
|
||||
.map(|ip| Ipv4Addr::from(*ip))
|
||||
.collect();
|
||||
let mut dev = DEVICE_LIST.lock();
|
||||
if dev.0 < device_list.epoch || device_list.epoch - dev.0 > u32::MAX >> 2 {
|
||||
dev.0 = device_list.epoch;
|
||||
dev.1 = ip_list;
|
||||
}
|
||||
}
|
||||
service_packet::Protocol::UnKnow(_) => {}
|
||||
}
|
||||
}
|
||||
Protocol::Error => {
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
InErrorPacket::TokenError => {
|
||||
if server_addr == peer_addr {
|
||||
//停止整个应用
|
||||
return Err(Error::Stop("token无效".to_string()));
|
||||
}
|
||||
}
|
||||
InErrorPacket::Disconnect => {
|
||||
if server_addr == peer_addr {
|
||||
fast_registration(&udp, server_addr)?;
|
||||
}
|
||||
}
|
||||
InErrorPacket::OtherError(e) => {
|
||||
println!("{:?}", e.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::Control => {
|
||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
ControlPacket::PingPacket(ping) => {
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||
udp.send_to(&net_packet.buffer()[..12], peer_addr)?;
|
||||
}
|
||||
ControlPacket::PongPacket(pong_packet) => {
|
||||
let current_time = Local::now().timestamp_millis();
|
||||
let rt = current_time - pong_packet.time();
|
||||
if rt >= 0 {
|
||||
if peer_addr == server_addr {
|
||||
SERVER_RT.store(rt, Ordering::Relaxed)
|
||||
} else {
|
||||
//其他设备
|
||||
if let Some(virtual_ip) = ADDR_TABLE.get(&peer_addr) {
|
||||
if let Some(mut info) = DIRECT_ROUTE_TABLE.get_mut(&virtual_ip) {
|
||||
info.delay = rt;
|
||||
info.recv_time = current_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlPacket::PunchRequest(punch_request) => {
|
||||
// println!("打洞请求:{:?}", punch_request);
|
||||
let src = punch_request.source();
|
||||
drop(punch_request);
|
||||
//回应
|
||||
let mut punch_response = PunchResponsePacket::new(net_packet.payload_mut())?;
|
||||
punch_response.set_source(current_device.virtual_ip);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into());
|
||||
udp.send_to(net_packet.buffer(), peer_addr)?;
|
||||
let route = Route::new(peer_addr);
|
||||
DIRECT_ROUTE_TABLE.insert(src, route);
|
||||
ADDR_TABLE.insert(peer_addr, src);
|
||||
}
|
||||
ControlPacket::PunchResponse(punch_response) => {
|
||||
// println!("打洞响应:{:?}", punch_response);
|
||||
let route = Route::new(peer_addr);
|
||||
DIRECT_ROUTE_TABLE.insert(punch_response.source(), route);
|
||||
ADDR_TABLE.insert(peer_addr, punch_response.source());
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::Ipv4Turn => {}
|
||||
Protocol::OtherTurn => {
|
||||
let turn_packet = TurnPacket::new(net_packet.payload())?;
|
||||
// println!("{:?}",turn_packet);
|
||||
let src = turn_packet.source();
|
||||
let dest = turn_packet.destination();
|
||||
if dest == current_device.virtual_ip {
|
||||
match turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
turn_packet::Protocol::Punch => {
|
||||
let punch = Punch::parse_from_bytes(turn_packet.payload())?;
|
||||
if punch.virtual_ip.to_be_bytes() == src.octets() {
|
||||
if !punch.reply {
|
||||
let mut punch_reply = Punch::new();
|
||||
punch_reply.reply = true;
|
||||
punch_reply.virtual_ip = u32::from_be_bytes(current_device.virtual_ip.octets());
|
||||
punch_reply.step = punch.step;
|
||||
if let Err(_) = sender.try_send(punch) {
|
||||
return Ok(());
|
||||
}
|
||||
let nat_info = NAT_INFO.lock();
|
||||
if let Some(info) = nat_info.as_ref() {
|
||||
punch_reply.public_ip_list = info.public_ips.clone();
|
||||
punch_reply.public_port = info.public_port as u32;
|
||||
punch_reply.public_port_range = info.public_port_range as u32;
|
||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(info.nat_type);
|
||||
drop(nat_info);
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + bytes.len()])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(turn_packet::Protocol::Punch.into());
|
||||
net_packet.set_ttl(255);
|
||||
let mut turn_packet = TurnPacket::new(net_packet.payload_mut())?;
|
||||
turn_packet.set_source(current_device.virtual_ip);
|
||||
turn_packet.set_destination(src);
|
||||
turn_packet.set_payload(&bytes);
|
||||
udp.send_to(net_packet.buffer(), peer_addr)?;
|
||||
}
|
||||
} else {
|
||||
let _ = sender.try_send(punch);
|
||||
}
|
||||
}
|
||||
}
|
||||
turn_packet::Protocol::UnKnow(_) => {}
|
||||
}
|
||||
} else {
|
||||
panic!("ip")
|
||||
}
|
||||
}
|
||||
Protocol::UnKnow(p) => {
|
||||
println!("未知协议:{}", p)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
-248
@@ -1,248 +0,0 @@
|
||||
use std::{io, thread};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use clap::Parser;
|
||||
use console::style;
|
||||
|
||||
use crate::handle::{CurrentDeviceInfo, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, NatInfo, SERVER_RT};
|
||||
use crate::handle::registration_handler::registration;
|
||||
use crate::tun_device::create_tun;
|
||||
|
||||
pub mod tun_device;
|
||||
pub mod nat;
|
||||
pub mod error;
|
||||
pub mod handle;
|
||||
pub mod proto;
|
||||
pub mod protocol;
|
||||
#[cfg(windows)]
|
||||
pub mod admin_check;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author = "Lu Beilin", version, about = "一个虚拟网络工具,启动后会获取一个ip,相同token下的设备之间可以用ip直接通信")]
|
||||
struct Args {
|
||||
/// 32位字符
|
||||
/// 相同token的设备之间才能通信。
|
||||
/// 建议使用uuid保证唯一性。
|
||||
/// 32-bit characters.
|
||||
/// Only devices with the same token can communicate with each other.
|
||||
/// It is recommended to use uuid to ensure uniqueness
|
||||
#[arg(short, long)]
|
||||
token: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
#[cfg(windows)]
|
||||
if !admin_check::is_app_elevated() {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
println!("{}", style("正在启动管理员权限执行...").red());
|
||||
if let Some(absolute_path) = std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|p| p.to_str().map(|p| p.to_string()))
|
||||
{
|
||||
let _ = runas::Command::new(&absolute_path).args(&args[1..]).status()
|
||||
.expect("failed to execute");
|
||||
} else {
|
||||
panic!("failed to execute")
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(any(unix))]
|
||||
if sudo::RunningAs::Root != sudo::check() {
|
||||
println!("{}", style("需要使用root权限执行...").red());
|
||||
sudo::escalate_if_needed().unwrap();
|
||||
}
|
||||
|
||||
println!("{}", style("启动服务...").green());
|
||||
|
||||
let token = args.token;
|
||||
// let d = Local::now().timestamp().to_string();
|
||||
let mac_address = mac_address::get_mac_address().unwrap().unwrap().to_string();
|
||||
let server_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(43, 139, 56, 10)), 29876);
|
||||
// let server_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127,0,0,1)), 29876);
|
||||
let mut port = 101 as u16;
|
||||
let udp = loop {
|
||||
match UdpSocket::bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(0), port))) {
|
||||
Ok(udp) => {
|
||||
break udp;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::AddrInUse {
|
||||
port += 1;
|
||||
} else {
|
||||
println!("创建udp失败:{:?}", e);
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
//注册
|
||||
let response = registration(&udp, server_address, token, mac_address).unwrap();
|
||||
{
|
||||
let ip_list = response
|
||||
.virtual_ip_list
|
||||
.iter()
|
||||
.map(|ip| Ipv4Addr::from(*ip))
|
||||
.collect();
|
||||
let mut dev = DEVICE_LIST.lock();
|
||||
dev.0 = response.epoch;
|
||||
dev.1 = ip_list;
|
||||
}
|
||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||
println!("virtual_gateway:{:?}", virtual_gateway);
|
||||
println!("virtual_netmask:{:?}", virtual_netmask);
|
||||
println!("当前设备ip(virtual_ip):{}", style(virtual_ip).green());
|
||||
//心跳线程
|
||||
{
|
||||
let udp = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
if let Err(e) = handle::heartbeat_handler::handle_loop(udp, server_address) {
|
||||
println!("心跳线程停止:{:?}", e);
|
||||
}
|
||||
std::process::exit(1);
|
||||
});
|
||||
}
|
||||
//初始化nat数据
|
||||
handle::init_nat_info(response.public_ip, response.public_port as u16);
|
||||
// tun服务
|
||||
let (tun_writer, tun_reader) =
|
||||
create_tun(virtual_ip, virtual_netmask, virtual_gateway).unwrap();
|
||||
// 打洞数据通道
|
||||
let (punch_sender, cone_receiver, req_symmetric_receiver, res_symmetric_receiver) = handle::punch_handler::bounded();
|
||||
//udp数据处理
|
||||
{
|
||||
// 低优先级的udp数据通道
|
||||
let (sender, receiver) = crossbeam::channel::bounded(100);
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::udp_recv_handler::recv_loop(
|
||||
udp1,
|
||||
server_address,
|
||||
sender,
|
||||
tun_writer,
|
||||
current_device,
|
||||
) {
|
||||
println!("udp数据处理线程停止:{:?}", e);
|
||||
}
|
||||
std::process::exit(1);
|
||||
});
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::udp_recv_handler::other_loop(udp1, receiver, current_device, punch_sender) {
|
||||
println!("udp数据处理线程停止:{:?}", e);
|
||||
}
|
||||
std::process::exit(1);
|
||||
});
|
||||
}
|
||||
//打洞处理
|
||||
{
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::punch_handler::cone_handle_loop(cone_receiver, udp1, current_device) {
|
||||
println!("打洞响应线程停止:{:?}", e);
|
||||
}
|
||||
});
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::punch_handler::req_symmetric_handle_loop(req_symmetric_receiver, udp1, current_device) {
|
||||
println!("打洞触发线程停止:{:?}", e);
|
||||
}
|
||||
});
|
||||
let udp1 = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::punch_handler::res_symmetric_handle_loop(res_symmetric_receiver, udp1, current_device) {
|
||||
println!("打洞触发线程停止:{:?}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
//tun数据处理
|
||||
{
|
||||
let udp = udp.try_clone().unwrap();
|
||||
let _ = thread::spawn(move || {
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
if let Err(e) = handle::tun_handler::handle_loop(udp, tun_reader, current_device) {
|
||||
println!("tun数据处理线程停止:{:?}", e);
|
||||
}
|
||||
std::process::exit(1);
|
||||
});
|
||||
}
|
||||
use console::Term;
|
||||
let term = Term::stdout();
|
||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||
loop {
|
||||
println!("{}", style("Please enter the command (Usage: list,status,exit,help):").color256(102));
|
||||
match term.read_line() {
|
||||
Ok(cmd) => {
|
||||
command(cmd.trim(), ¤t_device);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("read_line:{:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn command(cmd: &str, current_device: &CurrentDeviceInfo) {
|
||||
match cmd {
|
||||
"list" => {
|
||||
let server_delay = SERVER_RT.load(Ordering::Relaxed);
|
||||
let device_list_lock = DEVICE_LIST.lock();
|
||||
let (_epoch, device_list) = device_list_lock.clone();
|
||||
drop(device_list_lock);
|
||||
if device_list.is_empty() {
|
||||
println!("No other devices found");
|
||||
return;
|
||||
}
|
||||
for ip in device_list {
|
||||
if let Some(route_ref) = DIRECT_ROUTE_TABLE.get(&ip) {
|
||||
let str = if route_ref.value().delay >= 0 {
|
||||
format!("{}(p2p delay:{}ms)", ip, route_ref.value().delay)
|
||||
} else {
|
||||
format!("{}(p2p)", ip)
|
||||
};
|
||||
drop(route_ref);
|
||||
println!("{}", style(str).green());
|
||||
} else {
|
||||
let str = if server_delay >= 0 {
|
||||
format!("{}(relay delay:{}ms)", ip, server_delay * 2)
|
||||
} else {
|
||||
format!("{}(relay)", ip)
|
||||
};
|
||||
println!("{}", style(str).blue());
|
||||
}
|
||||
}
|
||||
}
|
||||
"status" => {
|
||||
let server_delay = SERVER_RT.load(Ordering::Relaxed);
|
||||
println!("Virtual ip:{}", style(current_device.virtual_ip).green());
|
||||
println!("Virtual gateway:{}", style(current_device.virtual_gateway).green());
|
||||
println!("Relay server :{}", style(current_device.connect_server).green());
|
||||
if server_delay >= 0 {
|
||||
println!("Delay of relay server :{}", style(server_delay).green());
|
||||
}
|
||||
}
|
||||
"help" | "h" => {
|
||||
println!("Options: ");
|
||||
println!("{} , Query the virtual IP of other devices", style("list").green());
|
||||
println!("{} , View current device status", style("status").green());
|
||||
println!("{} , Exit the program", style("exit").green());
|
||||
}
|
||||
"exit" => {
|
||||
std::process::exit(1);
|
||||
}
|
||||
_ => {
|
||||
println!("command {} not fount. ", style(cmd).red());
|
||||
println!("Try to enter: '{}'", style("help").green());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
use std::{io, thread};
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::proto::message::NatType;
|
||||
|
||||
// #[derive(Debug, Copy, Clone, PartialEq)]
|
||||
// pub enum NatType {
|
||||
// Symmetric,
|
||||
// Cone,
|
||||
// }
|
||||
//
|
||||
// impl Into<u8> for NatType {
|
||||
// fn into(self) -> u8 {
|
||||
// match self {
|
||||
// NatType::Symmetric => 0,
|
||||
// NatType::Cone => 1,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// 返回所有公网ip和端口变化范围
|
||||
pub fn public_ip_list() -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
let mut hash_set = HashSet::new();
|
||||
let mut max_port_range = 0;
|
||||
let mut nat_type = NatType::Cone;
|
||||
let mut port = 88;
|
||||
for _ in 0..3 {
|
||||
let udp = loop {
|
||||
match UdpSocket::bind(SocketAddr::new(IpAddr::from(Ipv4Addr::from(0)), port)) {
|
||||
Ok(udp) => {
|
||||
break udp;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::AddrInUse {
|
||||
port += 1;
|
||||
continue;
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
let (set, min_port, max_port) = public_ip_list_(&udp)?;
|
||||
drop(udp);
|
||||
let port_range = max_port - min_port;
|
||||
//有多个ip或者端口有变化,说明是对称nat
|
||||
if nat_type == NatType::Cone && (set.len() > 1 || port_range != 0) {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
if max_port_range < port_range {
|
||||
max_port_range = port_range;
|
||||
}
|
||||
for x in set {
|
||||
hash_set.insert(x);
|
||||
}
|
||||
thread::sleep(Duration::from_micros(5));
|
||||
}
|
||||
Ok((nat_type, hash_set.into_iter().collect(), max_port_range))
|
||||
}
|
||||
|
||||
/// 测试样本较少,可能不对
|
||||
///
|
||||
/// - 移动宽带:锥形网络、一个ip、端口和局域网端口不相同
|
||||
/// - 电信宽带:锥形网络、一个ip,端口和局域网端口不相同
|
||||
/// - 联调宽带:对称网络、端口不变ip轮流用
|
||||
/// - 移动4g:对称网络、ip端口都变 使用小的端口变化量小
|
||||
/// - 联通4g:对称网络、只有一个ip 端口变化大
|
||||
/// - 电信4g:对称网络只有一个ip 公网端口比较连续
|
||||
/// - 综上:客户端使用小端口,针对对称网络 尝试所有ip 公网端口+-变化量的范围
|
||||
/// - 打通概率 移动宽带=电信宽带>联调宽带>电信4g>移动4g>>联调4g
|
||||
pub fn public_ip_list_(udp: &UdpSocket) -> io::Result<(HashSet<Ipv4Addr>, u16, u16)> {
|
||||
// println!("local port {:?}", udp.local_addr().unwrap().port());
|
||||
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
|
||||
let mut buf = [0u8; 128];
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35062")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35062")?;
|
||||
let mut hash_set = HashSet::new();
|
||||
let mut count = 0;
|
||||
let mut min_port = 65535;
|
||||
let mut max_port = 0;
|
||||
for _ in 0..4 {
|
||||
if let Ok(len) = udp.recv(&mut buf) {
|
||||
if len != 16 || &buf[..10] != &b"NatType213"[..] {
|
||||
continue;
|
||||
}
|
||||
let port = u16::from_be_bytes([buf[14], buf[15]]);
|
||||
if min_port > port {
|
||||
min_port = port;
|
||||
}
|
||||
if max_port < port {
|
||||
max_port = port;
|
||||
}
|
||||
let ip = Ipv4Addr::new(buf[10], buf[11], buf[12], buf[13]);
|
||||
// println!("pub {:?}:{}", ip, port);
|
||||
hash_set.insert(ip);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
if count <= 1 {
|
||||
return Err(io::Error::from(io::ErrorKind::TimedOut));
|
||||
}
|
||||
Ok((hash_set, min_port, max_port))
|
||||
}
|
||||
|
||||
/// 返回nat类型
|
||||
pub fn nat_test() -> io::Result<NatType> {
|
||||
for _ in 0..3 {
|
||||
if NatType::Symmetric == nat_test_()? {
|
||||
return Ok(NatType::Symmetric);
|
||||
}
|
||||
thread::sleep(Duration::from_micros(5));
|
||||
}
|
||||
Ok(NatType::Cone)
|
||||
}
|
||||
|
||||
pub fn nat_test_() -> io::Result<NatType> {
|
||||
let udp = UdpSocket::bind("0.0.0.0:0")?;
|
||||
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
|
||||
let mut buf = [0u8; 128];
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat1.wherewego.top:35062")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35061")?;
|
||||
let _ = udp.send_to(b"NatTest", "nat2.wherewego.top:35062")?;
|
||||
let mut tmp_ip_port: Option<[u8; 6]> = None;
|
||||
let mut count = 0;
|
||||
for _ in 0..4 {
|
||||
if let Ok(len) = udp.recv(&mut buf) {
|
||||
if len != 16 || &buf[..10] != &b"NatType213"[..] {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
let mut ip_port = [0u8; 6];
|
||||
ip_port.copy_from_slice(&buf[10..16]);
|
||||
if let Some(tmp_ip_port) = &tmp_ip_port {
|
||||
if tmp_ip_port != &ip_port {
|
||||
return Ok(NatType::Symmetric);
|
||||
}
|
||||
} else {
|
||||
tmp_ip_port = Some(ip_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
if count <= 1 {
|
||||
return Err(io::Error::from(io::ErrorKind::TimedOut));
|
||||
}
|
||||
Ok(NatType::Cone)
|
||||
}
|
||||
#[test]
|
||||
fn nat_test_run(){
|
||||
let udp = UdpSocket::bind("0.0.0.0:101").unwrap();
|
||||
let print = public_ip_list_(&udp).unwrap();
|
||||
println!("{:?}",print);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod check;
|
||||
@@ -1,941 +0,0 @@
|
||||
// This file is generated by rust-protobuf 3.2.0. Do not edit
|
||||
// .proto file is parsed by pure
|
||||
// @generated
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/702
|
||||
#![allow(unknown_lints)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
#![allow(unused_attributes)]
|
||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
|
||||
#![allow(box_pointers)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(unused_results)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
//! Generated file from `message.proto`
|
||||
|
||||
/// Generated files are compatible only with the same version
|
||||
/// of protobuf runtime.
|
||||
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:RegistrationRequest)
|
||||
pub struct RegistrationRequest {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.token)
|
||||
pub token: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.mac_address)
|
||||
pub mac_address: ::std::string::String,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationRequest.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RegistrationRequest {
|
||||
fn default() -> &'a RegistrationRequest {
|
||||
<RegistrationRequest as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrationRequest {
|
||||
pub fn new() -> RegistrationRequest {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"token",
|
||||
|m: &RegistrationRequest| { &m.token },
|
||||
|m: &mut RegistrationRequest| { &mut m.token },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"mac_address",
|
||||
|m: &RegistrationRequest| { &m.mac_address },
|
||||
|m: &mut RegistrationRequest| { &mut m.mac_address },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationRequest>(
|
||||
"RegistrationRequest",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RegistrationRequest {
|
||||
const NAME: &'static str = "RegistrationRequest";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
10 => {
|
||||
self.token = is.read_string()?;
|
||||
},
|
||||
18 => {
|
||||
self.mac_address = is.read_string()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if !self.token.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.token);
|
||||
}
|
||||
if !self.mac_address.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(2, &self.mac_address);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if !self.token.is_empty() {
|
||||
os.write_string(1, &self.token)?;
|
||||
}
|
||||
if !self.mac_address.is_empty() {
|
||||
os.write_string(2, &self.mac_address)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> RegistrationRequest {
|
||||
RegistrationRequest::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.token.clear();
|
||||
self.mac_address.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RegistrationRequest {
|
||||
static instance: RegistrationRequest = RegistrationRequest {
|
||||
token: ::std::string::String::new(),
|
||||
mac_address: ::std::string::String::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for RegistrationRequest {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationRequest").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for RegistrationRequest {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RegistrationRequest {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:RegistrationResponse)
|
||||
pub struct RegistrationResponse {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_gateway)
|
||||
pub virtual_gateway: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_netmask)
|
||||
pub virtual_netmask: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.epoch)
|
||||
pub epoch: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_ip_list)
|
||||
pub virtual_ip_list: ::std::vec::Vec<u32>,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_ip)
|
||||
pub public_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_port)
|
||||
pub public_port: u32,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationResponse.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RegistrationResponse {
|
||||
fn default() -> &'a RegistrationResponse {
|
||||
<RegistrationResponse as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrationResponse {
|
||||
pub fn new() -> RegistrationResponse {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(7);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &RegistrationResponse| { &m.virtual_ip },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_gateway",
|
||||
|m: &RegistrationResponse| { &m.virtual_gateway },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_gateway },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_netmask",
|
||||
|m: &RegistrationResponse| { &m.virtual_netmask },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_netmask },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"epoch",
|
||||
|m: &RegistrationResponse| { &m.epoch },
|
||||
|m: &mut RegistrationResponse| { &mut m.epoch },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"virtual_ip_list",
|
||||
|m: &RegistrationResponse| { &m.virtual_ip_list },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_ip_list },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_ip",
|
||||
|m: &RegistrationResponse| { &m.public_ip },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port",
|
||||
|m: &RegistrationResponse| { &m.public_port },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_port },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationResponse>(
|
||||
"RegistrationResponse",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RegistrationResponse {
|
||||
const NAME: &'static str = "RegistrationResponse";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
13 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
21 => {
|
||||
self.virtual_gateway = is.read_fixed32()?;
|
||||
},
|
||||
29 => {
|
||||
self.virtual_netmask = is.read_fixed32()?;
|
||||
},
|
||||
32 => {
|
||||
self.epoch = is.read_uint32()?;
|
||||
},
|
||||
42 => {
|
||||
is.read_repeated_packed_fixed32_into(&mut self.virtual_ip_list)?;
|
||||
},
|
||||
45 => {
|
||||
self.virtual_ip_list.push(is.read_fixed32()?);
|
||||
},
|
||||
53 => {
|
||||
self.public_ip = is.read_fixed32()?;
|
||||
},
|
||||
56 => {
|
||||
self.public_port = is.read_uint32()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.virtual_gateway != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.virtual_netmask != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.epoch != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(4, self.epoch);
|
||||
}
|
||||
my_size += 5 * self.virtual_ip_list.len() as u64;
|
||||
if self.public_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.public_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(7, self.public_port);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(1, self.virtual_ip)?;
|
||||
}
|
||||
if self.virtual_gateway != 0 {
|
||||
os.write_fixed32(2, self.virtual_gateway)?;
|
||||
}
|
||||
if self.virtual_netmask != 0 {
|
||||
os.write_fixed32(3, self.virtual_netmask)?;
|
||||
}
|
||||
if self.epoch != 0 {
|
||||
os.write_uint32(4, self.epoch)?;
|
||||
}
|
||||
for v in &self.virtual_ip_list {
|
||||
os.write_fixed32(5, *v)?;
|
||||
};
|
||||
if self.public_ip != 0 {
|
||||
os.write_fixed32(6, self.public_ip)?;
|
||||
}
|
||||
if self.public_port != 0 {
|
||||
os.write_uint32(7, self.public_port)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> RegistrationResponse {
|
||||
RegistrationResponse::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.virtual_ip = 0;
|
||||
self.virtual_gateway = 0;
|
||||
self.virtual_netmask = 0;
|
||||
self.epoch = 0;
|
||||
self.virtual_ip_list.clear();
|
||||
self.public_ip = 0;
|
||||
self.public_port = 0;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RegistrationResponse {
|
||||
static instance: RegistrationResponse = RegistrationResponse {
|
||||
virtual_ip: 0,
|
||||
virtual_gateway: 0,
|
||||
virtual_netmask: 0,
|
||||
epoch: 0,
|
||||
virtual_ip_list: ::std::vec::Vec::new(),
|
||||
public_ip: 0,
|
||||
public_port: 0,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for RegistrationResponse {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationResponse").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for RegistrationResponse {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RegistrationResponse {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:DeviceList)
|
||||
pub struct DeviceList {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:DeviceList.epoch)
|
||||
pub epoch: u32,
|
||||
// @@protoc_insertion_point(field:DeviceList.virtual_ip_list)
|
||||
pub virtual_ip_list: ::std::vec::Vec<u32>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:DeviceList.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a DeviceList {
|
||||
fn default() -> &'a DeviceList {
|
||||
<DeviceList as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceList {
|
||||
pub fn new() -> DeviceList {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"epoch",
|
||||
|m: &DeviceList| { &m.epoch },
|
||||
|m: &mut DeviceList| { &mut m.epoch },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"virtual_ip_list",
|
||||
|m: &DeviceList| { &m.virtual_ip_list },
|
||||
|m: &mut DeviceList| { &mut m.virtual_ip_list },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DeviceList>(
|
||||
"DeviceList",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for DeviceList {
|
||||
const NAME: &'static str = "DeviceList";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
8 => {
|
||||
self.epoch = is.read_uint32()?;
|
||||
},
|
||||
18 => {
|
||||
is.read_repeated_packed_fixed32_into(&mut self.virtual_ip_list)?;
|
||||
},
|
||||
21 => {
|
||||
self.virtual_ip_list.push(is.read_fixed32()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.epoch != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(1, self.epoch);
|
||||
}
|
||||
my_size += 5 * self.virtual_ip_list.len() as u64;
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.epoch != 0 {
|
||||
os.write_uint32(1, self.epoch)?;
|
||||
}
|
||||
for v in &self.virtual_ip_list {
|
||||
os.write_fixed32(2, *v)?;
|
||||
};
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> DeviceList {
|
||||
DeviceList::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.epoch = 0;
|
||||
self.virtual_ip_list.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static DeviceList {
|
||||
static instance: DeviceList = DeviceList {
|
||||
epoch: 0,
|
||||
virtual_ip_list: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for DeviceList {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("DeviceList").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for DeviceList {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for DeviceList {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:Punch)
|
||||
pub struct Punch {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:Punch.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:Punch.public_ip_list)
|
||||
pub public_ip_list: ::std::vec::Vec<u32>,
|
||||
// @@protoc_insertion_point(field:Punch.public_port)
|
||||
pub public_port: u32,
|
||||
// @@protoc_insertion_point(field:Punch.public_port_range)
|
||||
pub public_port_range: u32,
|
||||
// @@protoc_insertion_point(field:Punch.nat_type)
|
||||
pub nat_type: ::protobuf::EnumOrUnknown<NatType>,
|
||||
// @@protoc_insertion_point(field:Punch.reply)
|
||||
pub reply: bool,
|
||||
// @@protoc_insertion_point(field:Punch.step)
|
||||
pub step: ::protobuf::EnumOrUnknown<Step>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:Punch.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a Punch {
|
||||
fn default() -> &'a Punch {
|
||||
<Punch as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
pub fn new() -> Punch {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(7);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &Punch| { &m.virtual_ip },
|
||||
|m: &mut Punch| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"public_ip_list",
|
||||
|m: &Punch| { &m.public_ip_list },
|
||||
|m: &mut Punch| { &mut m.public_ip_list },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port",
|
||||
|m: &Punch| { &m.public_port },
|
||||
|m: &mut Punch| { &mut m.public_port },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port_range",
|
||||
|m: &Punch| { &m.public_port_range },
|
||||
|m: &mut Punch| { &mut m.public_port_range },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"nat_type",
|
||||
|m: &Punch| { &m.nat_type },
|
||||
|m: &mut Punch| { &mut m.nat_type },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"reply",
|
||||
|m: &Punch| { &m.reply },
|
||||
|m: &mut Punch| { &mut m.reply },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"step",
|
||||
|m: &Punch| { &m.step },
|
||||
|m: &mut Punch| { &mut m.step },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Punch>(
|
||||
"Punch",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for Punch {
|
||||
const NAME: &'static str = "Punch";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
13 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
18 => {
|
||||
is.read_repeated_packed_fixed32_into(&mut self.public_ip_list)?;
|
||||
},
|
||||
21 => {
|
||||
self.public_ip_list.push(is.read_fixed32()?);
|
||||
},
|
||||
24 => {
|
||||
self.public_port = is.read_uint32()?;
|
||||
},
|
||||
32 => {
|
||||
self.public_port_range = is.read_uint32()?;
|
||||
},
|
||||
40 => {
|
||||
self.nat_type = is.read_enum_or_unknown()?;
|
||||
},
|
||||
48 => {
|
||||
self.reply = is.read_bool()?;
|
||||
},
|
||||
56 => {
|
||||
self.step = is.read_enum_or_unknown()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
my_size += 5 * self.public_ip_list.len() as u64;
|
||||
if self.public_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(3, self.public_port);
|
||||
}
|
||||
if self.public_port_range != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(4, self.public_port_range);
|
||||
}
|
||||
if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) {
|
||||
my_size += ::protobuf::rt::int32_size(5, self.nat_type.value());
|
||||
}
|
||||
if self.reply != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) {
|
||||
my_size += ::protobuf::rt::int32_size(7, self.step.value());
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(1, self.virtual_ip)?;
|
||||
}
|
||||
for v in &self.public_ip_list {
|
||||
os.write_fixed32(2, *v)?;
|
||||
};
|
||||
if self.public_port != 0 {
|
||||
os.write_uint32(3, self.public_port)?;
|
||||
}
|
||||
if self.public_port_range != 0 {
|
||||
os.write_uint32(4, self.public_port_range)?;
|
||||
}
|
||||
if self.nat_type != ::protobuf::EnumOrUnknown::new(NatType::Symmetric) {
|
||||
os.write_enum(5, ::protobuf::EnumOrUnknown::value(&self.nat_type))?;
|
||||
}
|
||||
if self.reply != false {
|
||||
os.write_bool(6, self.reply)?;
|
||||
}
|
||||
if self.step != ::protobuf::EnumOrUnknown::new(Step::Step1) {
|
||||
os.write_enum(7, ::protobuf::EnumOrUnknown::value(&self.step))?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> Punch {
|
||||
Punch::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.virtual_ip = 0;
|
||||
self.public_ip_list.clear();
|
||||
self.public_port = 0;
|
||||
self.public_port_range = 0;
|
||||
self.nat_type = ::protobuf::EnumOrUnknown::new(NatType::Symmetric);
|
||||
self.reply = false;
|
||||
self.step = ::protobuf::EnumOrUnknown::new(Step::Step1);
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static Punch {
|
||||
static instance: Punch = Punch {
|
||||
virtual_ip: 0,
|
||||
public_ip_list: ::std::vec::Vec::new(),
|
||||
public_port: 0,
|
||||
public_port_range: 0,
|
||||
nat_type: ::protobuf::EnumOrUnknown::from_i32(0),
|
||||
reply: false,
|
||||
step: ::protobuf::EnumOrUnknown::from_i32(0),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for Punch {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("Punch").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for Punch {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for Punch {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
|
||||
// @@protoc_insertion_point(enum:NatType)
|
||||
pub enum NatType {
|
||||
// @@protoc_insertion_point(enum_value:NatType.Symmetric)
|
||||
Symmetric = 0,
|
||||
// @@protoc_insertion_point(enum_value:NatType.Cone)
|
||||
Cone = 1,
|
||||
}
|
||||
|
||||
impl ::protobuf::Enum for NatType {
|
||||
const NAME: &'static str = "NatType";
|
||||
|
||||
fn value(&self) -> i32 {
|
||||
*self as i32
|
||||
}
|
||||
|
||||
fn from_i32(value: i32) -> ::std::option::Option<NatType> {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(NatType::Symmetric),
|
||||
1 => ::std::option::Option::Some(NatType::Cone),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
|
||||
const VALUES: &'static [NatType] = &[
|
||||
NatType::Symmetric,
|
||||
NatType::Cone,
|
||||
];
|
||||
}
|
||||
|
||||
impl ::protobuf::EnumFull for NatType {
|
||||
fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().enum_by_package_relative_name("NatType").unwrap()).clone()
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor {
|
||||
let index = *self as usize;
|
||||
Self::enum_descriptor().value_by_index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::default::Default for NatType {
|
||||
fn default() -> Self {
|
||||
NatType::Symmetric
|
||||
}
|
||||
}
|
||||
|
||||
impl NatType {
|
||||
fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData {
|
||||
::protobuf::reflect::GeneratedEnumDescriptorData::new::<NatType>("NatType")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
|
||||
// @@protoc_insertion_point(enum:Step)
|
||||
pub enum Step {
|
||||
// @@protoc_insertion_point(enum_value:Step.Step1)
|
||||
Step1 = 0,
|
||||
// @@protoc_insertion_point(enum_value:Step.Step2)
|
||||
Step2 = 1,
|
||||
// @@protoc_insertion_point(enum_value:Step.Step3)
|
||||
Step3 = 2,
|
||||
// @@protoc_insertion_point(enum_value:Step.Step4)
|
||||
Step4 = 3,
|
||||
}
|
||||
|
||||
impl ::protobuf::Enum for Step {
|
||||
const NAME: &'static str = "Step";
|
||||
|
||||
fn value(&self) -> i32 {
|
||||
*self as i32
|
||||
}
|
||||
|
||||
fn from_i32(value: i32) -> ::std::option::Option<Step> {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(Step::Step1),
|
||||
1 => ::std::option::Option::Some(Step::Step2),
|
||||
2 => ::std::option::Option::Some(Step::Step3),
|
||||
3 => ::std::option::Option::Some(Step::Step4),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
|
||||
const VALUES: &'static [Step] = &[
|
||||
Step::Step1,
|
||||
Step::Step2,
|
||||
Step::Step3,
|
||||
Step::Step4,
|
||||
];
|
||||
}
|
||||
|
||||
impl ::protobuf::EnumFull for Step {
|
||||
fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().enum_by_package_relative_name("Step").unwrap()).clone()
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor {
|
||||
let index = *self as usize;
|
||||
Self::enum_descriptor().value_by_index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::default::Default for Step {
|
||||
fn default() -> Self {
|
||||
Step::Step1
|
||||
}
|
||||
}
|
||||
|
||||
impl Step {
|
||||
fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData {
|
||||
::protobuf::reflect::GeneratedEnumDescriptorData::new::<Step>("Step")
|
||||
}
|
||||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\rmessage.proto\"L\n\x13RegistrationRequest\x12\x14\n\x05token\x18\x01\
|
||||
\x20\x01(\tR\x05token\x12\x1f\n\x0bmac_address\x18\x02\x20\x01(\tR\nmacA\
|
||||
ddress\"\x83\x02\n\x14RegistrationResponse\x12\x1d\n\nvirtual_ip\x18\x01\
|
||||
\x20\x01(\x07R\tvirtualIp\x12'\n\x0fvirtual_gateway\x18\x02\x20\x01(\x07\
|
||||
R\x0evirtualGateway\x12'\n\x0fvirtual_netmask\x18\x03\x20\x01(\x07R\x0ev\
|
||||
irtualNetmask\x12\x14\n\x05epoch\x18\x04\x20\x01(\rR\x05epoch\x12&\n\x0f\
|
||||
virtual_ip_list\x18\x05\x20\x03(\x07R\rvirtualIpList\x12\x1b\n\tpublic_i\
|
||||
p\x18\x06\x20\x01(\x07R\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\x20\
|
||||
\x01(\rR\npublicPort\"J\n\nDeviceList\x12\x14\n\x05epoch\x18\x01\x20\x01\
|
||||
(\rR\x05epoch\x12&\n\x0fvirtual_ip_list\x18\x02\x20\x03(\x07R\rvirtualIp\
|
||||
List\"\xef\x01\n\x05Punch\x12\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tv\
|
||||
irtualIp\x12$\n\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\
|
||||
\x12\x1f\n\x0bpublic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11publ\
|
||||
ic_port_range\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12#\n\x08nat_type\
|
||||
\x18\x05\x20\x01(\x0e2\x08.NatTypeR\x07natType\x12\x14\n\x05reply\x18\
|
||||
\x06\x20\x01(\x08R\x05reply\x12\x19\n\x04step\x18\x07\x20\x01(\x0e2\x05.\
|
||||
StepR\x04step*\"\n\x07NatType\x12\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\
|
||||
\x10\x01*2\n\x04Step\x12\t\n\x05Step1\x10\0\x12\t\n\x05Step2\x10\x01\x12\
|
||||
\t\n\x05Step3\x10\x02\x12\t\n\x05Step4\x10\x03b\x06proto3\
|
||||
";
|
||||
|
||||
/// `FileDescriptorProto` object which was a source for this generated file
|
||||
fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new();
|
||||
file_descriptor_proto_lazy.get(|| {
|
||||
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
/// `FileDescriptor` object which allows dynamic access to files
|
||||
pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
|
||||
static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
file_descriptor.get(|| {
|
||||
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
|
||||
let mut deps = ::std::vec::Vec::with_capacity(0);
|
||||
let mut messages = ::std::vec::Vec::with_capacity(4);
|
||||
messages.push(RegistrationRequest::generated_message_descriptor_data());
|
||||
messages.push(RegistrationResponse::generated_message_descriptor_data());
|
||||
messages.push(DeviceList::generated_message_descriptor_data());
|
||||
messages.push(Punch::generated_message_descriptor_data());
|
||||
let mut enums = ::std::vec::Vec::with_capacity(2);
|
||||
enums.push(NatType::generated_enum_descriptor_data());
|
||||
enums.push(Step::generated_enum_descriptor_data());
|
||||
::protobuf::reflect::GeneratedFileDescriptor::new_generated(
|
||||
file_descriptor_proto(),
|
||||
deps,
|
||||
messages,
|
||||
enums,
|
||||
)
|
||||
});
|
||||
::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)
|
||||
})
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
use std::fmt;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
Ping,
|
||||
Pong,
|
||||
PunchRequest,
|
||||
PunchResponse,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Ping,
|
||||
2 => Protocol::Pong,
|
||||
3 => Protocol::PunchRequest,
|
||||
4 => Protocol::PunchResponse,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Ping => 1,
|
||||
Protocol::Pong => 2,
|
||||
Protocol::PunchRequest => 3,
|
||||
Protocol::PunchResponse => 4,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ControlPacket<B> {
|
||||
PingPacket(PingPacket<B>),
|
||||
PongPacket(PongPacket<B>),
|
||||
PunchRequest(PunchRequestPacket<B>),
|
||||
PunchResponse(PunchResponsePacket<B>),
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ControlPacket<B> {
|
||||
pub fn new(protocol: u8, buffer: B) -> Result<ControlPacket<B>> {
|
||||
match Protocol::from(protocol) {
|
||||
Protocol::Ping => Ok(ControlPacket::PingPacket(PingPacket::new(buffer)?)),
|
||||
Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)),
|
||||
Protocol::PunchRequest => Ok(ControlPacket::PunchRequest(PunchRequestPacket::new(
|
||||
buffer,
|
||||
)?)),
|
||||
Protocol::PunchResponse => Ok(ControlPacket::PunchResponse(PunchResponsePacket::new(
|
||||
buffer,
|
||||
)?)),
|
||||
Protocol::UnKnow(_) => Err(Error::NotSupport),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 网络探针
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PingPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PongPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<PingPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 8 + 4 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(PingPacket { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn time(&self) -> i64 {
|
||||
i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap())
|
||||
}
|
||||
pub fn epoch(&self) -> u32 {
|
||||
u32::from_be_bytes(self.buffer.as_ref()[8..12].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> PingPacket<B> {
|
||||
pub fn set_time(&mut self, time: i64) {
|
||||
self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes())
|
||||
}
|
||||
pub fn set_epoch(&mut self, epoch: u32) {
|
||||
self.buffer.as_mut()[8..12].copy_from_slice(&epoch.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PingPacket")
|
||||
.field("time", &self.time())
|
||||
.field("epoch", &self.epoch())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PongPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<PongPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(PongPacket { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PongPacket<B> {
|
||||
pub fn time(&self) -> i64 {
|
||||
i64::from_be_bytes(self.buffer.as_ref()[..8].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> PongPacket<B> {
|
||||
pub fn set_time(&mut self, time: i64) {
|
||||
self.buffer.as_mut()[..8].copy_from_slice(&time.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for PongPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PongPacket")
|
||||
.field("time", &self.time())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub type TurnPongPacket<B> = TurnPingPacket<B>;
|
||||
|
||||
/// 探测目标延迟
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TurnPingPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPingPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<TurnPingPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 16 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(TurnPingPacket { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPingPacket<B> {
|
||||
// pub fn source(&self) -> Ipv4Addr {
|
||||
// let tmp:[u8;4] = self.buffer.as_ref()[..4].try_into().unwrap();
|
||||
// Ipv4Addr::from(tmp)
|
||||
// }
|
||||
// pub fn destination(&self) -> Ipv4Addr {
|
||||
// let tmp:[u8;4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
// Ipv4Addr::from(tmp)
|
||||
// }
|
||||
pub fn time(&self) -> i64 {
|
||||
i64::from_be_bytes(self.buffer.as_ref()[8..].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> TurnPingPacket<B> {
|
||||
pub fn set_source(&mut self, source: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
|
||||
}
|
||||
pub fn set_destination(&mut self, destination: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets());
|
||||
}
|
||||
pub fn set_time(&mut self, time: i64) {
|
||||
self.buffer.as_mut()[8..].copy_from_slice(&time.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
pub type PunchResponsePacket<B> = PunchPacket<B>;
|
||||
pub type PunchRequestPacket<B> = PunchPacket<B>;
|
||||
|
||||
/// nat穿透
|
||||
#[derive(Clone)]
|
||||
pub struct PunchPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PunchPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<PunchPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(Self { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PunchPacket<B> {
|
||||
pub fn source(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> PunchPacket<B> {
|
||||
pub fn set_source(&mut self, source: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for PunchPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PunchPacket")
|
||||
.field("source", &self.source())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
pub mod control_packet;
|
||||
pub mod error_packet;
|
||||
pub mod service_packet;
|
||||
pub mod turn_packet;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Version {
|
||||
V1,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Version {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Version::V1,
|
||||
val => Version::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Version {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Version::V1 => 1,
|
||||
Version::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
/// 服务包 用于和服务端交互
|
||||
Service,
|
||||
/// 响应异常
|
||||
Error,
|
||||
/// 控制协议
|
||||
Control,
|
||||
/// 转发ipv4数据
|
||||
Ipv4Turn,
|
||||
OtherTurn,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Service,
|
||||
2 => Protocol::Error,
|
||||
3 => Protocol::Control,
|
||||
4 => Protocol::Ipv4Turn,
|
||||
5 => Protocol::OtherTurn,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Service => 1,
|
||||
Protocol::Error => 2,
|
||||
Protocol::Control => 3,
|
||||
Protocol::Ipv4Turn => 4,
|
||||
Protocol::OtherTurn => 5,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NetPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<NetPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
// 不能大于udp最大载荷长度
|
||||
if len < 4 || len > 65535 - 20 - 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(NetPacket { buffer })
|
||||
}
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
self.buffer.as_ref()
|
||||
}
|
||||
pub fn into_buffer(self) -> B {
|
||||
self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
pub fn version(&self) -> Version {
|
||||
Version::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn protocol(&self) -> Protocol {
|
||||
Protocol::from(self.buffer.as_ref()[1])
|
||||
}
|
||||
pub fn transport_protocol(&self) -> u8 {
|
||||
self.buffer.as_ref()[2]
|
||||
}
|
||||
pub fn ttl(&self) -> u8 {
|
||||
self.buffer.as_ref()[3]
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[4..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
||||
pub fn set_version(&mut self, version: Version) {
|
||||
self.buffer.as_mut()[0] = version.into();
|
||||
}
|
||||
pub fn set_protocol(&mut self, protocol: Protocol) {
|
||||
self.buffer.as_mut()[1] = protocol.into();
|
||||
}
|
||||
pub fn set_transport_protocol(&mut self, transport_protocol: u8) {
|
||||
self.buffer.as_mut()[2] = transport_protocol;
|
||||
}
|
||||
pub fn set_ttl(&mut self, ttl: u8) {
|
||||
self.buffer.as_mut()[3] = ttl;
|
||||
}
|
||||
pub fn set_payload(&mut self, payload: &[u8]) {
|
||||
self.buffer.as_mut()[4..payload.len() + 4].copy_from_slice(payload);
|
||||
}
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[4..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for NetPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("NetPacket")
|
||||
.field("version", &self.version())
|
||||
.field("protocol", &self.protocol())
|
||||
.field("transport_protocol", &self.transport_protocol())
|
||||
.field("ttl", &self.ttl())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
/// 注册请求
|
||||
RegistrationRequest,
|
||||
/// 注册响应
|
||||
RegistrationResponse,
|
||||
/// 更新设备列表
|
||||
UpdateDeviceList,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Self::RegistrationRequest,
|
||||
2 => Self::RegistrationResponse,
|
||||
3 => Self::UpdateDeviceList,
|
||||
val => Self::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Self::RegistrationRequest => 1,
|
||||
Self::RegistrationResponse => 2,
|
||||
Self::UpdateDeviceList => 3,
|
||||
Self::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
use std::fmt;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Protocol {
|
||||
Punch,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Punch,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Punch => 1,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TurnPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<TurnPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len <= 8 {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
Ok(Self { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TurnPacket<B> {
|
||||
pub fn source(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[..4].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn destination(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[8..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> TurnPacket<B> {
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[8..]
|
||||
}
|
||||
pub fn set_source(&mut self, source: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&source.octets());
|
||||
}
|
||||
pub fn set_destination(&mut self, destination: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&destination.octets());
|
||||
}
|
||||
pub fn set_payload(&mut self, payload: &[u8]) {
|
||||
self.buffer.as_mut()[8..payload.len() + 8].copy_from_slice(payload)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for TurnPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TurnPacket")
|
||||
.field("source", &self.source())
|
||||
.field("destination", &self.destination())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
#[cfg(any(unix))]
|
||||
pub use unix::create_tun;
|
||||
#[cfg(any(unix))]
|
||||
pub use unix::{TunReader, TunWriter};
|
||||
|
||||
#[cfg(any(unix))]
|
||||
pub mod unix;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod windows;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::create_tun;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{TunReader, TunWriter};
|
||||
@@ -1,156 +0,0 @@
|
||||
use std::io;
|
||||
use std::io::{Error, Read, Write};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::Command;
|
||||
|
||||
use bytes::BufMut;
|
||||
use tun::Device;
|
||||
use tun::platform::posix::{Reader, Writer};
|
||||
|
||||
pub fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> crate::error::Result<(TunWriter, TunReader)> {
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(1420)
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
config.platform(|config| {
|
||||
config.packet_information(true);
|
||||
});
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
|
||||
// let up_eth_str: String = format!("ifconfig utun3 {:?} {:?} up ", address, gateway);
|
||||
let route_add_str: String = format!(
|
||||
"sudo route -n add -net {:?} -netmask {:?} {:?}",
|
||||
address, netmask, gateway
|
||||
);
|
||||
//
|
||||
// let up_eth_out = Command::new("sh")
|
||||
// .arg("-c")
|
||||
// .arg(up_eth_str)
|
||||
// .output()
|
||||
// .expect("sh exec error!");
|
||||
// if !up_eth_out.status.success() {
|
||||
// return Err(crate::error::Error::Stop(format!("设置地址失败:{:?}", up_eth_out)));
|
||||
// }
|
||||
// println!("{:?}", up_eth_out);
|
||||
let if_config_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !if_config_out.status.success() {
|
||||
return Err(crate::error::Error::Stop(format!("设置路由失败:{:?}", if_config_out)));
|
||||
}
|
||||
// println!("{:?}", if_config_out);
|
||||
// let cmd_str: String = " ifconfig|grep flags=8051|awk -F ':' '{print $1}'|tail -1".to_string();
|
||||
//
|
||||
// let cmd_str_out = Command::new("sh")
|
||||
// .arg("-c")
|
||||
// .arg(cmd_str)
|
||||
// .output()
|
||||
// .expect("sh exec error!");
|
||||
// if !cmd_str_out.status.success(){
|
||||
// return Err(Error::Stop(format!("设置路由失败:{:?}", cmd_str_out)));
|
||||
// }
|
||||
// println!("{:?}", cmd_str_out);
|
||||
let packet_information = dev.has_packet_information();
|
||||
let (reader, writer) = dev.split();
|
||||
Ok((
|
||||
TunWriter(writer, packet_information),
|
||||
TunReader(reader, packet_information),
|
||||
))
|
||||
}
|
||||
|
||||
pub struct TunReader(Reader, bool);
|
||||
|
||||
impl TunReader {
|
||||
pub fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> io::Result<&mut [u8]> {
|
||||
let len = self.0.read(buf)?;
|
||||
if self.1 {
|
||||
Ok(&mut buf[4..len])
|
||||
} else {
|
||||
Ok(&mut buf[..len])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunWriter(Writer, bool);
|
||||
|
||||
impl TunWriter {
|
||||
pub fn write(&mut self, packet: &[u8]) -> io::Result<()> {
|
||||
if self.1 {
|
||||
let mut buf = Vec::<u8>::with_capacity(4 + packet.len());
|
||||
buf.put_u16(0);
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
buf.put_u16(libc::PF_INET as u16);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
buf.put_u16(libc::ETH_P_IP as u16);
|
||||
buf.extend_from_slice(packet);
|
||||
self.0.write_all(&buf)
|
||||
} else {
|
||||
self.0.write_all(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn main1() {
|
||||
// loop {
|
||||
// let len = reader.read(&mut buffer).unwrap();
|
||||
// println!("{:?}", &buffer[..len]);
|
||||
// match ip::Packet::new(&buffer[4..len]) {
|
||||
// Ok(ip::Packet::V4(pkt)) => {
|
||||
// match icmp::Packet::new(pkt.payload()) {
|
||||
// Ok(icmp) => {
|
||||
// match icmp.echo() {
|
||||
// Ok(icmp) => {
|
||||
// println!("{:?}", icmp);
|
||||
// let reply = ip::v4::Builder::default()
|
||||
// .id(0x42)
|
||||
// .unwrap()
|
||||
// .ttl(64)
|
||||
// .unwrap()
|
||||
// .source(pkt.destination())
|
||||
// .unwrap()
|
||||
// .destination(pkt.source())
|
||||
// .unwrap()
|
||||
// .icmp()
|
||||
// .unwrap()
|
||||
// .echo()
|
||||
// .unwrap()
|
||||
// .reply()
|
||||
// .unwrap()
|
||||
// .identifier(icmp.identifier())
|
||||
// .unwrap()
|
||||
// .sequence(icmp.sequence())
|
||||
// .unwrap()
|
||||
// .payload(icmp.payload())
|
||||
// .unwrap()
|
||||
// .build()
|
||||
// .unwrap();
|
||||
// let l = reply.len();
|
||||
// &mut buffer[4..(l + 4)].copy_from_slice(&reply);
|
||||
// // writer.write_all(&buffer[..4]).unwrap();
|
||||
// writer.write_all(&buffer[..(l + 4)]).unwrap();
|
||||
// }
|
||||
// Err(_) => {}
|
||||
// }
|
||||
// }
|
||||
// Err(_) => {}
|
||||
// }
|
||||
// }
|
||||
// _ => {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -1,132 +0,0 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use libloading::Library;
|
||||
use wintun::{Adapter, Packet, Session};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
pub struct TunWriter(Arc<Session>);
|
||||
|
||||
impl TunWriter {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.0.allocate_send_packet(buf.len() as u16) {
|
||||
Ok(mut packet) => {
|
||||
packet.bytes_mut().copy_from_slice(buf);
|
||||
self.0.send_packet(packet);
|
||||
return Ok(());
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "send err"));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TunReader(Arc<Session>);
|
||||
|
||||
impl TunReader {
|
||||
pub fn next(&self) -> io::Result<Packet> {
|
||||
match self.0.receive_blocking() {
|
||||
Ok(packet) => {
|
||||
return Ok(packet);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "read err"));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
) -> Result<(TunWriter, TunReader)> {
|
||||
let win_tun = unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(library) => match wintun::load_from_library(library) {
|
||||
Ok(win_tun) => win_tun,
|
||||
Err(e) => {
|
||||
return Err(Error::Stop(format!("{:?}", e)));
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
println!("{}", console::style("wintun.dll not found").red());
|
||||
return Err(Error::Stop(format!("{:?}", e)));
|
||||
}
|
||||
}
|
||||
};
|
||||
let adapter = match Adapter::open(&win_tun, "Demo") {
|
||||
Ok(a) => a,
|
||||
Err(_) => match Adapter::create(&win_tun, "Example", "Demo", None) {
|
||||
Ok(adapter) => adapter,
|
||||
|
||||
Err(e) => return Err(Error::Stop(format!("{:?}", e))),
|
||||
},
|
||||
};
|
||||
let index = adapter.get_adapter_index().unwrap();
|
||||
let set_mtu = format!(
|
||||
"netsh interface ipv4 set subinterface {} mtu=1420 store=persistent",
|
||||
index
|
||||
);
|
||||
let set_metric = format!("netsh interface ip set interface {} metric=1", index);
|
||||
let set_address = format!(
|
||||
"netsh interface ip set address {} static {:?} {:?} ", // gateway={:?}
|
||||
index, address, netmask,
|
||||
);
|
||||
// println!("{}", set_mtu);
|
||||
// println!("{}", set_metric);
|
||||
// println!("{}", set_address);
|
||||
// 执行网卡初始化命令
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_mtu)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("设置mtu失败:{:?}", out)));
|
||||
}
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_metric)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("设置接口跃点失败:{:?}", out)));
|
||||
}
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_address)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("设置网络地址失败:{:?}", out)));
|
||||
}
|
||||
let dest = {
|
||||
let ip = address.octets();
|
||||
let mask = netmask.octets();
|
||||
Ipv4Addr::from([
|
||||
ip[0] & mask[0],
|
||||
ip[1] & mask[1],
|
||||
ip[2] & mask[2],
|
||||
ip[3] & mask[3],
|
||||
])
|
||||
};
|
||||
let set_route = format!(
|
||||
"route add {:?} mask {:?} {:?} if {}",
|
||||
dest, netmask, gateway, index
|
||||
);
|
||||
// println!("{}", set_route);
|
||||
// 执行添加路由命令
|
||||
let out = std::process::Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(set_route)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(Error::Stop(format!("添加路由失败:{:?}", out)));
|
||||
}
|
||||
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
|
||||
let reader_session = session.clone();
|
||||
Ok((TunWriter(session), TunReader(reader_session)))
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
[package]
|
||||
name = "vnt-cli"
|
||||
version = "1.2.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vnt = { path = "../vnt", package = "vnt", optional = true }
|
||||
common = { path = "../common" }
|
||||
tokio = { version = "1.28.1", features = ["full"] }
|
||||
getopts = "0.2.21"
|
||||
console = "0.15.2"
|
||||
os_info = "3.7.0"
|
||||
dirs = "4.0.0"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0.94"
|
||||
log = "0.4.17"
|
||||
log4rs = "1.2.0"
|
||||
[dependencies.uuid]
|
||||
version = "1.4.1"
|
||||
features = [
|
||||
"v4", # Lets you generate random UUIDs
|
||||
]
|
||||
|
||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
sudo = "0.6.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||
|
||||
[features]
|
||||
default = ["normal"]
|
||||
normal = ["vnt"]
|
||||
ring-cipher = ["vnt/ring-cipher"]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
embed-manifest = "1.4.0"
|
||||
@@ -0,0 +1,77 @@
|
||||
## 模块介绍
|
||||
体积小,可以在服务器、路由器等环境使用
|
||||
## 详细参数说明
|
||||
### -k `<token>`
|
||||
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
|
||||
### -n `<name>`
|
||||
设备名称,方便区分不同设备
|
||||
### -d `<id>`
|
||||
设备id,每台设备的唯一标识,注意不要重复
|
||||
### -c
|
||||
关闭控制台交互式命令,后台运行时可以加此参数
|
||||
### -s `<server>`
|
||||
注册和中继服务器地址,注册和转发数据
|
||||
### -e `<stun-server>`
|
||||
使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略
|
||||
### -a
|
||||
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
|
||||
### -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),
|
||||
|
||||
则在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
|
||||
|
||||
### -w `<password>`
|
||||
|
||||
提升通信安全性,使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密(包括中继数据)。使用相同密码的客户端才能通信
|
||||
|
||||
| 密码位数 | 加密算法 |
|
||||
|---------|-------|
|
||||
| 小于8 | AES128-GCM
|
||||
| 大于等于8 | AES256-GCM |
|
||||
|
||||
### -W
|
||||
开启和服务端通信加密,可以避免中间人攻击
|
||||
### -m
|
||||
模拟组播,高频使用组播通信时,可以尝试开启此参数,默认情况下会把组播当作广播发给所有节点
|
||||
|
||||
默认情况(组播当广播发送):稳定性好,使用组播频率低时更省流量
|
||||
|
||||
模拟组播:高频使用组播时防止广播泛洪,客户端和中继服务器会维护组播成员等信息,注意使用此选项时,虚拟网内所有成员都需要开启此选项
|
||||
|
||||
### -u `<mtu>`
|
||||
|
||||
设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值,不加密默认为1430,加密默认为1410
|
||||
|
||||
### --tcp
|
||||
和服务端使用tcp通信。有些网络提供商对UDP限制比较大,这个时候可以选择使用TCP模式,提高稳定性。一般来说udp延迟和消耗更低
|
||||
### --ip `<IP>`
|
||||
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
|
||||
### --par `<parallel>`
|
||||
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
|
||||
### --thread `<thread>`
|
||||
线程数(必须为正整数),默认为核心数乘2,该值表示处理网络读写、ip代理、打洞等用到的线程数,组网设备数较多、处理延迟较大时可适当调大此值
|
||||
### --model `<model>`
|
||||
加密模式,可选值 aes_gcm/aes_cbc,默认使用aes_gcm,通常情况使用aes_cbc性能更好
|
||||
|
||||
| 密码位数 | model | 加密算法 |
|
||||
|-------|--------|------------|
|
||||
| 1~8位 | aes_gcm | AES128-GCM |
|
||||
| `>=`8 | aes_gcm | AES256-GCM |
|
||||
| 1~8位 | aes_cbc | AES128-CBC |
|
||||
| `>=`8 | aes_cbc | AES256-CBC |
|
||||
|
||||
### --relay
|
||||
禁用p2p,在网络环境很差时,只使用服务器中转效果可能更好(可以配合--tcp参数一起使用)
|
||||
### --list
|
||||
在后台运行时,查看其他设备列表
|
||||
### --all
|
||||
在后台运行时,查看其他设备完整信息
|
||||
### --info
|
||||
在后台运行时,查看当前设备信息
|
||||
### --route
|
||||
在后台运行时,查看数据转发路径
|
||||
### --stop
|
||||
停止后台运行
|
||||
@@ -0,0 +1,10 @@
|
||||
// use embed_manifest::{embed_manifest, new_manifest};
|
||||
// use embed_manifest::manifest::ExecutionLevel;
|
||||
|
||||
fn main() {
|
||||
////强制用管理员运行貌似体验更差了
|
||||
// if std::env::var_os("CARGO_CFG_WINDOWS").is_some() {
|
||||
// embed_manifest(new_manifest("vnt")
|
||||
// .requested_execution_level(ExecutionLevel::RequireAdministrator)).expect("unable to embed manifest file");
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Info};
|
||||
|
||||
pub struct CommandClient {
|
||||
udp: UdpSocket,
|
||||
}
|
||||
|
||||
impl CommandClient {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let path_buf = crate::app_home()?.join("command-port");
|
||||
if !path_buf.exists() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not started"));
|
||||
}
|
||||
let port = std::fs::read_to_string(path_buf)?;
|
||||
let port = match u16::from_str(&port) {
|
||||
Ok(port) => { port }
|
||||
Err(_) => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "'command-port' file error"));
|
||||
}
|
||||
};
|
||||
let udp = UdpSocket::bind("127.0.0.1:0")?;
|
||||
udp.set_read_timeout(Some(Duration::from_secs(2)))?;
|
||||
udp.connect(SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::new(127, 0, 0, 1),
|
||||
port,
|
||||
)))?;
|
||||
Ok(Self { udp })
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandClient {
|
||||
pub fn list(&self) -> io::Result<Vec<DeviceItem>> {
|
||||
self.udp.send(b"list")?;
|
||||
let mut buf = [0; 10240];
|
||||
let len = self.udp.recv(&mut buf)?;
|
||||
match serde_json::from_slice::<Vec<DeviceItem>>(&buf[..len]) {
|
||||
Ok(val) => {
|
||||
Ok(val)
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e);
|
||||
Err(io::Error::new(io::ErrorKind::Other, "data error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn route(&self) -> io::Result<Vec<RouteItem>> {
|
||||
self.udp.send(b"route")?;
|
||||
let mut buf = [0; 10240];
|
||||
let len = self.udp.recv(&mut buf)?;
|
||||
match serde_json::from_slice::<Vec<RouteItem>>(&buf[..len]) {
|
||||
Ok(val) => {
|
||||
Ok(val)
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e);
|
||||
Err(io::Error::new(io::ErrorKind::Other, "data error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn info(&self) -> io::Result<Info> {
|
||||
self.udp.send(b"info")?;
|
||||
let mut buf = [0; 10240];
|
||||
let len = self.udp.recv(&mut buf)?;
|
||||
match serde_json::from_slice::<Info>(&buf[..len]) {
|
||||
Ok(val) => {
|
||||
Ok(val)
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?},{:?}",&buf[..len],e);
|
||||
Err(io::Error::new(io::ErrorKind::Other, "data error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn stop(&self) -> io::Result<String> {
|
||||
self.udp.send(b"stop")?;
|
||||
let mut buf = [0; 10240];
|
||||
let len = self.udp.recv(&mut buf)?;
|
||||
Ok(String::from_utf8(buf[..len].to_vec()).unwrap())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Info {
|
||||
pub name: String,
|
||||
pub virtual_ip: String,
|
||||
pub virtual_gateway: String,
|
||||
pub virtual_netmask: String,
|
||||
pub connect_status: String,
|
||||
pub relay_server: String,
|
||||
pub nat_type: String,
|
||||
pub public_ips: String,
|
||||
pub local_ip: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct RouteItem {
|
||||
pub destination: String,
|
||||
pub next_hop: String,
|
||||
pub metric: String,
|
||||
pub rt: String,
|
||||
pub interface: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DeviceItem {
|
||||
pub name: String,
|
||||
pub virtual_ip: String,
|
||||
pub nat_type: String,
|
||||
pub public_ips: String,
|
||||
pub local_ip: String,
|
||||
pub nat_traversal_type: String,
|
||||
pub rt: String,
|
||||
pub status: String,
|
||||
pub client_secret: bool,
|
||||
pub current_client_secret:bool,
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
use std::io;
|
||||
use vnt::core::Vnt;
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Info};
|
||||
use crate::console_out;
|
||||
|
||||
pub mod client;
|
||||
pub mod server;
|
||||
pub mod entity;
|
||||
|
||||
pub enum CommandEnum {
|
||||
Route,
|
||||
List,
|
||||
All,
|
||||
Info,
|
||||
Stop,
|
||||
}
|
||||
|
||||
pub fn command(cmd: CommandEnum) {
|
||||
if let Err(e) = command_(cmd) {
|
||||
println!("cmd: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn command_(cmd: CommandEnum) -> io::Result<()> {
|
||||
let command_client = client::CommandClient::new()?;
|
||||
match cmd {
|
||||
CommandEnum::Route => {
|
||||
let list = command_client.route()?;
|
||||
console_out::console_route_table(list);
|
||||
}
|
||||
CommandEnum::List => {
|
||||
let list = command_client.list()?;
|
||||
console_out::console_device_list(list);
|
||||
}
|
||||
CommandEnum::All => {
|
||||
let list = command_client.list()?;
|
||||
console_out::console_device_list_all(list);
|
||||
}
|
||||
CommandEnum::Info => {
|
||||
let info = command_client.info()?;
|
||||
console_out::console_info(info);
|
||||
}
|
||||
CommandEnum::Stop => {
|
||||
command_client.stop()?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
|
||||
let route_table = vnt.route_table();
|
||||
let mut route_list = Vec::with_capacity(route_table.len());
|
||||
for (destination, route) in route_table {
|
||||
let next_hop = vnt.route_key(&route.route_key()).map_or(String::new(), |v| v.to_string());
|
||||
let metric = route.metric.to_string();
|
||||
let rt = if route.rt < 0 {
|
||||
"".to_string()
|
||||
} else {
|
||||
route.rt.to_string()
|
||||
};
|
||||
let interface = route.addr.to_string();
|
||||
let item = RouteItem {
|
||||
destination: destination.to_string(),
|
||||
next_hop,
|
||||
metric,
|
||||
rt,
|
||||
interface,
|
||||
};
|
||||
route_list.push(item);
|
||||
}
|
||||
route_list
|
||||
}
|
||||
|
||||
pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
let info = vnt.current_device();
|
||||
let device_list = vnt.device_list();
|
||||
let mut list = Vec::new();
|
||||
let current_client_secret = vnt.client_encrypt();
|
||||
for peer in device_list {
|
||||
let name = peer.name;
|
||||
let virtual_ip = peer.virtual_ip.to_string();
|
||||
let (nat_type, public_ips, local_ip) = if let Some(nat_info) = vnt.peer_nat_info(&peer.virtual_ip) {
|
||||
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(",");
|
||||
let local_ip = nat_info.local_ip.to_string();
|
||||
(nat_type, public_ips, local_ip)
|
||||
} else {
|
||||
("".to_string(), "".to_string(), "".to_string())
|
||||
};
|
||||
let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
||||
let nat_traversal_type = if route.metric == 1 {
|
||||
"p2p"
|
||||
} else if route.addr == info.connect_server {
|
||||
"server-relay"
|
||||
} else {
|
||||
"client-relay"
|
||||
}.to_string();
|
||||
let rt = if route.rt < 0 {
|
||||
"".to_string()
|
||||
} else {
|
||||
route.rt.to_string()
|
||||
};
|
||||
(nat_traversal_type, rt)
|
||||
} else {
|
||||
("relay".to_string(), "".to_string())
|
||||
};
|
||||
let status = format!("{:?}", peer.status);
|
||||
let client_secret = peer.client_secret;
|
||||
let item = DeviceItem {
|
||||
name,
|
||||
virtual_ip,
|
||||
nat_type,
|
||||
public_ips,
|
||||
local_ip,
|
||||
nat_traversal_type,
|
||||
rt,
|
||||
status,
|
||||
client_secret,
|
||||
current_client_secret,
|
||||
};
|
||||
list.push(item);
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
pub fn command_info(vnt: &Vnt) -> Info {
|
||||
let current_device = vnt.current_device();
|
||||
let nat_info = vnt.nat_info();
|
||||
let name = vnt.name().to_string();
|
||||
let virtual_ip = current_device.virtual_ip().to_string();
|
||||
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 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(",");
|
||||
let local_ip = nat_info.local_ip.to_string();
|
||||
Info {
|
||||
name,
|
||||
virtual_ip,
|
||||
virtual_gateway,
|
||||
virtual_netmask,
|
||||
connect_status,
|
||||
relay_server,
|
||||
nat_type,
|
||||
public_ips,
|
||||
local_ip,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use tokio::net::UdpSocket;
|
||||
|
||||
use vnt::core::Vnt;
|
||||
|
||||
|
||||
pub struct CommandServer {}
|
||||
|
||||
impl CommandServer {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandServer {
|
||||
pub async fn start(self, vnt: Vnt) -> io::Result<()> {
|
||||
let udp = UdpSocket::bind("127.0.0.1:0").await?;
|
||||
let path_buf = crate::app_home()?.join("command-port");
|
||||
let mut file = std::fs::File::create(path_buf)?;
|
||||
file.write_all(udp.local_addr()?.port().to_string().as_bytes())?;
|
||||
file.sync_all()?;
|
||||
let mut buf = [0u8; 64];
|
||||
loop {
|
||||
let (len, addr) = udp.recv_from(&mut buf).await?;
|
||||
match std::str::from_utf8(&buf[..len]) {
|
||||
Ok(cmd) => {
|
||||
if let Ok(out) = command(cmd, &vnt) {
|
||||
let _ = udp.send_to(out.as_bytes(), addr).await;
|
||||
if "stopped" == &out {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn command(cmd: &str, vnt: &Vnt) -> io::Result<String> {
|
||||
let out_str = match cmd {
|
||||
"route" => {
|
||||
match serde_json::to_string(&crate::command::command_route(vnt)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"list" => {
|
||||
match serde_json::to_string(&crate::command::command_list(vnt)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"info" => {
|
||||
match serde_json::to_string(&crate::command::command_info(vnt)) {
|
||||
Ok(str) => {
|
||||
str
|
||||
}
|
||||
Err(e) => {
|
||||
format!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
"stop" => {
|
||||
vnt.stop()?;
|
||||
"stopped".to_string()
|
||||
}
|
||||
_ => {
|
||||
format!("command '{}' not found. \n Try to enter: 'help'\n", cmd)
|
||||
}
|
||||
};
|
||||
Ok(out_str)
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
use console::{style, Style};
|
||||
|
||||
use crate::command::entity::{DeviceItem, RouteItem, Info};
|
||||
|
||||
pub mod table;
|
||||
|
||||
pub fn console_info(status: Info) {
|
||||
println!("Name: {}", style(status.name).green());
|
||||
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());
|
||||
println!("NAT type: {}", style(status.nat_type).green());
|
||||
println!("Relay server: {}", style(status.relay_server).green());
|
||||
println!("Public ips: {}", style(status.public_ips).green());
|
||||
println!("Local ip: {}", style(status.local_ip).green());
|
||||
}
|
||||
|
||||
pub fn console_route_table(mut list: Vec<RouteItem>) {
|
||||
if list.is_empty() {
|
||||
println!("No route found");
|
||||
return;
|
||||
}
|
||||
list.sort_by(|t1, t2| t1.destination.cmp(&t2.destination));
|
||||
let mut out_list = Vec::with_capacity(list.len());
|
||||
|
||||
out_list.push(vec![("Destination".to_string(), Style::new()),
|
||||
("Next Hop".to_string(), Style::new()),
|
||||
("Metric".to_string(), Style::new()),
|
||||
("Rt".to_string(), Style::new()),
|
||||
("Interface".to_string(), Style::new()), ]);
|
||||
for item in list {
|
||||
out_list.push(vec![(item.destination, Style::new().green()),
|
||||
(item.next_hop, Style::new().green()),
|
||||
(item.metric, Style::new().green()),
|
||||
(item.rt, Style::new().green()),
|
||||
(item.interface, Style::new().green())]);
|
||||
}
|
||||
|
||||
table::println_table(out_list)
|
||||
}
|
||||
|
||||
pub fn console_device_list(mut list: Vec<DeviceItem>) {
|
||||
if list.is_empty() {
|
||||
println!("No other devices found");
|
||||
return;
|
||||
}
|
||||
list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip));
|
||||
list.sort_by(|t1, t2| t1.status.cmp(&t2.status));
|
||||
let mut out_list = Vec::with_capacity(list.len());
|
||||
//表头
|
||||
out_list.push(vec![("Name".to_string(), Style::new()),
|
||||
("Virtual Ip".to_string(), Style::new()),
|
||||
("Status".to_string(), Style::new()),
|
||||
("P2P/Relay".to_string(), Style::new()),
|
||||
("Rt".to_string(), Style::new())]);
|
||||
for item in list {
|
||||
if &item.status == "Online" {
|
||||
if item.client_secret != item.current_client_secret {
|
||||
//加密状态不一致,无法通信的
|
||||
out_list.push(vec![(item.name, Style::new().red()),
|
||||
(item.virtual_ip, Style::new().red()),
|
||||
(item.status, Style::new().red()),
|
||||
("".to_string(), Style::new().red()),
|
||||
("".to_string(), Style::new().red())]);
|
||||
} else {
|
||||
if &item.nat_traversal_type == "p2p" {
|
||||
out_list.push(vec![(item.name, Style::new().green()),
|
||||
(item.virtual_ip, Style::new().green()),
|
||||
(item.status, Style::new().green()),
|
||||
(item.nat_traversal_type, Style::new().green()),
|
||||
(item.rt, Style::new().green())]);
|
||||
} else {
|
||||
out_list.push(vec![(item.name, Style::new().yellow()),
|
||||
(item.virtual_ip, Style::new().yellow()),
|
||||
(item.status, Style::new().yellow()),
|
||||
(item.nat_traversal_type, Style::new().yellow()),
|
||||
(item.rt, Style::new().yellow())]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out_list.push(vec![(item.name, Style::new().color256(102)),
|
||||
(item.virtual_ip, Style::new().color256(102)),
|
||||
(item.status, Style::new().color256(102)),
|
||||
("".to_string(), Style::new().color256(102)),
|
||||
("".to_string(), Style::new().color256(102))]);
|
||||
}
|
||||
}
|
||||
table::println_table(out_list)
|
||||
}
|
||||
|
||||
pub fn console_device_list_all(mut list: Vec<DeviceItem>) {
|
||||
if list.is_empty() {
|
||||
println!("No other devices found");
|
||||
return;
|
||||
}
|
||||
list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip));
|
||||
list.sort_by(|t1, t2| t1.status.cmp(&t2.status));
|
||||
let mut out_list = Vec::with_capacity(list.len());
|
||||
//表头
|
||||
out_list.push(vec![("Name".to_string(), Style::new()),
|
||||
("Virtual Ip".to_string(), Style::new()),
|
||||
("Status".to_string(), Style::new()),
|
||||
("P2P/Relay".to_string(), Style::new()),
|
||||
("Rt".to_string(), Style::new()),
|
||||
("NAT Type".to_string(), Style::new()),
|
||||
("Public Ips".to_string(), Style::new()),
|
||||
("Local Ip".to_string(), Style::new())]);
|
||||
for item in list {
|
||||
if &item.status == "Online" {
|
||||
if &item.nat_traversal_type == "p2p" {
|
||||
out_list.push(vec![(item.name, Style::new().green()),
|
||||
(item.virtual_ip, Style::new().green()),
|
||||
(item.status, Style::new().green()),
|
||||
(item.nat_traversal_type, Style::new().green()),
|
||||
(item.rt, Style::new().green()),
|
||||
(item.nat_type, Style::new().green()),
|
||||
(item.public_ips, Style::new().green()),
|
||||
(item.local_ip, Style::new().green())]);
|
||||
} else {
|
||||
out_list.push(vec![(item.name, Style::new().yellow()),
|
||||
(item.virtual_ip, Style::new().yellow()),
|
||||
(item.status, Style::new().yellow()),
|
||||
(item.nat_traversal_type, Style::new().yellow()),
|
||||
(item.rt, Style::new().yellow()),
|
||||
(item.nat_type, Style::new().yellow()),
|
||||
(item.public_ips, Style::new().yellow()),
|
||||
(item.local_ip, Style::new().yellow()), ]);
|
||||
}
|
||||
} else {
|
||||
out_list.push(vec![(item.name, Style::new().color256(102)),
|
||||
(item.virtual_ip, Style::new().color256(102)),
|
||||
(item.status, Style::new().color256(102)),
|
||||
("".to_string(), Style::new().color256(102)),
|
||||
("".to_string(), Style::new().color256(102)),
|
||||
("".to_string(), Style::new().color256(102)),
|
||||
("".to_string(), Style::new().color256(102)),
|
||||
("".to_string(), Style::new().color256(102)), ]);
|
||||
}
|
||||
}
|
||||
table::println_table(out_list)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use console::Style;
|
||||
|
||||
pub fn println_table(table: Vec<Vec<(String, Style)>>) {
|
||||
if table.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut width_list = vec![0; table[0].len()];
|
||||
for in_list in table.iter() {
|
||||
for (index, (item, _)) in in_list.iter().enumerate() {
|
||||
let width = console::measure_text_width(item) + 4;
|
||||
if width_list[index] < width {
|
||||
width_list[index] = width;
|
||||
}
|
||||
}
|
||||
}
|
||||
for in_list in table {
|
||||
for (col, (item, style)) in in_list.iter().enumerate() {
|
||||
let str = format!("{:1$}", item, width_list[col]);
|
||||
print!("{}", style.apply_to(str));
|
||||
}
|
||||
println!()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use console::style;
|
||||
use getopts::Options;
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
use tokio::signal;
|
||||
#[cfg(unix)]
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
|
||||
use common::args_parse::{ips_parse, out_ips_parse};
|
||||
use vnt::cipher::CipherModel;
|
||||
use vnt::core::{Config, Vnt, VntUtil};
|
||||
use vnt::handle::handshake_handler::HandshakeEnum;
|
||||
use vnt::handle::registration_handler::ReqEnum;
|
||||
|
||||
mod command;
|
||||
mod console_out;
|
||||
mod root_check;
|
||||
|
||||
pub fn app_home() -> io::Result<PathBuf> {
|
||||
let path = dirs::home_dir().ok_or(io::Error::new(io::ErrorKind::Other, "not home"))?.join(".vnt-cli");
|
||||
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.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
|
||||
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
|
||||
opts.optopt("w", "", "客户端加密", "<password>");
|
||||
opts.optflag("W", "", "服务端加密");
|
||||
opts.optflag("m", "", "模拟组播");
|
||||
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
||||
opts.optflag("", "tcp", "tcp");
|
||||
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
|
||||
opts.optflag("", "relay", "仅使用服务器转发");
|
||||
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
|
||||
opts.optopt("", "thread", "线程数(必须为正整数)", "<thread>");
|
||||
opts.optopt("", "model", "加密模式", "<model>");
|
||||
//"后台运行时,查看其他设备列表"
|
||||
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());
|
||||
return;
|
||||
}
|
||||
};
|
||||
if matches.opt_present("h") || args.len() == 1 {
|
||||
print_usage(&program, opts);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if !matches.opt_present("k") {
|
||||
print_usage(&program, opts);
|
||||
println!("parameter -k not found .");
|
||||
return;
|
||||
}
|
||||
let tap = matches.opt_present("a");
|
||||
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() {
|
||||
if let Some(id) = common::identifier::get_unique_identifier() {
|
||||
id
|
||||
} else {
|
||||
let path_buf = app_home().unwrap().join("device-id");
|
||||
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
|
||||
}
|
||||
}
|
||||
} 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 server_address = match server_address_str.to_socket_addrs() {
|
||||
Ok(mut addr) => {
|
||||
if let Some(addr) = addr.next() {
|
||||
addr
|
||||
} else {
|
||||
println!("parameter -s error .");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("parameter -s error {}.", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
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 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 {}", 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 {}", 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");
|
||||
let simulate_multicast = matches.opt_present("m");
|
||||
let unused_cmd = matches.opt_present("c");
|
||||
let mtu: Option<String> = matches.opt_get("u").unwrap();
|
||||
let mtu = if let Some(mtu) = mtu {
|
||||
match u16::from_str(&mtu) {
|
||||
Ok(mtu) => {
|
||||
Some(mtu)
|
||||
}
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-u {}", 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("--ip error"));
|
||||
if let Some(virtual_ip) = virtual_ip {
|
||||
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast() {
|
||||
println!("--ip invalid");
|
||||
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");
|
||||
return;
|
||||
}
|
||||
let thread_num = matches.opt_get::<usize>("thread").unwrap().unwrap_or(std::thread::available_parallelism().unwrap().get() * 2);
|
||||
let cipher_model = matches.opt_get::<CipherModel>("model").unwrap().unwrap_or(CipherModel::AesGcm);
|
||||
if thread_num == 0 {
|
||||
println!("--thread invalid");
|
||||
return;
|
||||
}
|
||||
println!("version {}",vnt::VNT_VERSION);
|
||||
let config = Config::new(tap,
|
||||
token, device_id, name,
|
||||
server_address, server_address_str,
|
||||
stun_server, in_ip,
|
||||
out_ip, password, simulate_multicast, mtu,
|
||||
tcp_channel, virtual_ip, relay, server_encrypt, parallel, cipher_model);
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().worker_threads(thread_num).build().unwrap();
|
||||
runtime.block_on(main0(config, !unused_cmd));
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
async fn main0(config: Config, show_cmd: bool) {
|
||||
let server_encrypt = config.server_encrypt;
|
||||
let mut vnt_util = VntUtil::new(config).await.unwrap();
|
||||
let mut conn_count = 0;
|
||||
let response = loop {
|
||||
if conn_count > 0 {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
|
||||
}
|
||||
conn_count += 1;
|
||||
if let Err(e) = vnt_util.connect().await {
|
||||
println!("connect server failed {}", e);
|
||||
return;
|
||||
}
|
||||
match vnt_util.handshake().await {
|
||||
Ok(response) => {
|
||||
if server_encrypt {
|
||||
let finger = response.unwrap().finger().unwrap();
|
||||
println!("{}{}", green("server fingerprint:".to_string()), finger);
|
||||
match vnt_util.secret_handshake().await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
match e {
|
||||
HandshakeEnum::NotSecret => {}
|
||||
HandshakeEnum::KeyError => {}
|
||||
HandshakeEnum::Timeout => {
|
||||
println!("handshake timeout")
|
||||
}
|
||||
HandshakeEnum::ServerError(str) => {
|
||||
println!("error:{}", str);
|
||||
}
|
||||
HandshakeEnum::Other(str) => {
|
||||
println!("error:{}", str);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
match vnt_util.register().await {
|
||||
Ok(response) => {
|
||||
break response;
|
||||
}
|
||||
Err(e) => {
|
||||
match e {
|
||||
ReqEnum::TokenError => {
|
||||
println!("token error");
|
||||
return;
|
||||
}
|
||||
ReqEnum::AddressExhausted => {
|
||||
println!("address exhausted");
|
||||
return;
|
||||
}
|
||||
ReqEnum::Timeout => {
|
||||
println!("timeout...");
|
||||
}
|
||||
ReqEnum::ServerError(str) => {
|
||||
println!("error:{}", str);
|
||||
}
|
||||
ReqEnum::Other(str) => {
|
||||
println!("error:{}", str);
|
||||
}
|
||||
ReqEnum::IpAlreadyExists => {
|
||||
println!("ip already exists");
|
||||
return;
|
||||
}
|
||||
ReqEnum::InvalidIp => {
|
||||
println!("invalid ip");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
match e {
|
||||
HandshakeEnum::NotSecret => {
|
||||
println!("The server does not support encryption");
|
||||
return;
|
||||
}
|
||||
HandshakeEnum::KeyError => {}
|
||||
HandshakeEnum::Timeout => {
|
||||
println!("handshake timeout")
|
||||
}
|
||||
HandshakeEnum::ServerError(str) => {
|
||||
println!("error:{}", str);
|
||||
}
|
||||
HandshakeEnum::Other(str) => {
|
||||
println!("error:{}", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
println!(" ====== Connect Successfully ====== ");
|
||||
println!("virtual_gateway:{}", response.virtual_gateway);
|
||||
println!("virtual_ip:{}", green(response.virtual_ip.to_string()));
|
||||
let driver_info = vnt_util.create_iface().unwrap();
|
||||
println!(" ====== Create Network Interface Successfully ====== ");
|
||||
println!("name:{}", driver_info.name);
|
||||
println!("version:{}", driver_info.version);
|
||||
let mut vnt = match vnt_util.build().await {
|
||||
Ok(vnt) => {
|
||||
vnt
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error:{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
println!(" ====== Start Successfully ====== ");
|
||||
let vnt_c = vnt.clone();
|
||||
tokio::spawn(async {
|
||||
if let Err(e) = command::server::CommandServer::new().start(vnt_c).await {
|
||||
println!("command error :{}", e);
|
||||
}
|
||||
});
|
||||
if show_cmd {
|
||||
let stdin = tokio::io::stdin();
|
||||
let mut cmd = String::new();
|
||||
let mut reader = BufReader::new(stdin);
|
||||
#[cfg(unix)]
|
||||
let mut sigterm = signal(SignalKind::terminate()).expect("Error setting SIGTERM handler");
|
||||
loop {
|
||||
cmd.clear();
|
||||
println!("input:list,info,route,all,stop");
|
||||
#[cfg(unix)]
|
||||
tokio::select! {
|
||||
_ = vnt.wait_stop()=>{
|
||||
return;
|
||||
}
|
||||
_ = signal::ctrl_c()=>{
|
||||
let _ = vnt.stop();
|
||||
vnt.wait_stop_ms(std::time::Duration::from_secs(3)).await;
|
||||
return;
|
||||
}
|
||||
_ = sigterm.recv()=>{
|
||||
let _ = vnt.stop();
|
||||
vnt.wait_stop_ms(std::time::Duration::from_secs(3)).await;
|
||||
return;
|
||||
}
|
||||
rs = reader.read_line(&mut cmd)=>{
|
||||
match rs {
|
||||
Ok(len) => {
|
||||
if !command(&cmd[..len],&vnt){
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("input err:{}",e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
tokio::select! {
|
||||
_ = vnt.wait_stop()=>{
|
||||
return;
|
||||
}
|
||||
_ = signal::ctrl_c()=>{
|
||||
let _ = vnt.stop();
|
||||
vnt.wait_stop_ms(std::time::Duration::from_secs(3)).await;
|
||||
return;
|
||||
}
|
||||
rs = reader.read_line(&mut cmd)=>{
|
||||
match rs {
|
||||
Ok(len) => {
|
||||
if !command(&cmd[..len],&vnt){
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("input err:{}",e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(unix)]
|
||||
tokio::select! {
|
||||
_ = vnt.wait_stop()=>{
|
||||
return;
|
||||
}
|
||||
_ = signal::ctrl_c()=>{
|
||||
let _ = vnt.stop();
|
||||
vnt.wait_stop_ms(std::time::Duration::from_secs(3)).await;
|
||||
return;
|
||||
}
|
||||
_ = sigterm.recv()=>{
|
||||
let _ = vnt.stop();
|
||||
vnt.wait_stop_ms(std::time::Duration::from_secs(3)).await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
vnt.wait_stop().await;
|
||||
}
|
||||
|
||||
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!("Options:");
|
||||
println!(" -k <token> {}", green("必选,使用相同的token,就能组建一个局域网络".to_string()));
|
||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip");
|
||||
println!(" -c 关闭交互式命令,使用此参数禁用控制台输入");
|
||||
println!(" -s <server> 注册和中继服务器地址");
|
||||
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,可指定多个网段");
|
||||
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
|
||||
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
|
||||
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
|
||||
println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
|
||||
println!(" -u <mtu> 自定义mtu(不加密默认为1430,加密默认为1410)");
|
||||
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
|
||||
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
|
||||
println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p");
|
||||
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
|
||||
println!(" --thread <thread> 线程数(必须为正整数),默认为核心数乘2");
|
||||
println!(" --model <model> 加密模式,可选值 aes_gcm/aes_cbc,默认使用aes_gcm,通常情况使用aes_cbc性能更好");
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::is_app_elevated;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
mod unix;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub use unix::is_app_elevated;
|
||||
@@ -0,0 +1,3 @@
|
||||
pub fn is_app_elevated() -> bool {
|
||||
sudo::RunningAs::Root == sudo::check()
|
||||
}
|
||||
@@ -1,76 +1,76 @@
|
||||
/// 使用 https://github.com/spa5k/is_sudo/blob/main/src/window.rs
|
||||
use std::io::Error;
|
||||
use std::ptr;
|
||||
|
||||
use winapi::um::handleapi::CloseHandle;
|
||||
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
|
||||
use winapi::um::securitybaseapi::GetTokenInformation;
|
||||
use winapi::um::winnt::{HANDLE, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation};
|
||||
|
||||
// Use std::io::Error::last_os_error for errors.
|
||||
// NOTE: For this example I'm simple passing on the OS error.
|
||||
// However, customising the error could provide more context
|
||||
|
||||
/// Returns true if the current process has admin rights, otherwise false.
|
||||
pub fn is_app_elevated() -> bool {
|
||||
_is_app_elevated().unwrap_or(false)
|
||||
}
|
||||
|
||||
/// On success returns a bool indicating if the current process has admin rights.
|
||||
/// Otherwise returns an OS error.
|
||||
///
|
||||
/// This is unlikely to fail but if it does it's even more unlikely that you have admin permissions anyway.
|
||||
/// Therefore the public function above simply eats the error and returns a bool.
|
||||
fn _is_app_elevated() -> Result<bool, Error> {
|
||||
let token = QueryAccessToken::from_current_process()?;
|
||||
token.is_elevated()
|
||||
}
|
||||
|
||||
/// A safe wrapper around querying Windows access tokens.
|
||||
pub struct QueryAccessToken(HANDLE);
|
||||
|
||||
impl QueryAccessToken {
|
||||
pub fn from_current_process() -> Result<Self, Error> {
|
||||
unsafe {
|
||||
let mut handle: HANDLE = ptr::null_mut();
|
||||
let result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle);
|
||||
|
||||
if result != 0 {
|
||||
Ok(Self(handle))
|
||||
} else {
|
||||
Err(Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// On success returns a bool indicating if the access token has elevated privilidges.
|
||||
/// Otherwise returns an OS error.
|
||||
pub fn is_elevated(&self) -> Result<bool, Error> {
|
||||
unsafe {
|
||||
let mut elevation = TOKEN_ELEVATION::default();
|
||||
let size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
||||
let mut ret_size = size;
|
||||
// The weird looking repetition of `as *mut _` is casting the reference to a c_void pointer.
|
||||
if GetTokenInformation(
|
||||
self.0,
|
||||
TokenElevation,
|
||||
&mut elevation as *mut _ as *mut _,
|
||||
size,
|
||||
&mut ret_size,
|
||||
) != 0
|
||||
{
|
||||
Ok(elevation.TokenIsElevated != 0)
|
||||
} else {
|
||||
Err(Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for QueryAccessToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { CloseHandle(self.0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
/// 使用 https://github.com/spa5k/is_sudo/blob/main/src/window.rs
|
||||
use std::io::Error;
|
||||
use std::ptr;
|
||||
|
||||
use winapi::um::handleapi::CloseHandle;
|
||||
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
|
||||
use winapi::um::securitybaseapi::GetTokenInformation;
|
||||
use winapi::um::winnt::{TokenElevation, HANDLE, TOKEN_ELEVATION, TOKEN_QUERY};
|
||||
|
||||
// Use std::io::Error::last_os_error for errors.
|
||||
// NOTE: For this example I'm simple passing on the OS error.
|
||||
// However, customising the error could provide more context
|
||||
|
||||
/// Returns true if the current process has admin rights, otherwise false.
|
||||
pub fn is_app_elevated() -> bool {
|
||||
_is_app_elevated().unwrap_or(false)
|
||||
}
|
||||
|
||||
/// On success returns a bool indicating if the current process has admin rights.
|
||||
/// Otherwise returns an OS error.
|
||||
///
|
||||
/// This is unlikely to fail but if it does it's even more unlikely that you have admin permissions anyway.
|
||||
/// Therefore the public function above simply eats the error and returns a bool.
|
||||
fn _is_app_elevated() -> Result<bool, Error> {
|
||||
let token = QueryAccessToken::from_current_process()?;
|
||||
token.is_elevated()
|
||||
}
|
||||
|
||||
/// A safe wrapper around querying Windows access tokens.
|
||||
pub struct QueryAccessToken(HANDLE);
|
||||
|
||||
impl QueryAccessToken {
|
||||
pub fn from_current_process() -> Result<Self, Error> {
|
||||
unsafe {
|
||||
let mut handle: HANDLE = ptr::null_mut();
|
||||
let result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle);
|
||||
|
||||
if result != 0 {
|
||||
Ok(Self(handle))
|
||||
} else {
|
||||
Err(Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// On success returns a bool indicating if the access token has elevated privilidges.
|
||||
/// Otherwise returns an OS error.
|
||||
pub fn is_elevated(&self) -> Result<bool, Error> {
|
||||
unsafe {
|
||||
let mut elevation = TOKEN_ELEVATION::default();
|
||||
let size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
||||
let mut ret_size = size;
|
||||
// The weird looking repetition of `as *mut _` is casting the reference to a c_void pointer.
|
||||
if GetTokenInformation(
|
||||
self.0,
|
||||
TokenElevation,
|
||||
&mut elevation as *mut _ as *mut _,
|
||||
size,
|
||||
&mut ret_size,
|
||||
) != 0
|
||||
{
|
||||
Ok(elevation.TokenIsElevated != 0)
|
||||
} else {
|
||||
Err(Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for QueryAccessToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { CloseHandle(self.0) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "vnt-jni"
|
||||
version = "1.2.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vnt = {path="../vnt"}
|
||||
|
||||
jni = { version = "0.21.1", default-features = false }
|
||||
[lib]
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
@@ -0,0 +1 @@
|
||||
## 提供给安卓端使用
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod vnt_util;
|
||||
pub mod vnt;
|
||||
@@ -0,0 +1,138 @@
|
||||
use std::ptr;
|
||||
use jni::errors::Error;
|
||||
use jni::JNIEnv;
|
||||
use jni::objects::{JClass, JObject, JValue};
|
||||
use jni::sys::{jboolean, jbyte, jint, jlong, jobject, jobjectArray, jsize};
|
||||
use vnt::channel::Route;
|
||||
use vnt::core::sync::VntSync;
|
||||
use vnt::handle::PeerDeviceInfo;
|
||||
|
||||
#[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 VntSync;
|
||||
let _ = (&*vnt).stop();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitStop0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) {
|
||||
let vnt = raw_vnt as *mut VntSync;
|
||||
let _ = (&mut *vnt).wait_stop();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitStopMs0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
ms: jlong,
|
||||
) -> jboolean {
|
||||
let vnt = raw_vnt as *mut VntSync;
|
||||
if (&mut *vnt).wait_stop_ms(ms as _) {
|
||||
jni::sys::JNI_TRUE
|
||||
} else {
|
||||
jni::sys::JNI_FALSE
|
||||
}
|
||||
}
|
||||
|
||||
#[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 VntSync;
|
||||
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 VntSync;
|
||||
let vnt = &mut *vnt;
|
||||
let list = vnt.device_list();
|
||||
|
||||
let arr = match env.new_object_array(
|
||||
list.len() as jsize,
|
||||
"top/wherewego/vnt/jni/PeerDeviceInfo",
|
||||
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 address = route.addr.to_string();
|
||||
let metric = route.metric;
|
||||
let rt = route.rt;
|
||||
let rs = env.new_object(
|
||||
"top/wherewego/vnt/jni/Route",
|
||||
"(Ljava/lang/String;BI)V",
|
||||
&[JValue::Object(&env.new_string(address)?.into()),
|
||||
JValue::Byte(metric as jbyte),
|
||||
JValue::Int(rt as jint)],
|
||||
)?;
|
||||
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/PeerDeviceInfo",
|
||||
"(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())
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::ptr;
|
||||
|
||||
use jni::errors::Error;
|
||||
use jni::objects::{JClass, JObject, JString, JValue};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use jni::sys::jboolean;
|
||||
use jni::sys::{jint, jlong, jobject};
|
||||
use jni::JNIEnv;
|
||||
use vnt::cipher::CipherModel;
|
||||
use vnt::core::Config;
|
||||
use vnt::core::sync::VntUtilSync;
|
||||
use vnt::handle::registration_handler::{RegResponse, ReqEnum};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use vnt::tun_tap_device::DriverInfo;
|
||||
|
||||
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("Ljava/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("Ljava/lang/RuntimeException", "not utf-8")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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("Ljava/lang/RuntimeException", "not utf-8")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<VntUtilSync, Error> {
|
||||
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 nat_test_server = to_string_not_null(env, &config, "natTestServer")?;
|
||||
let server_address = match server_address_str.to_socket_addrs() {
|
||||
Ok(mut rs) => {
|
||||
if let Some(addr) = rs.next() {
|
||||
addr
|
||||
} else {
|
||||
env.throw_new("Ljava/lang/RuntimeException", "server address err")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("Ljava/lang/RuntimeException", format!("server address {}", e))
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
};
|
||||
let mut stun_server = Vec::new();
|
||||
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 config = Config::new(false,
|
||||
token, device_id, name,
|
||||
server_address, server_address_str,
|
||||
stun_server, vec![],
|
||||
vec![], password, false, None, false, None, false,false,1,CipherModel::AesGcm);
|
||||
match VntUtilSync::new(config) {
|
||||
Ok(vnt_util) => {
|
||||
Ok(vnt_util)
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("Ljava/lang/RuntimeException", format!("vnt start error {}", e))
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_new0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
config: JObject,
|
||||
) -> jlong {
|
||||
match new_sync(&mut env, config) {
|
||||
Ok(vnt_util) => {
|
||||
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_VntUtil_connect0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
) {
|
||||
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
|
||||
match (&mut *raw_vnt_util).connect() {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt connect error {}", e))
|
||||
.expect("throw");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_register0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
) -> jobject {
|
||||
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
|
||||
match (&mut *raw_vnt_util).register() {
|
||||
Ok(response) => {
|
||||
match reg_response(&mut env, response) {
|
||||
Ok(res) => {
|
||||
return res;
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw(format!("vnt register error {}", e)).expect("throw");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
match e {
|
||||
ReqEnum::TokenError => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/TokenErrorException", "TokenError")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::AddressExhausted => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/AddressExhaustedException", "AddressExhausted")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::Timeout => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/TimeoutException", "Timeout")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::ServerError(str) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt register error {}", str))
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::Other(str) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt register error {}", str))
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::IpAlreadyExists => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/IpAlreadyExistsException", "IpAlreadyExists")
|
||||
.expect("throw");
|
||||
}
|
||||
ReqEnum::InvalidIp => {
|
||||
env.throw_new("top/wherewego/vnt/jni/exception/InvalidIpException", "InvalidIp")
|
||||
.expect("throw");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_createIface0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
fd: jint,
|
||||
) {
|
||||
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
|
||||
|
||||
(&mut *raw_vnt_util).create_iface(fd as i32);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_createIface0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
) -> jobject {
|
||||
let raw_vnt_util = raw_vnt_util as *mut VntUtilSync;
|
||||
let rs = (&mut *raw_vnt_util).create_iface();
|
||||
match rs {
|
||||
Ok(driver_info) => {
|
||||
match driver_info_e(&mut env, driver_info) {
|
||||
Ok(res) => {
|
||||
return res;
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw(format!("vnt create iface error {}", e)).expect("throw");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt create iface error {}", e))
|
||||
.expect("throw");
|
||||
}
|
||||
}
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_VntUtil_build0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt_util: jlong,
|
||||
) -> jlong {
|
||||
let raw_vnt_util = Box::from_raw(raw_vnt_util as *mut VntUtilSync);
|
||||
match raw_vnt_util.build() {
|
||||
Ok(rs) => {
|
||||
return Box::into_raw(Box::new(rs)) as jlong;
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("vnt start error:{:?}", e))
|
||||
.expect("throw");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn reg_response(env: &mut JNIEnv, response: RegResponse) -> Result<jobject, Error> {
|
||||
let virtual_ip = u32::from(response.virtual_ip);
|
||||
let virtual_gateway = u32::from(response.virtual_gateway);
|
||||
let virtual_netmask = u32::from(response.virtual_netmask);
|
||||
let response = env.new_object(
|
||||
"top/wherewego/vnt/jni/RegResponse",
|
||||
"(III)V",
|
||||
&[JValue::Int(virtual_ip as jint),
|
||||
JValue::Int(virtual_gateway as jint),
|
||||
JValue::Int(virtual_netmask as jint)],
|
||||
)?;
|
||||
Ok(response.into_raw())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn driver_info_e(env: &mut JNIEnv, driver_info: DriverInfo) -> Result<jobject, Error> {
|
||||
let is_tun = driver_info.device_type.is_tun();
|
||||
let name = driver_info.name;
|
||||
let version = driver_info.version;
|
||||
let mac = driver_info.mac.unwrap_or(String::new());
|
||||
let response = env.new_object(
|
||||
"top/wherewego/vnt/jni/DriverInfo",
|
||||
"(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
|
||||
&[JValue::Bool(is_tun as jboolean),
|
||||
JValue::Object(&env.new_string(name)?.into()),
|
||||
JValue::Object(&env.new_string(version)?.into()),
|
||||
JValue::Object(&env.new_string(mac)?.into()), ],
|
||||
)?;
|
||||
Ok(response.into_raw())
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
[package]
|
||||
name = "vnt"
|
||||
version = "1.2.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
packet = { path = "./packet" }
|
||||
bytes = "1.3.0"
|
||||
log = "0.4.17"
|
||||
libc = "0.2.137"
|
||||
crossbeam-utils = "0.8"
|
||||
dashmap = "5.5.1"
|
||||
parking_lot = "0.12.1"
|
||||
byte-pool = "0.2.4"
|
||||
lazy_static = "1.4.0"
|
||||
rand = "0.8.5"
|
||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||
thiserror = "1.0.37"
|
||||
protobuf = "3.2.0"
|
||||
socket2 ={ version = "0.5.2", features = ["all"] }
|
||||
tokio = { version = "1.28.1", features = ["full"] }
|
||||
aes-gcm = {version="0.10.2", optional = true}
|
||||
ring = {version="0.16.20", optional = true}
|
||||
cbc = "0.1.2"
|
||||
aes = "0.8.3"
|
||||
stun-format = {version="1.0.1",features=["fmt","rfc3489"]}
|
||||
rsa = {version="0.7.2", features = [] }
|
||||
spki = {version="0.6.0",features=["fingerprint","alloc"]}
|
||||
|
||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
tun = { path = "./rust-tun" }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
|
||||
win-tun-tap = {path = "./win-tun-tap"}
|
||||
libloading = "0.7.4"
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen = "3.2.0"
|
||||
protoc-bin-vendored = "3.0.0"
|
||||
|
||||
[features]
|
||||
default=["aes-gcm"]
|
||||
ring-cipher=["ring"]
|
||||
|
||||
|
||||
@@ -7,4 +7,3 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
thiserror = "1.0.37"
|
||||
@@ -0,0 +1,122 @@
|
||||
use std::{fmt, io};
|
||||
|
||||
/// 地址解析协议,由IP地址找到MAC地址
|
||||
/// https://www.ietf.org/rfc/rfc6747.txt
|
||||
/*
|
||||
0 2 4 5 6 8 10 (字节)
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 硬件类型|协议类型|硬件地址长度|协议地址长度|操作类型|
|
||||
| 源MAC地址 | 源ip地址 |
|
||||
| 目的MAC地址 | 目的ip地址 |
|
||||
*/
|
||||
|
||||
pub struct ArpPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ArpPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() != 28 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ArpPacket<B> {
|
||||
/// 硬件类型 以太网类型为1
|
||||
pub fn hardware_type(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
|
||||
}
|
||||
/// 上层协议类型,ipv4是0x0800
|
||||
pub fn protocol_type(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
/// 如果是MAC地址 则长度为6
|
||||
pub fn hardware_size(&self) -> u8 {
|
||||
self.buffer.as_ref()[4]
|
||||
}
|
||||
/// 如果是IPv4 则长度为4
|
||||
pub fn protocol_size(&self) -> u8 {
|
||||
self.buffer.as_ref()[5]
|
||||
}
|
||||
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应
|
||||
pub fn op_code(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
|
||||
}
|
||||
/// 发送端硬件地址,仅支持以太网
|
||||
pub fn sender_hardware_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[8..14]
|
||||
}
|
||||
/// 发送端协议地址,仅支持IPv4
|
||||
pub fn sender_protocol_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[14..18]
|
||||
}
|
||||
/// 接收端硬件地址,仅支持以太网
|
||||
pub fn target_hardware_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[18..24]
|
||||
}
|
||||
/// 接收端协议地址,仅支持IPv4
|
||||
pub fn target_protocol_addr(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[24..28]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> ArpPacket<B> {
|
||||
/// 硬件类型 以太网类型为1
|
||||
pub fn set_hardware_type(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
/// 上层协议类型,ipv4是0x0800
|
||||
pub fn set_protocol_type(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
/// 如果是MAC地址 则长度为6
|
||||
pub fn set_hardware_size(&mut self, value: u8) {
|
||||
self.buffer.as_mut()[4] = value
|
||||
}
|
||||
/// 如果是IPv4 则长度为4
|
||||
pub fn set_protocol_size(&mut self, value: u8) {
|
||||
self.buffer.as_mut()[5] = value
|
||||
}
|
||||
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应
|
||||
pub fn set_op_code(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
/// 发送端硬件地址,仅支持以太网
|
||||
pub fn set_sender_hardware_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[8..14].copy_from_slice(buf)
|
||||
}
|
||||
/// 发送端协议地址,仅支持IPv4
|
||||
pub fn set_sender_protocol_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[14..18].copy_from_slice(buf)
|
||||
}
|
||||
/// 接收端硬件地址,仅支持以太网
|
||||
pub fn set_target_hardware_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[18..24].copy_from_slice(buf)
|
||||
}
|
||||
/// 接收端协议地址,仅支持IPv4
|
||||
pub fn set_target_protocol_addr(&mut self, buf: &[u8]) {
|
||||
self.buffer.as_mut()[24..28].copy_from_slice(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for ArpPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ArpPacket")
|
||||
.field("hardware_type", &self.hardware_type())
|
||||
.field("protocol_type", &self.protocol_type())
|
||||
.field("hardware_size", &self.hardware_size())
|
||||
.field("protocol_size", &self.protocol_size())
|
||||
.field("op_code", &self.op_code())
|
||||
.field("sender_hardware_addr", &self.sender_hardware_addr())
|
||||
.field("sender_protocol_addr", &self.sender_protocol_addr())
|
||||
.field("target_hardware_addr", &self.target_hardware_addr())
|
||||
.field("target_protocol_addr", &self.target_protocol_addr())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod arp;
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod packet;
|
||||
pub mod protocol;
|
||||
@@ -0,0 +1,77 @@
|
||||
use std::{fmt, io};
|
||||
use crate::ethernet::protocol::Protocol;
|
||||
|
||||
/// 以太网帧协议
|
||||
/// https://www.ietf.org/rfc/rfc894.txt
|
||||
/*
|
||||
0 6 12 14 (字节)
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 目的地址 | 源地址 | 类型 |
|
||||
*/
|
||||
pub struct EthernetPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> EthernetPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> EthernetPacket<B> {
|
||||
EthernetPacket { buffer }
|
||||
}
|
||||
|
||||
pub fn new(buffer: B) -> io::Result<EthernetPacket<B>> {
|
||||
let packet = EthernetPacket::unchecked(buffer);
|
||||
//头部固定14位
|
||||
if packet.buffer.as_ref().len() < 14 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> EthernetPacket<B> {
|
||||
/// 目的MAC地址
|
||||
pub fn destination(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[0..6]
|
||||
}
|
||||
/// 源MAC地址
|
||||
pub fn source(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[6..12]
|
||||
}
|
||||
/// 3层协议
|
||||
pub fn protocol(&self) -> Protocol {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[12..14].try_into().unwrap()).into()
|
||||
}
|
||||
/// 载荷
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[14..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> EthernetPacket<B> {
|
||||
pub fn set_destination(&mut self, value: &[u8]) {
|
||||
self.buffer.as_mut()[0..6].copy_from_slice(value);
|
||||
}
|
||||
|
||||
pub fn set_source(&mut self, value: &[u8]) {
|
||||
self.buffer.as_mut()[6..12].copy_from_slice(value);
|
||||
}
|
||||
|
||||
pub fn set_protocol(&mut self, value: Protocol) {
|
||||
let p: u16 = value.into();
|
||||
self.buffer.as_mut()[12..14].copy_from_slice(&p.to_be_bytes())
|
||||
}
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[14..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for EthernetPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("EthernetPacket")
|
||||
.field("destination", &self.destination())
|
||||
.field("source", &self.source())
|
||||
.field("protocol", &self.protocol())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/// 以太网帧协议
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
///
|
||||
Ipv4,
|
||||
|
||||
///
|
||||
Arp,
|
||||
|
||||
///
|
||||
WakeOnLan,
|
||||
|
||||
///
|
||||
Trill,
|
||||
|
||||
///
|
||||
DecNet,
|
||||
|
||||
///
|
||||
Rarp,
|
||||
|
||||
///
|
||||
AppleTalk,
|
||||
|
||||
///
|
||||
Aarp,
|
||||
|
||||
///
|
||||
Ipx,
|
||||
|
||||
///
|
||||
Qnx,
|
||||
|
||||
///
|
||||
Ipv6,
|
||||
|
||||
///
|
||||
FlowControl,
|
||||
|
||||
///
|
||||
CobraNet,
|
||||
|
||||
///
|
||||
Mpls,
|
||||
|
||||
///
|
||||
MplsMulticast,
|
||||
|
||||
///
|
||||
PppoeDiscovery,
|
||||
|
||||
///
|
||||
PppoeSession,
|
||||
|
||||
///
|
||||
Vlan,
|
||||
|
||||
///
|
||||
PBridge,
|
||||
|
||||
///
|
||||
Lldp,
|
||||
|
||||
///
|
||||
Ptp,
|
||||
|
||||
///
|
||||
Cfm,
|
||||
|
||||
///
|
||||
QinQ,
|
||||
|
||||
///
|
||||
Unknown(u16),
|
||||
}
|
||||
|
||||
impl From<u16> for Protocol {
|
||||
fn from(value: u16) -> Protocol {
|
||||
use self::Protocol::*;
|
||||
|
||||
match value {
|
||||
0x0800 => Ipv4,
|
||||
0x0806 => Arp,
|
||||
0x0842 => WakeOnLan,
|
||||
0x22f3 => Trill,
|
||||
0x6003 => DecNet,
|
||||
0x8035 => Rarp,
|
||||
0x809b => AppleTalk,
|
||||
0x80f3 => Aarp,
|
||||
0x8137 => Ipx,
|
||||
0x8204 => Qnx,
|
||||
0x86dd => Ipv6,
|
||||
0x8808 => FlowControl,
|
||||
0x8819 => CobraNet,
|
||||
0x8847 => Mpls,
|
||||
0x8848 => MplsMulticast,
|
||||
0x8863 => PppoeDiscovery,
|
||||
0x8864 => PppoeSession,
|
||||
0x8100 => Vlan,
|
||||
0x88a8 => PBridge,
|
||||
0x88cc => Lldp,
|
||||
0x88f7 => Ptp,
|
||||
0x8902 => Cfm,
|
||||
0x9100 => QinQ,
|
||||
n => Unknown(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u16> for Protocol {
|
||||
fn into(self) -> u16 {
|
||||
use self::Protocol::*;
|
||||
|
||||
match self {
|
||||
Ipv4 => 0x0800,
|
||||
Arp => 0x0806,
|
||||
WakeOnLan => 0x0842,
|
||||
Trill => 0x22f3,
|
||||
DecNet => 0x6003,
|
||||
Rarp => 0x8035,
|
||||
AppleTalk => 0x809b,
|
||||
Aarp => 0x80f3,
|
||||
Ipx => 0x8137,
|
||||
Qnx => 0x8204,
|
||||
Ipv6 => 0x86dd,
|
||||
FlowControl => 0x8808,
|
||||
CobraNet => 0x8819,
|
||||
Mpls => 0x8847,
|
||||
MplsMulticast => 0x8848,
|
||||
PppoeDiscovery => 0x8863,
|
||||
PppoeSession => 0x8864,
|
||||
Vlan => 0x8100,
|
||||
PBridge => 0x88a8,
|
||||
Lldp => 0x88cc,
|
||||
Ptp => 0x88f7,
|
||||
Cfm => 0x8902,
|
||||
QinQ => 0x9100,
|
||||
Unknown(n) => n,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::fmt;
|
||||
|
||||
use std::{fmt, io};
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
|
||||
use crate::cal_checksum;
|
||||
use crate::error::*;
|
||||
use crate::icmp::{Code, Kind};
|
||||
use crate::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
/// icmp 协议
|
||||
/* https://www.rfc-editor.org/rfc/rfc792
|
||||
0 1 2 3
|
||||
@@ -17,20 +17,18 @@ use crate::error::*;
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
*/
|
||||
use crate::icmp::{Code, Kind};
|
||||
use crate::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
pub struct IcmpPacket<B> {
|
||||
buffer: B,
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> Result<Self> {
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
@@ -56,9 +54,7 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
Code::from(self.kind(), self.buffer.as_ref()[1])
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[2..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
@@ -71,12 +67,8 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
| Kind::TimestampReply
|
||||
| Kind::InformationRequest
|
||||
| Kind::InformationReply => {
|
||||
let ide = (&self.buffer.as_ref()[4..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap();
|
||||
let seq = (&self.buffer.as_ref()[6..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap();
|
||||
let ide =u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap());
|
||||
let seq = u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap());
|
||||
HeaderOther::Identifier(ide, seq)
|
||||
}
|
||||
Kind::DestinationUnreachable | Kind::TimeExceeded | Kind::SourceQuench => {
|
||||
@@ -110,6 +102,7 @@ impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||
},
|
||||
Kind::TimestampRequest | Kind::TimestampReply => {
|
||||
let mut buffer = Cursor::new(self.payload());
|
||||
|
||||
Description::Timestamp(
|
||||
buffer.read_u32::<BigEndian>().unwrap(),
|
||||
buffer.read_u32::<BigEndian>().unwrap(),
|
||||
@@ -128,11 +121,11 @@ impl<B: AsRef<[u8]>> fmt::Debug for IcmpPacket<B> {
|
||||
} else {
|
||||
"icmp::Packet!"
|
||||
})
|
||||
.field("kind", &self.kind())
|
||||
.field("code", &self.code())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
.field("kind", &self.kind())
|
||||
.field("code", &self.code())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::cal_checksum;
|
||||
|
||||
/// igmp v1
|
||||
/* https://datatracker.ietf.org/doc/html/rfc1112
|
||||
0 1 2 3
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|Version| Type | Unused | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Group Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
/// v1版本的报文
|
||||
pub struct IgmpV1Packet<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV1Type {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x12
|
||||
ReportV1,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV1Type {
|
||||
fn from(value: u8) -> IgmpV1Type {
|
||||
use self::IgmpV1Type::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x12 => ReportV1,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV1Type {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpV1Type::Query => 0x11,
|
||||
IgmpV1Type::ReportV1 => 0x12,
|
||||
IgmpV1Type::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV1Packet<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() != 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV1Packet<B> {
|
||||
pub fn version(&self) -> u8 {
|
||||
self.buffer.as_ref()[0] >> 4
|
||||
}
|
||||
pub fn igmp_type(&self) -> IgmpV1Type {
|
||||
IgmpV1Type::from(self.buffer.as_ref()[0] & 0x0F)
|
||||
}
|
||||
pub fn unused(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn group_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV1Packet<B> {
|
||||
pub fn set_version(&mut self, version: u8) {
|
||||
self.buffer.as_mut()[0] = (version << 4) | 0x0F & self.buffer.as_mut()[0]
|
||||
}
|
||||
pub fn set_type(&mut self, igmp_type: IgmpV1Type) {
|
||||
let t: u8 = igmp_type.into();
|
||||
self.buffer.as_mut()[0] = self.buffer.as_mut()[0] & 0xF0 | t
|
||||
}
|
||||
pub fn set_checksum(&mut self, checksum: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
|
||||
}
|
||||
pub fn update_checksum(&mut self) {
|
||||
self.set_checksum(0);
|
||||
self.set_checksum(cal_checksum(self.buffer.as_ref()));
|
||||
}
|
||||
pub fn set_group_address(&mut self, group_address: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets());
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV1Packet<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V1")
|
||||
.field("version", &self.version())
|
||||
.field("type", &self.igmp_type())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("group_address", &self.group_address())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::cal_checksum;
|
||||
|
||||
/// igmp v2
|
||||
/* https://www.rfc-editor.org/rfc/rfc2236.html
|
||||
|
||||
0 1 2 3
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Max Resp Time | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Group Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
/// v2版本的报文
|
||||
pub struct IgmpV2Packet<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV2Type {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x16
|
||||
ReportV2,
|
||||
LeaveV2,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV2Type {
|
||||
fn from(value: u8) -> IgmpV2Type {
|
||||
use self::IgmpV2Type::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x16 => ReportV2,
|
||||
0x17 => LeaveV2,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV2Type {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpV2Type::Query => 0x11,
|
||||
IgmpV2Type::ReportV2 => 0x16,
|
||||
IgmpV2Type::LeaveV2 => 0x17,
|
||||
IgmpV2Type::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV2Packet<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() != 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV2Packet<B> {
|
||||
pub fn igmp_type(&self) -> IgmpV2Type {
|
||||
IgmpV2Type::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn max_resp_time(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn group_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV2Packet<B> {
|
||||
pub fn set_type(&mut self, igmp_type: IgmpV2Type) {
|
||||
self.buffer.as_mut()[0] = igmp_type.into()
|
||||
}
|
||||
pub fn set_max_resp_time(&mut self, resp: u8) {
|
||||
self.buffer.as_mut()[1] = resp
|
||||
}
|
||||
pub fn set_checksum(&mut self, checksum: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes());
|
||||
}
|
||||
pub fn update_checksum(&mut self) {
|
||||
self.set_checksum(0);
|
||||
self.set_checksum(cal_checksum(self.buffer.as_ref()));
|
||||
}
|
||||
pub fn set_group_address(&mut self, group_address: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets());
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV2Packet<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V2")
|
||||
.field("type", &self.igmp_type())
|
||||
.field("max_resp_time", &self.max_resp_time())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("group_address", &self.group_address())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::cal_checksum;
|
||||
|
||||
/// igmp v3
|
||||
/* https://www.rfc-editor.org/rfc/rfc3376
|
||||
Query:
|
||||
0 1 2 3
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 0x11 | Max Resp Code | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Group Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Resv |S| QRV | QQIC | Number of Sources (N) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source Address [1] |
|
||||
+- -+
|
||||
| Source Address [2] |
|
||||
+- . -+
|
||||
. . .
|
||||
. . .
|
||||
+- -+
|
||||
| Source Address [N] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Report:
|
||||
0 1 2 3
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type = 0x22 | Reserved | Checksum |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Reserved | Number of Group Records (M) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Group Record [1] .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Group Record [2] .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| . |
|
||||
. . .
|
||||
| . |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Group Record [M] .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Group Record:
|
||||
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Record Type | Aux Data Len | Number of Sources (N) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Multicast Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Source Address [1] |
|
||||
+- -+
|
||||
| Source Address [2] |
|
||||
+- -+
|
||||
. . .
|
||||
. . .
|
||||
. . .
|
||||
+- -+
|
||||
| Source Address [N] |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. .
|
||||
. Auxiliary Data .
|
||||
. .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Record Type:
|
||||
1 MODE_IS_INCLUDE 表示主机希望加入指定组播组并指定了一个或多个源地址
|
||||
2 MODE_IS_EXCLUDE 表示主机希望加入指定组播组但排除了一个或多个源地址
|
||||
3 CHANGE_TO_INCLUDE_MODE 表示主机正在将组播组的过滤模式从排除切换为包括,指定了一个或多个源地址
|
||||
4 CHANGE_TO_EXCLUDE_MODE 表示主机正在将组播组的过滤模式从包括切换为排除,指定了一个或多个源地址
|
||||
5 ALLOW_NEW_SOURCES 表示主机希望在已有的源地址列表中添加新的源地址,指定了一个或多个源地址
|
||||
6 BLOCK_OLD_SOURCES 表示主机希望在已有的源地址列表中删除旧的源地址,指定了一个或多个源地址
|
||||
*/
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV3Type {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x22
|
||||
ReportV3,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV3Type {
|
||||
fn from(value: u8) -> IgmpV3Type {
|
||||
use self::IgmpV3Type::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x22 => ReportV3,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV3Type {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpV3Type::Query => 0x11,
|
||||
IgmpV3Type::ReportV3 => 0x22,
|
||||
IgmpV3Type::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum IgmpV3RecordType {
|
||||
//1 MODE_IS_INCLUDE 表示主机希望加入指定组播组并指定了一个或多个源地址
|
||||
ModeIsInclude,
|
||||
//2 MODE_IS_EXCLUDE 表示主机希望加入指定组播组但排除了一个或多个源地址
|
||||
ModeIsExclude,
|
||||
//3 CHANGE_TO_INCLUDE_MODE 表示主机正在将组播组的过滤模式从排除切换为包括,指定了一个或多个源地址
|
||||
ChangeToIncludeMode,
|
||||
//4 CHANGE_TO_EXCLUDE_MODE 表示主机正在将组播组的过滤模式从包括切换为排除,指定了一个或多个源地址
|
||||
ChangeToExcludeMode,
|
||||
//5 ALLOW_NEW_SOURCES 表示主机希望在已有的源地址列表中添加新的源地址,指定了一个或多个源地址
|
||||
AllowNewSources,
|
||||
//6 BLOCK_OLD_SOURCES 表示主机希望在已有的源地址列表中删除旧的源地址,指定了一个或多个源地址
|
||||
BlockOldSources,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpV3RecordType {
|
||||
fn from(value: u8) -> IgmpV3RecordType {
|
||||
use self::IgmpV3RecordType::*;
|
||||
|
||||
match value {
|
||||
1 => ModeIsInclude,
|
||||
2 => ModeIsExclude,
|
||||
3 => ChangeToIncludeMode,
|
||||
4 => ChangeToExcludeMode,
|
||||
5 => AllowNewSources,
|
||||
6 => BlockOldSources,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpV3RecordType {
|
||||
fn into(self) -> u8 {
|
||||
use self::IgmpV3RecordType::*;
|
||||
|
||||
match self {
|
||||
ModeIsInclude => 1,
|
||||
ModeIsExclude => 2,
|
||||
ChangeToIncludeMode => 3,
|
||||
ChangeToExcludeMode => 4,
|
||||
AllowNewSources => 5,
|
||||
BlockOldSources => 6,
|
||||
Unknown(v) => v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// v3版本的query报文
|
||||
pub struct IgmpV3QueryPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3QueryPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 12 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> IgmpV3QueryPacket<B> {
|
||||
pub fn set_igmp_type(&mut self) {
|
||||
self.buffer.as_mut()[0] = IgmpV3Type::Query.into();
|
||||
}
|
||||
pub fn set_max_resp_code(&mut self, code: u8) {
|
||||
self.buffer.as_mut()[1] = code;
|
||||
}
|
||||
pub fn set_group_address(&mut self, addr: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&addr.octets())
|
||||
}
|
||||
pub fn set_checksum(&mut self, checksum: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes())
|
||||
}
|
||||
pub fn set_qrv(&mut self, qrv: u8) {
|
||||
self.buffer.as_mut()[8] = (self.buffer.as_ref()[8]&(!0x07)) | (qrv & 0x07)
|
||||
}
|
||||
pub fn set_qqic(&mut self, qqic: u8) {
|
||||
self.buffer.as_mut()[9] = qqic
|
||||
}
|
||||
|
||||
pub fn update_checksum(&mut self) {
|
||||
self.set_checksum(0);
|
||||
let checksum = cal_checksum(self.buffer.as_ref());
|
||||
self.set_checksum(checksum);
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3QueryPacket<B> {
|
||||
pub fn igmp_type(&self) -> IgmpV3Type {
|
||||
IgmpV3Type::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn max_resp_code(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn group_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
/// 保留字段,设置为0
|
||||
pub fn resv(&self) -> u8 {
|
||||
self.buffer.as_ref()[8] >> 4
|
||||
}
|
||||
/// 标志位
|
||||
/// 该比特位为1时,所有收到此查询报文的其他路由器不启动定时器刷新过程,但是此查询报文并不抑制查询者选举过程和路由器的主机侧处理过程;默认未置位。
|
||||
pub fn s(&self) -> u8 {
|
||||
(self.buffer.as_ref()[8] & 0x0F) >> 3
|
||||
}
|
||||
/// 查询者向网络通告的健壮系数
|
||||
/// 此参数可使查询者使用自己的健壮系统同步其他组播路由器的健壮系数;
|
||||
/// 其他路由器接收到查询报文时,如果发现该字段非0,则将自己的健壮系数调整为该字段的值;如果发现该字段为0,则不做处理。默认健壮系数值为2。
|
||||
pub fn qrv(&self) -> u8 {
|
||||
self.buffer.as_ref()[8] & 0x07
|
||||
}
|
||||
/// IGMP查询者的查询间隔
|
||||
/// 非查询者收到查询报文时,如果发现该字段非0,则将自己的查询间隔参数调整为该字段的值:如果发现该字段为0,则不做处理。默认值为60。
|
||||
pub fn qqic(&self) -> u8 {
|
||||
self.buffer.as_ref()[9]
|
||||
}
|
||||
/// 报文中包含的组播源的数量
|
||||
/// 对于普遍组查询报文和特定组查询报文,该字段为0;对于特定源组查询报文,该字段非0
|
||||
pub fn source_number(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[10..12].try_into().unwrap())
|
||||
}
|
||||
pub fn source_addresses(&self) -> Option<Vec<Ipv4Addr>> {
|
||||
let num = self.source_number();
|
||||
if num == 0 {
|
||||
None
|
||||
} else {
|
||||
let num = num as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
for index in 0..num {
|
||||
let start = (12 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
|
||||
list.push(Ipv4Addr::from(tmp));
|
||||
}
|
||||
Some(list)
|
||||
}
|
||||
}
|
||||
pub fn source_address(&self, index: u16) -> Option<Ipv4Addr> {
|
||||
if self.source_number() >= index {
|
||||
None
|
||||
} else {
|
||||
let start = (12 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
|
||||
Some(Ipv4Addr::from(tmp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// v3版本的query报文
|
||||
pub struct IgmpV3ReportPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3ReportPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3ReportPacket<B> {
|
||||
pub fn igmp_type(&self) -> IgmpV3Type {
|
||||
IgmpV3Type::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
pub fn reserved1(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0
|
||||
}
|
||||
pub fn reserved2(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||
}
|
||||
pub fn record_number(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
|
||||
}
|
||||
pub fn group_records(&self) -> Option<Vec<IgmpV3RecordPacket<&[u8]>>> {
|
||||
let num = self.record_number();
|
||||
if num == 0 {
|
||||
None
|
||||
} else {
|
||||
let num = num as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let mut start = 8 as usize;
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
for _ in 0..num {
|
||||
if start >= len {
|
||||
return None;
|
||||
}
|
||||
if let Ok(record) = IgmpV3RecordPacket::new(&buf[start..]) {
|
||||
let end = start + 8 + record.aux_data_len() as usize * 4 + record.source_number() as usize * 4;
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
list.push(IgmpV3RecordPacket::new(&buf[start..end]).unwrap());
|
||||
start = end;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// group record
|
||||
pub struct IgmpV3RecordPacket<B> {
|
||||
pub buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3RecordPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))
|
||||
} else {
|
||||
let packet = Self::unchecked(buffer);
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IgmpV3RecordPacket<B> {
|
||||
pub fn record_type(&self) -> IgmpV3RecordType {
|
||||
IgmpV3RecordType::from(self.buffer.as_ref()[0])
|
||||
}
|
||||
/// 辅助数据长度 以4字节为单位
|
||||
pub fn aux_data_len(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
/// 源地址数
|
||||
pub fn source_number(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
///多播地址
|
||||
pub fn multicast_address(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn source_addresses(&self) -> Option<Vec<Ipv4Addr>> {
|
||||
let num = self.source_number();
|
||||
if num == 0 {
|
||||
None
|
||||
} else {
|
||||
let num = num as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let buf = self.buffer.as_ref();
|
||||
let len = buf.len();
|
||||
for index in 0..num {
|
||||
let start = (8 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
if end > len {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = buf[start..end].try_into().unwrap();
|
||||
list.push(Ipv4Addr::from(tmp));
|
||||
}
|
||||
Some(list)
|
||||
}
|
||||
}
|
||||
pub fn source_address(&self, index: u16) -> Option<Ipv4Addr> {
|
||||
if self.source_number() >= index {
|
||||
None
|
||||
} else {
|
||||
let start = (8 + index * 4) as usize;
|
||||
let end = start + 4;
|
||||
if end > self.buffer.as_ref().len() {
|
||||
return None;
|
||||
}
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[start..end].try_into().unwrap();
|
||||
Some(Ipv4Addr::from(tmp))
|
||||
}
|
||||
}
|
||||
/// 在文档中没有定义辅助数据的作用,通常应该是空的
|
||||
pub fn auxiliary_data(&self) -> &[u8] {
|
||||
let start = 8 + self.source_number() as usize * 4;
|
||||
let end = start + self.aux_data_len() as usize * 4;
|
||||
if end > self.buffer.as_ref().len() {
|
||||
return &[];
|
||||
}
|
||||
&self.buffer.as_ref()[start..end]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3QueryPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V3Query")
|
||||
.field("type", &self.igmp_type())
|
||||
.field("max_resp_code", &self.max_resp_code())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("group_address", &self.group_address())
|
||||
.field("s", &self.s())
|
||||
.field("qrv", &self.qrv())
|
||||
.field("qqic", &self.qqic())
|
||||
.field("number of sources", &self.source_number())
|
||||
.field("source_addresses", &self.source_addresses())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3ReportPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V3Report")
|
||||
.field("type", &self.igmp_type())
|
||||
.field("reserved1", &self.reserved1())
|
||||
.field("checksum", &self.checksum())
|
||||
.field("is_valid", &self.is_valid())
|
||||
.field("reserved2", &self.reserved2())
|
||||
.field("record_number", &self.record_number())
|
||||
.field("group_records", &self.group_records())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for IgmpV3RecordPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("igmp::V3Record")
|
||||
.field("record_type", &self.record_type())
|
||||
.field("aux_data_len", &self.aux_data_len())
|
||||
.field("source_number", &self.source_number())
|
||||
.field("multicast_address", &self.multicast_address())
|
||||
.field("source_addresses", &self.source_addresses())
|
||||
.field("auxiliary_data", &self.auxiliary_data())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
pub mod igmp_v1;
|
||||
pub mod igmp_v2;
|
||||
pub mod igmp_v3;
|
||||
|
||||
#[derive(Debug,Copy, Clone,Eq, PartialEq)]
|
||||
pub enum IgmpType {
|
||||
/// 0x11 所有组224.0.0.1或者特定组
|
||||
Query,
|
||||
/// 0x12
|
||||
ReportV1,
|
||||
/// 0x16
|
||||
ReportV2,
|
||||
/// 0x22
|
||||
ReportV3,
|
||||
/// 0x17 目标组固定是 224.0.0.2
|
||||
LeaveV2,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for IgmpType {
|
||||
fn from(value: u8) -> IgmpType {
|
||||
use self::IgmpType::*;
|
||||
|
||||
match value {
|
||||
0x11 => Query,
|
||||
0x12 => ReportV1,
|
||||
0x16 => ReportV2,
|
||||
0x22 => ReportV3,
|
||||
0x17 => LeaveV2,
|
||||
v => Unknown(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for IgmpType {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
IgmpType::Query => 0x11,
|
||||
IgmpType::ReportV1 => 0x12,
|
||||
IgmpType::ReportV2 => 0x16,
|
||||
IgmpType::ReportV3 => 0x22,
|
||||
IgmpType::LeaveV2 => 0x17,
|
||||
IgmpType::Unknown(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
use std::fmt;
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
|
||||
use crate::cal_checksum;
|
||||
use crate::error::*;
|
||||
use crate::ip::ipv4::protocol::Protocol;
|
||||
|
||||
/// ip协议
|
||||
@@ -39,16 +37,16 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> Result<Self> {
|
||||
if buffer.as_ref()[0] >> 4 != 4 {
|
||||
Err(Error::Unimplemented)?
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
if buffer.as_ref().len() < 20 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "len < 20"))?;
|
||||
}
|
||||
if buffer.as_ref()[0] >> 4 != 4 {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "not ipv4"))?;
|
||||
}
|
||||
let packet = Self::unchecked(buffer);
|
||||
if packet.buffer.as_ref().len() < packet.header_len() as usize * 4 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, "head_len err"))?;
|
||||
}
|
||||
Ok(packet)
|
||||
}
|
||||
@@ -60,17 +58,6 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[(self.header_len() as usize * 4)..]
|
||||
// match self.protocol() {
|
||||
// Protocol::Udp => {
|
||||
// let udp = UdpPacket::new(IpAddr::V4(self.source_ip()),
|
||||
// IpAddr::V4(self.destination_ip()),
|
||||
// &self.buffer.as_ref()[(self.header_len() as usize * 4)..])?;
|
||||
// Ok(crate::IpUpperLayer::UDP(udp))
|
||||
// }
|
||||
// _ => {
|
||||
// Ok(crate::IpUpperLayer::Unknown(self.buffer.as_ref()));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,13 +70,18 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> IpV4Packet<B> {
|
||||
let len = self.header_len() as usize * 4;
|
||||
&mut self.buffer.as_mut()[len..]
|
||||
}
|
||||
|
||||
pub fn set_protocol(&mut self, value: Protocol) {
|
||||
self.header_mut()[9] = value.into();
|
||||
}
|
||||
pub fn set_source_ip(&mut self, value: Ipv4Addr) {
|
||||
self.header_mut()[12..16].copy_from_slice(&value.octets());
|
||||
}
|
||||
pub fn set_destination_ip(&mut self, value: Ipv4Addr) {
|
||||
self.header_mut()[16..20].copy_from_slice(&value.octets());
|
||||
}
|
||||
pub fn set_flags(&mut self, flags: u8) {
|
||||
self.buffer.as_mut()[6] = (self.buffer.as_ref()[6] & 0b11100000) | (flags << 5)
|
||||
}
|
||||
fn set_checksum(&mut self, value: u16) {
|
||||
self.header_mut()[10..12].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
@@ -141,16 +133,12 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
||||
|
||||
/// ip报总字节数
|
||||
pub fn length(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[2..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
|
||||
/// 标识. ip报文在数据链路层可能会被拆分,同一报文的不同分组标识字段相同
|
||||
pub fn id(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[4..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||
}
|
||||
|
||||
/// 标志 3位.
|
||||
@@ -170,10 +158,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
||||
/// 以字节为单位,用于指明分段起始点相对于包头起始点的偏移量
|
||||
/// 由于分段到达时可能错序,所以分段的偏移字段可以使接收者按照正确的顺序重组数据包
|
||||
pub fn offset(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[6..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
& 0x1fff
|
||||
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap()) & 0x1fff
|
||||
}
|
||||
|
||||
/// 生存时间.
|
||||
@@ -189,9 +174,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
||||
|
||||
/// 首部校验和
|
||||
pub fn checksum(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[10..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[10..12].try_into().unwrap())
|
||||
}
|
||||
/// 验证校验和
|
||||
///
|
||||
@@ -1,4 +1,4 @@
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
#[derive(Eq, PartialEq,Ord, PartialOrd, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
///
|
||||
Hopopt,
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::io;
|
||||
use ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
pub mod ipv4;
|
||||
|
||||
pub enum IpPacket<B> {
|
||||
@@ -9,10 +8,10 @@ pub enum IpPacket<B> {
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> IpPacket<B> {
|
||||
pub fn new(buffer: B) -> Result<Self> {
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
match buffer.as_ref()[0] >> 4 {
|
||||
4 => Ok(IpPacket::V4(IpV4Packet::new(buffer)?)),
|
||||
_ => Err(Error::InvalidPacket),
|
||||
_ => Err(io::Error::from(io::ErrorKind::InvalidData)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,13 @@ use std::net::Ipv4Addr;
|
||||
use byteorder::BigEndian;
|
||||
use byteorder::ReadBytesExt;
|
||||
|
||||
pub mod error;
|
||||
pub mod icmp;
|
||||
pub mod igmp;
|
||||
pub mod ip;
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
|
||||
pub mod ethernet;
|
||||
pub mod arp;
|
||||
// pub enum IpUpperLayer<B> {
|
||||
// UDP(UdpPacket<B>),
|
||||
// Unknown(B),
|
||||
@@ -102,9 +103,9 @@ pub fn ipv4_cal_checksum(
|
||||
src_ip: &Ipv4Addr,
|
||||
dest_ip: &Ipv4Addr,
|
||||
protocol: u8,
|
||||
length: u16,
|
||||
) -> u16 {
|
||||
use std::io::Cursor;
|
||||
let length = buffer.len();
|
||||
let mut sum = 0;
|
||||
let src_ip = src_ip.octets();
|
||||
sum += u32c(src_ip[0], src_ip[1]);
|
||||
@@ -133,7 +134,6 @@ fn u32c(x: u8, y: u8) -> u32 {
|
||||
((x as u32) << 8) | y as u32
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1,9 +1,6 @@
|
||||
use std::fmt;
|
||||
use std::net::IpAddr;
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
|
||||
use crate::error::*;
|
||||
use crate::tcp::Flags;
|
||||
|
||||
/// tcp
|
||||
@@ -48,59 +45,69 @@ use crate::tcp::Flags;
|
||||
Options+Padding:32位整数倍,最多40个字节
|
||||
*/
|
||||
pub struct TcpPacket<B> {
|
||||
source_ip: IpAddr,
|
||||
destination_ip: IpAddr,
|
||||
source_ip: Ipv4Addr,
|
||||
destination_ip: Ipv4Addr,
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> TcpPacket<B> {
|
||||
pub fn unchecked(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> TcpPacket<B> {
|
||||
TcpPacket {
|
||||
source_ip,
|
||||
destination_ip,
|
||||
buffer,
|
||||
}
|
||||
}
|
||||
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<TcpPacket<B>> {
|
||||
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> io::Result<TcpPacket<B>> {
|
||||
let packet = TcpPacket::unchecked(source_ip, destination_ip, buffer);
|
||||
|
||||
if packet.buffer.as_ref().len() < 20 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
|
||||
if packet.buffer.as_ref().len() < packet.data_offset() as usize * 4 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> TcpPacket<B> {
|
||||
fn set_checksum(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[16..18].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
pub fn set_source_port(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
pub fn set_destination_port(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
/// 更新校验和
|
||||
pub fn update_checksum(&mut self) {
|
||||
//先将校验和置0
|
||||
self.set_checksum(0);
|
||||
self.set_checksum(self.cal_checksum())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||
/// 源端口
|
||||
pub fn source_port(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[0..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
|
||||
}
|
||||
|
||||
/// 目标端口
|
||||
pub fn destination_port(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[2..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
/// 序列号
|
||||
pub fn sequence(&self) -> u32 {
|
||||
(&self.buffer.as_ref()[4..])
|
||||
.read_u32::<BigEndian>()
|
||||
.unwrap()
|
||||
u32::from_be_bytes(self.buffer.as_ref()[4..8].try_into().unwrap())
|
||||
}
|
||||
/// 确认号
|
||||
pub fn acknowledgment(&self) -> u32 {
|
||||
(&self.buffer.as_ref()[8..])
|
||||
.read_u32::<BigEndian>()
|
||||
.unwrap()
|
||||
u32::from_be_bytes(self.buffer.as_ref()[8..12].try_into().unwrap())
|
||||
}
|
||||
/// 数据偏移 4字节为单位
|
||||
pub fn data_offset(&self) -> u8 {
|
||||
@@ -110,14 +117,10 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||
Flags(self.buffer.as_ref()[13])
|
||||
}
|
||||
pub fn window(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[14..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[14..16].try_into().unwrap())
|
||||
}
|
||||
pub fn checksum(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[16..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[16..18].try_into().unwrap())
|
||||
}
|
||||
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
|
||||
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
|
||||
@@ -126,26 +129,15 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||
self.checksum() == 0 || self.cal_checksum() == 0
|
||||
}
|
||||
fn cal_checksum(&self) -> u16 {
|
||||
match self.source_ip {
|
||||
IpAddr::V4(src) => {
|
||||
if let IpAddr::V4(dest) = self.destination_ip {
|
||||
return crate::ipv4_cal_checksum(
|
||||
self.buffer.as_ref(),
|
||||
&src,
|
||||
&dest,
|
||||
6,
|
||||
self.buffer.as_ref().len() as u16,
|
||||
);
|
||||
}
|
||||
}
|
||||
IpAddr::V6(_src) => {}
|
||||
}
|
||||
unimplemented!()
|
||||
crate::ipv4_cal_checksum(
|
||||
self.buffer.as_ref(),
|
||||
&self.source_ip,
|
||||
&self.destination_ip,
|
||||
6,
|
||||
)
|
||||
}
|
||||
pub fn urgent_pointer(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[18..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[18..20].try_into().unwrap())
|
||||
}
|
||||
pub fn options(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[20..(self.data_offset() as usize * 4)]
|
||||
@@ -1 +1 @@
|
||||
pub mod udp;
|
||||
pub mod udp;
|
||||
@@ -1,11 +1,5 @@
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::net::IpAddr;
|
||||
|
||||
use byteorder::WriteBytesExt;
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
|
||||
use crate::error::*;
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
/// udp协议
|
||||
///
|
||||
@@ -53,22 +47,22 @@ RFC 768 https://www.ietf.org/rfc/rfc768.txt
|
||||
*/
|
||||
|
||||
pub struct UdpPacket<B> {
|
||||
source_ip: IpAddr,
|
||||
destination_ip: IpAddr,
|
||||
source_ip: Ipv4Addr,
|
||||
destination_ip: Ipv4Addr,
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> UdpPacket<B> {
|
||||
pub fn unchecked(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> UdpPacket<B> {
|
||||
UdpPacket {
|
||||
source_ip,
|
||||
destination_ip,
|
||||
buffer,
|
||||
}
|
||||
}
|
||||
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<UdpPacket<B>> {
|
||||
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> io::Result<UdpPacket<B>> {
|
||||
if buffer.as_ref().len() < 8 {
|
||||
Err(Error::SmallBuffer)?
|
||||
Err(io::Error::from(io::ErrorKind::InvalidData))?;
|
||||
}
|
||||
let packet = Self::unchecked(source_ip, destination_ip, buffer);
|
||||
Ok(packet)
|
||||
@@ -78,30 +72,22 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||
impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||
/// 源端口
|
||||
pub fn source_port(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[0..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
|
||||
}
|
||||
|
||||
/// 目标端口
|
||||
pub fn destination_port(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[2..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
|
||||
/// 总字节数
|
||||
pub fn length(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[4..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||
}
|
||||
|
||||
/// Checksum of the packet.
|
||||
pub fn checksum(&self) -> u16 {
|
||||
(&self.buffer.as_ref()[6..])
|
||||
.read_u16::<BigEndian>()
|
||||
.unwrap()
|
||||
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
|
||||
}
|
||||
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
|
||||
pub fn is_valid(&self) -> bool {
|
||||
@@ -111,55 +97,38 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||
&self.buffer.as_ref()[8..]
|
||||
}
|
||||
fn cal_checksum(&self) -> u16 {
|
||||
match self.source_ip {
|
||||
IpAddr::V4(src) => {
|
||||
if let IpAddr::V4(dest) = self.destination_ip {
|
||||
return crate::ipv4_cal_checksum(
|
||||
self.buffer.as_ref(),
|
||||
&src,
|
||||
&dest,
|
||||
17,
|
||||
self.length(),
|
||||
);
|
||||
}
|
||||
}
|
||||
IpAddr::V6(_src) => {}
|
||||
}
|
||||
unimplemented!()
|
||||
crate::ipv4_cal_checksum(
|
||||
self.buffer.as_ref(),
|
||||
&self.source_ip,
|
||||
&self.destination_ip,
|
||||
17,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||
fn header_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[..8]
|
||||
}
|
||||
}
|
||||
// impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||
// fn header_mut(&mut self) -> &mut [u8] {
|
||||
// &mut self.buffer.as_mut()[..8]
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||
/// 设置源端口
|
||||
pub fn set_source_port(&mut self, value: u16) -> &mut Self {
|
||||
Cursor::new(&mut self.header_mut()[0..])
|
||||
.write_u16::<BigEndian>(value)
|
||||
.unwrap();
|
||||
self
|
||||
pub fn set_source_port(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
|
||||
/// 设置目的端口
|
||||
pub fn set_destination_port(&mut self, value: u16) -> &mut Self {
|
||||
Cursor::new(&mut self.header_mut()[2..])
|
||||
.write_u16::<BigEndian>(value)
|
||||
.unwrap();
|
||||
self
|
||||
pub fn set_destination_port(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
fn set_checknum(&mut self, value: u16) {
|
||||
Cursor::new(&mut self.header_mut()[6..])
|
||||
.write_u16::<BigEndian>(value)
|
||||
.unwrap();
|
||||
fn set_checksum(&mut self, value: u16) {
|
||||
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
|
||||
}
|
||||
pub fn update_checknum(&mut self) {
|
||||
pub fn update_checksum(&mut self) {
|
||||
//先写0
|
||||
self.set_checknum(0);
|
||||
self.set_checknum(self.cal_checksum());
|
||||
self.set_checksum(0);
|
||||
self.set_checksum(self.cal_checksum());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
syntax = "proto3";
|
||||
message HandshakeRequest{
|
||||
string version = 1;
|
||||
bool secret = 2;
|
||||
}
|
||||
message HandshakeResponse{
|
||||
string version = 1;
|
||||
bool secret = 2;
|
||||
bytes public_key = 3;
|
||||
string key_finger = 4;
|
||||
}
|
||||
message SecretHandshakeRequest{
|
||||
string token = 1;
|
||||
bytes key = 2;
|
||||
}
|
||||
message RegistrationRequest{
|
||||
string token = 1;
|
||||
string device_id = 2;
|
||||
string name = 3;
|
||||
bool is_fast = 4;
|
||||
string version = 5;
|
||||
fixed32 virtual_ip = 6;
|
||||
bool allow_ip_change = 7;
|
||||
bool client_secret = 8;
|
||||
}
|
||||
|
||||
message RegistrationResponse{
|
||||
fixed32 virtual_ip = 1;
|
||||
fixed32 virtual_gateway = 2;
|
||||
fixed32 virtual_netmask = 3;
|
||||
uint32 epoch = 4;
|
||||
repeated DeviceInfo device_info_list = 5;
|
||||
fixed32 public_ip = 6;
|
||||
uint32 public_port = 7;
|
||||
bytes public_ipv6 = 8;
|
||||
}
|
||||
message DeviceInfo{
|
||||
string name = 1;
|
||||
fixed32 virtual_ip = 2;
|
||||
uint32 device_status = 3;
|
||||
bool client_secret = 4;
|
||||
}
|
||||
|
||||
message DeviceList{
|
||||
uint32 epoch = 1;
|
||||
repeated DeviceInfo device_info_list = 2;
|
||||
}
|
||||
|
||||
message PunchInfo{
|
||||
repeated fixed32 public_ip_list = 2;
|
||||
uint32 public_port = 3;
|
||||
uint32 public_port_range = 4;
|
||||
PunchNatType nat_type = 5;
|
||||
bool reply = 6;
|
||||
fixed32 local_ip = 7;
|
||||
uint32 local_port = 8;
|
||||
repeated bytes public_ipv6_list = 9;
|
||||
}
|
||||
enum PunchNatType{
|
||||
Symmetric = 0;
|
||||
Cone = 1;
|
||||
}
|
||||
@@ -15,31 +15,11 @@ libc = "0.2"
|
||||
thiserror = "1"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "android"))'.dependencies]
|
||||
tokio = { version = "1", features = ["net", "macros"], optional = true }
|
||||
tokio-util = { version = "0.6", features = ["codec"], optional = true }
|
||||
bytes = { version = "1", optional = true }
|
||||
byteorder = { version = "1", optional = true }
|
||||
# This is only for the `ready` macro.
|
||||
futures-core = { version = "0.3", optional = true }
|
||||
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||
ioctl = { version = "0.6", package = "ioctl-sys" }
|
||||
|
||||
[dev-dependencies]
|
||||
packet = "0.1"
|
||||
futures = "0.3"
|
||||
|
||||
[features]
|
||||
async = ["tokio", "tokio-util", "bytes", "byteorder", "futures-core"]
|
||||
|
||||
[[example]]
|
||||
name = "read-async"
|
||||
required-features = [ "async", "tokio/rt-multi-thread" ]
|
||||
|
||||
[[example]]
|
||||
name = "read-async-codec"
|
||||
required-features = [ "async", "tokio/rt-multi-thread" ]
|
||||
|
||||
[[example]]
|
||||
name = "ping-tun"
|
||||
required-features = [ "async", "tokio/rt-multi-thread" ]
|
||||
@@ -12,15 +12,14 @@
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::io::{Read, Write};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::error::*;
|
||||
|
||||
/// A TUN device.
|
||||
pub trait Device: Read + Write {
|
||||
type Queue: Read + Write;
|
||||
pub trait Device {
|
||||
type Queue ;
|
||||
|
||||
/// Reconfigure the device.
|
||||
fn configure(&mut self, config: &Configuration) -> Result<()> {
|
||||
@@ -91,5 +90,5 @@ pub trait Device: Read + Write {
|
||||
fn set_mtu(&mut self, value: i32) -> Result<()>;
|
||||
|
||||
/// Get a device queue.
|
||||
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue>;
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue>;
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
#![cfg(unix)]
|
||||
mod error;
|
||||
pub use crate::error::*;
|
||||
|
||||
@@ -27,27 +27,6 @@ pub use crate::configuration::{Configuration, Layer};
|
||||
pub mod platform;
|
||||
pub use crate::platform::create;
|
||||
|
||||
#[cfg(all(
|
||||
feature = "async",
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "android"
|
||||
)
|
||||
))]
|
||||
pub mod r#async;
|
||||
#[cfg(all(
|
||||
feature = "async",
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "android"
|
||||
)
|
||||
))]
|
||||
pub use r#async::*;
|
||||
|
||||
pub fn configure() -> Configuration {
|
||||
Configuration::default()
|
||||
}
|
||||
+43
-116
@@ -13,10 +13,10 @@
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::vec::Vec;
|
||||
@@ -92,7 +92,7 @@ impl Device {
|
||||
}
|
||||
|
||||
queues.push(Queue {
|
||||
tun,
|
||||
tun: Arc::new(tun),
|
||||
pi_enabled: config.platform.packet_information,
|
||||
});
|
||||
}
|
||||
@@ -126,45 +126,40 @@ impl Device {
|
||||
req
|
||||
}
|
||||
|
||||
/// Make the device persistent.
|
||||
pub fn persist(&mut self) -> Result<()> {
|
||||
unsafe {
|
||||
if tunsetpersist(self.as_raw_fd(), &1) < 0 {
|
||||
Err(io::Error::last_os_error().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
// /// Make the device persistent.
|
||||
// pub fn persist(&mut self) -> Result<()> {
|
||||
// unsafe {
|
||||
// if tunsetpersist(self.as_raw_fd(), &1) < 0 {
|
||||
// Err(io::Error::last_os_error().into())
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Set the owner of the device.
|
||||
pub fn user(&mut self, value: i32) -> Result<()> {
|
||||
unsafe {
|
||||
if tunsetowner(self.as_raw_fd(), &value) < 0 {
|
||||
Err(io::Error::last_os_error().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the group of the device.
|
||||
pub fn group(&mut self, value: i32) -> Result<()> {
|
||||
unsafe {
|
||||
if tunsetgroup(self.as_raw_fd(), &value) < 0 {
|
||||
Err(io::Error::last_os_error().into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn split(mut self) -> (posix::Reader, posix::Writer) {
|
||||
let queue = self.queues.swap_remove(0);
|
||||
let fd = Arc::new(queue.tun);
|
||||
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
|
||||
}
|
||||
// /// Set the owner of the device.
|
||||
// pub fn user(&mut self, value: i32) -> Result<()> {
|
||||
// unsafe {
|
||||
// if tunsetowner(self.as_raw_fd(), &value) < 0 {
|
||||
// Err(io::Error::last_os_error().into())
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /// Set the group of the device.
|
||||
// pub fn group(&mut self, value: i32) -> Result<()> {
|
||||
// unsafe {
|
||||
// if tunsetgroup(self.as_raw_fd(), &value) < 0 {
|
||||
// Err(io::Error::last_os_error().into())
|
||||
// } else {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
/// Return whether the device has packet information
|
||||
pub fn has_packet_information(&mut self) -> bool {
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.queues[0].has_packet_information()
|
||||
}
|
||||
|
||||
@@ -174,30 +169,6 @@ impl Device {
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Device {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.queues[0].read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.queues[0].read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Device {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.queues[0].write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.queues[0].flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.queues[0].write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl D for Device {
|
||||
type Queue = Queue;
|
||||
|
||||
@@ -377,73 +348,29 @@ impl D for Device {
|
||||
}
|
||||
}
|
||||
|
||||
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
|
||||
self.queues.get_mut(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Device {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.queues[0].as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Device {
|
||||
fn into_raw_fd(mut self) -> RawFd {
|
||||
// It is Ok to swap the first queue with the last one, because the self will be dropped afterwards
|
||||
let queue = self.queues.swap_remove(0);
|
||||
queue.into_raw_fd()
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue> {
|
||||
self.queues.get(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Queue {
|
||||
tun: Fd,
|
||||
tun: Arc<Fd>,
|
||||
pi_enabled: bool,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
pub fn has_packet_information(&mut self) -> bool {
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
self.pi_enabled
|
||||
}
|
||||
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.tun.set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Queue {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.tun.read(buf)
|
||||
pub fn reader(&self) -> posix::Reader {
|
||||
posix::Reader(self.tun.clone())
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.tun.read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Queue {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.tun.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.tun.flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.tun.write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Queue {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.tun.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Queue {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.tun.into_raw_fd()
|
||||
pub fn writer(&self) -> posix::Writer {
|
||||
posix::Writer(self.tun.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use libc;
|
||||
use libc::{c_char, c_uint, c_void, sockaddr, socklen_t, AF_INET, SOCK_DGRAM};
|
||||
use libc::{AF_INET, c_char, c_uint, c_void, SOCK_DGRAM, sockaddr, socklen_t};
|
||||
|
||||
use crate::configuration::{Configuration, Layer};
|
||||
use crate::device::Device as D;
|
||||
@@ -121,7 +121,7 @@ impl Device {
|
||||
name: CStr::from_ptr(name.as_ptr() as *const c_char)
|
||||
.to_string_lossy()
|
||||
.into(),
|
||||
queue: Queue { tun: tun },
|
||||
queue: Queue { tun: Arc::new(tun) },
|
||||
ctl: ctl,
|
||||
}
|
||||
};
|
||||
@@ -165,11 +165,11 @@ impl Device {
|
||||
}
|
||||
}
|
||||
|
||||
/// Split the interface into a `Reader` and `Writer`.
|
||||
pub fn split(self) -> (posix::Reader, posix::Writer) {
|
||||
let fd = Arc::new(self.queue.tun);
|
||||
(posix::Reader(fd.clone()), posix::Writer(fd.clone()))
|
||||
}
|
||||
// /// Split the interface into a `Reader` and `Writer`.
|
||||
// pub fn split(self) -> (posix::Reader, posix::Writer) {
|
||||
// let fd = Arc::new(self.queue.tun);
|
||||
// (posix::Reader(fd.clone()), posix::Writer(fd.clone()))
|
||||
// }
|
||||
|
||||
/// Return whether the device has packet information
|
||||
pub fn has_packet_information(&self) -> bool {
|
||||
@@ -182,29 +182,29 @@ impl Device {
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for Device {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.queue.tun.read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.queue.tun.read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Device {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.queue.tun.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.queue.tun.flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.queue.tun.write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
// impl Read for Device {
|
||||
// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// self.queue.tun.read(buf)
|
||||
// }
|
||||
//
|
||||
// fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
// self.queue.tun.read_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Write for Device {
|
||||
// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// self.queue.tun.write(buf)
|
||||
// }
|
||||
//
|
||||
// fn flush(&mut self) -> io::Result<()> {
|
||||
// self.queue.tun.flush()
|
||||
// }
|
||||
//
|
||||
// fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
// self.queue.tun.write_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl D for Device {
|
||||
type Queue = Queue;
|
||||
@@ -365,29 +365,29 @@ impl D for Device {
|
||||
}
|
||||
}
|
||||
|
||||
fn queue(&mut self, index: usize) -> Option<&mut Self::Queue> {
|
||||
fn queue(&self, index: usize) -> Option<&Self::Queue> {
|
||||
if index > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&mut self.queue)
|
||||
Some(&self.queue)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Device {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.queue.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Device {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.queue.into_raw_fd()
|
||||
}
|
||||
}
|
||||
// impl AsRawFd for Device {
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// self.queue.as_raw_fd()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl IntoRawFd for Device {
|
||||
// fn into_raw_fd(self) -> RawFd {
|
||||
// self.queue.into_raw_fd()
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct Queue {
|
||||
tun: Fd,
|
||||
tun: Arc<Fd>,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
@@ -399,40 +399,47 @@ impl Queue {
|
||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
||||
self.tun.set_nonblock()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Queue {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.tun.as_raw_fd()
|
||||
pub fn reader(&self) -> posix::Reader {
|
||||
posix::Reader(self.tun.clone())
|
||||
}
|
||||
pub fn writer(&self) -> posix::Writer {
|
||||
posix::Writer(self.tun.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Queue {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.tun.into_raw_fd()
|
||||
}
|
||||
}
|
||||
// impl AsRawFd for Queue {
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// self.tun.as_raw_fd()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl IntoRawFd for Queue {
|
||||
// fn into_raw_fd(self) -> RawFd {
|
||||
// self.tun.into_raw_fd()
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Read for Queue {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.tun.read(buf)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.tun.read_vectored(bufs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Queue {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.tun.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.tun.flush()
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.tun.write_vectored(bufs)
|
||||
}
|
||||
}
|
||||
// impl Read for Queue {
|
||||
// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// self.tun.read(buf)
|
||||
// }
|
||||
//
|
||||
// fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
// self.tun.read_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Write for Queue {
|
||||
// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
// self.tun.write(buf)
|
||||
// }
|
||||
//
|
||||
// fn flush(&mut self) -> io::Result<()> {
|
||||
// self.tun.flush()
|
||||
// }
|
||||
//
|
||||
// fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
// self.tun.write_vectored(bufs)
|
||||
// }
|
||||
// }
|
||||
@@ -27,15 +27,6 @@ pub mod macos;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use self::macos::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
pub mod ios;
|
||||
#[cfg(target_os = "ios")]
|
||||
pub use self::ios::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod android;
|
||||
#[cfg(target_os = "android")]
|
||||
pub use self::android::{create, Configuration, Device, Queue};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
@@ -12,22 +12,24 @@
|
||||
//
|
||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::os::unix::io::{AsRawFd,RawFd};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::platform::posix::Fd;
|
||||
use libc;
|
||||
|
||||
/// Read-only end for a file descriptor.
|
||||
#[derive(Clone)]
|
||||
pub struct Reader(pub(crate) Arc<Fd>);
|
||||
|
||||
/// Write-only end for a file descriptor.
|
||||
#[derive(Clone)]
|
||||
pub struct Writer(pub(crate) Arc<Fd>);
|
||||
|
||||
impl Read for Reader {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
impl Reader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::read(self.0.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len());
|
||||
|
||||
@@ -39,7 +41,7 @@ impl Read for Reader {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
pub fn read_vectored(&self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let mut msg: libc::msghdr = mem::zeroed();
|
||||
// msg.msg_name: NULL
|
||||
@@ -57,8 +59,8 @@ impl Read for Reader {
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Writer {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
impl Writer {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::write(self.0.as_raw_fd(), buf.as_ptr() as *const _, buf.len());
|
||||
|
||||
@@ -70,11 +72,8 @@ impl Write for Writer {
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
pub fn write_vectored(&self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let mut msg: libc::msghdr = mem::zeroed();
|
||||
// msg.msg_name = NULL
|
||||
@@ -90,6 +89,22 @@ impl Write for Writer {
|
||||
Ok(n as usize)
|
||||
}
|
||||
}
|
||||
pub fn write_all(&self, mut buf: &[u8]) -> io::Result<()> {
|
||||
while !buf.is_empty() {
|
||||
match self.write(buf) {
|
||||
Ok(0) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::WriteZero,
|
||||
"failed to write whole buffer",
|
||||
));
|
||||
}
|
||||
Ok(n) => buf = &buf[n..],
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Reader {
|
||||
@@ -97,9 +112,14 @@ impl AsRawFd for Reader {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Writer {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
//
|
||||
// impl AsRawFd for Writer {
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// self.0.as_raw_fd()
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,626 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use dashmap::DashMap;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
use tokio::net::tcp::OwnedReadHalf;
|
||||
use tokio::sync::watch::{channel, Receiver, Sender};
|
||||
use crate::channel::{Route, RouteKey, Status};
|
||||
use crate::channel::punch::NatType;
|
||||
use crate::core::status::VntWorker;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::handle::recv_handler::ChannelDataHandler;
|
||||
use byte_pool::{Block, BytePool};
|
||||
lazy_static::lazy_static! {
|
||||
static ref POOL:BytePool = BytePool::new();
|
||||
}
|
||||
pub struct ContextInner {
|
||||
//udp用于打洞、服务端通信(可选)
|
||||
pub(crate) main_channel: Arc<UdpSocket>,
|
||||
//在udp的基础上,可以选择使用tcp和服务端通信
|
||||
pub(crate) main_tcp_channel: Option<tokio::sync::mpsc::Sender<Vec<u8>>>,
|
||||
pub(crate) route_table: DashMap<Ipv4Addr, Vec<Route>>,
|
||||
pub(crate) route_table_time: DashMap<(RouteKey, Ipv4Addr), AtomicCell<Instant>>,
|
||||
pub(crate) status_receiver: Receiver<Status>,
|
||||
pub(crate) status_sender: Sender<Status>,
|
||||
pub(crate) udp_map: DashMap<usize, Arc<UdpSocket>>,
|
||||
pub(crate) channel_num: usize,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
pub(crate) inner: Arc<ContextInner>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(main_channel: Arc<UdpSocket>, main_tcp_channel: Option<tokio::sync::mpsc::Sender<Vec<u8>>>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>, _channel_num: usize) -> Self {
|
||||
//当前版本只支持一个通道
|
||||
let channel_num = 1;
|
||||
let (status_sender, status_receiver) = channel(Status::Cone);
|
||||
let inner = Arc::new(ContextInner {
|
||||
main_channel,
|
||||
main_tcp_channel,
|
||||
route_table: DashMap::with_capacity(16),
|
||||
route_table_time: DashMap::with_capacity(16),
|
||||
status_receiver,
|
||||
status_sender,
|
||||
udp_map: DashMap::new(),
|
||||
channel_num,
|
||||
current_device,
|
||||
});
|
||||
Self {
|
||||
inner
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn is_close(&self) -> bool {
|
||||
*self.inner.status_receiver.borrow() == Status::Close
|
||||
}
|
||||
pub fn is_cone(&self) -> bool {
|
||||
*self.inner.status_receiver.borrow() == Status::Cone
|
||||
}
|
||||
pub fn close(&self) {
|
||||
let _ = self.inner.status_sender.send(Status::Close);
|
||||
}
|
||||
pub fn is_main_tcp(&self) -> bool {
|
||||
self.inner.main_tcp_channel.is_some()
|
||||
}
|
||||
pub fn switch(&self, nat_type: NatType) {
|
||||
match nat_type {
|
||||
NatType::Symmetric => {
|
||||
self.switch_to_symmetric();
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.switch_to_cone();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn switch_to_cone(&self) {
|
||||
let _ = self.inner.status_sender.send(Status::Cone);
|
||||
}
|
||||
pub fn switch_to_symmetric(&self) {
|
||||
let _ = self.inner.status_sender.send(Status::Symmetric);
|
||||
}
|
||||
pub fn main_local_port(&self) -> io::Result<u16> {
|
||||
self.inner.main_channel.local_addr().map(|k| k.port())
|
||||
}
|
||||
pub async fn send_main_udp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
|
||||
self.inner.main_channel.send_to(buf, addr).await
|
||||
}
|
||||
pub async fn send_main(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
if sender.send(buf.to_vec()).await.is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "send_main err"))
|
||||
}
|
||||
} else {
|
||||
self.inner.main_channel.send_to(buf, addr).await
|
||||
}
|
||||
}
|
||||
pub fn try_send_main(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
if sender.try_send(buf.to_vec()).is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "try_send_main err"))
|
||||
}
|
||||
} else {
|
||||
self.inner.main_channel.try_send_to(buf, addr)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn send_all(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
|
||||
for udp_ref in self.inner.udp_map.iter() {
|
||||
let udp = udp_ref.clone();
|
||||
drop(udp_ref);
|
||||
udp.send_to(buf, addr).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<usize> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
if v.value().is_empty() {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "route not found"));
|
||||
}
|
||||
let route = v.value()[0];
|
||||
drop(v);
|
||||
if !route.is_p2p() {
|
||||
if let Some(time) = self.inner.route_table_time.get(&(route.route_key(), *id)) {
|
||||
//借道传输时,长时间不通信的通道不使用
|
||||
if time.value().load().elapsed() > Duration::from_secs(6) {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "route time out"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(udp_ref) = self.inner.udp_map.get(&route.index) {
|
||||
let udp = udp_ref.value().clone();
|
||||
drop(udp_ref);
|
||||
return udp.send_to(buf, route.addr).await;
|
||||
}
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
|
||||
pub fn try_send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<usize> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
if v.value().is_empty() {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "route not found"));
|
||||
}
|
||||
let route = v.value()[0];
|
||||
drop(v);
|
||||
if let Some(udp) = self.inner.udp_map.get(&route.index) {
|
||||
return udp.value().try_send_to(buf, route.addr);
|
||||
}
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
pub async fn send_by_key(&self, buf: &[u8], route_key: &RouteKey) -> io::Result<usize> {
|
||||
if route_key.index == 0 {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
vec[4..].copy_from_slice(buf);
|
||||
return if sender.send(vec).await.is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "send_by_key err"))
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Some(udp_ref) = self.inner.udp_map.get(&route_key.index) {
|
||||
let udp = udp_ref.value().clone();
|
||||
drop(udp_ref);
|
||||
return udp.send_to(buf, route_key.addr).await;
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
pub fn try_send_by_key(&self, buf: &[u8], route_key: &RouteKey) -> io::Result<usize> {
|
||||
if route_key.index == 0 {
|
||||
if let Some(sender) = &self.inner.main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
vec[4..].copy_from_slice(buf);
|
||||
return if sender.try_send(vec).is_ok() {
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "try_send_by_key err"))
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Some(udp) = self.inner.udp_map.get(&route_key.index) {
|
||||
return udp.value().try_send_to(buf, route_key.addr);
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) {
|
||||
self.add_route_(id, route, true)
|
||||
}
|
||||
pub fn add_route(&self, id: Ipv4Addr, route: Route) {
|
||||
self.add_route_(id, route, false)
|
||||
}
|
||||
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) {
|
||||
let key = route.route_key();
|
||||
let mut list = self.inner.route_table.entry(id).or_insert_with(|| Vec::with_capacity(4));
|
||||
let mut exist = false;
|
||||
for x in list.iter_mut() {
|
||||
if x.metric < route.metric {
|
||||
//不能比当前的路径更长
|
||||
return;
|
||||
}
|
||||
if x.route_key() == key {
|
||||
if only_if_absent {
|
||||
return;
|
||||
}
|
||||
x.metric = route.metric;
|
||||
x.rt = route.rt;
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if exist {
|
||||
list.sort_by_key(|k| k.sort_key());
|
||||
} else {
|
||||
if route.metric == 1 {
|
||||
//添加了直连的则排除非直连的
|
||||
list.retain(|k| k.metric == 1);
|
||||
}
|
||||
list.push(route);
|
||||
list.sort_by_key(|k| k.sort_key());
|
||||
let max_len = self.inner.channel_num + 1;
|
||||
if list.len() > max_len {
|
||||
list.truncate(max_len);
|
||||
}
|
||||
}
|
||||
self.inner.route_table_time.insert((key, id), AtomicCell::new(Instant::now()));
|
||||
}
|
||||
pub fn route(&self, id: &Ipv4Addr) -> Option<Vec<Route>> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
Some(v.value().clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn route_one(&self, id: &Ipv4Addr) -> Option<Route> {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
v.value().first().map(|v| *v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn route_to_id(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
|
||||
for x in self.inner.route_table.iter() {
|
||||
for route in x.value() {
|
||||
if &route.route_key() == route_key && route.is_p2p() {
|
||||
return Some(*x.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn need_punch(&self, id: &Ipv4Addr) -> bool {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
if v.value().iter().filter(|k| k.is_p2p()).count() >= self.inner.channel_num {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
pub fn route_table(&self) -> Vec<(Ipv4Addr, Vec<Route>)> {
|
||||
self.inner.route_table.iter().map(|k| (k.key().clone(), k.value().clone())).collect()
|
||||
}
|
||||
pub fn route_table_one(&self) -> Vec<(Ipv4Addr, Route)> {
|
||||
let mut v = Vec::with_capacity(8);
|
||||
for x in self.inner.route_table.iter() {
|
||||
if let Some(route) = x.value().first() {
|
||||
v.push((*x.key(), *route));
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
pub fn direct_route_table_one(&self) -> Vec<(Ipv4Addr, Route)> {
|
||||
let mut v = Vec::with_capacity(8);
|
||||
for x in self.inner.route_table.iter() {
|
||||
if let Some(route) = x.value().first() {
|
||||
if route.metric == 1 {
|
||||
v.push((*x.key(), *route));
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
pub fn remove_route_all(&self, id: &Ipv4Addr) {
|
||||
if let Some((_, routes)) = self.inner.route_table.remove(id) {
|
||||
for x in routes {
|
||||
self.inner.route_table_time.remove(&(x.route_key(), *id));
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn remove_route(&self, id: &Ipv4Addr, route_key: RouteKey) {
|
||||
if let Some(v) = self.inner.route_table.get(id) {
|
||||
let mut routes = v.value().clone();
|
||||
drop(v);
|
||||
routes.retain(|x| x.route_key() != route_key);
|
||||
self.inner.route_table.insert(*id, routes);
|
||||
}
|
||||
self.inner.route_table_time.remove(&(route_key, *id));
|
||||
}
|
||||
pub fn update_read_time(&self, id: &Ipv4Addr, route_key: &RouteKey) {
|
||||
if let Some(time) = self.inner.route_table_time.get(&(*route_key, *id)) {
|
||||
time.value().store(Instant::now());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Channel {
|
||||
context: Context,
|
||||
handler: ChannelDataHandler,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub fn new(context: Context,
|
||||
handler: ChannelDataHandler, ) -> Self {
|
||||
Self {
|
||||
context,
|
||||
handler,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct BufSenderGroup(usize, Vec<tokio::sync::mpsc::Sender<(Block<'static>, usize, usize, RouteKey)>>);
|
||||
|
||||
struct BufReceiverGroup(Vec<tokio::sync::mpsc::Receiver<(Block<'static>, usize, usize, RouteKey)>>);
|
||||
|
||||
impl BufSenderGroup {
|
||||
pub async fn send(&mut self, val: (Block<'static>, usize, usize, RouteKey)) -> bool {
|
||||
let index = self.0 % self.1.len();
|
||||
self.0 = self.0.wrapping_add(1);
|
||||
self.1[index].send(val).await.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn buf_channel_group(size: usize) -> (BufSenderGroup, BufReceiverGroup) {
|
||||
let mut buf_sender_group = Vec::with_capacity(size);
|
||||
let mut buf_receiver_group = Vec::with_capacity(size);
|
||||
for _ in 0..size {
|
||||
let (buf_sender, buf_receiver) = tokio::sync::mpsc::channel::<(Block<'static, Vec<u8>>, usize, usize, RouteKey)>(10);
|
||||
buf_sender_group.push(buf_sender);
|
||||
buf_receiver_group.push(buf_receiver);
|
||||
}
|
||||
(BufSenderGroup(0, buf_sender_group), BufReceiverGroup(buf_receiver_group))
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
async fn tcp_handle(mut tcp_r: OwnedReadHalf, mut buf_sender: BufSenderGroup, head_reserve: usize) -> io::Result<()> {
|
||||
let mut head = [0; 4];
|
||||
let addr = tcp_r.peer_addr()?;
|
||||
let key = RouteKey::new(0, addr);
|
||||
loop {
|
||||
let mut buf = POOL.alloc(4096);
|
||||
tcp_r.read_exact(&mut head).await?;
|
||||
let len = (((head[2] as u16) << 8) | head[3] as u16) as usize;
|
||||
if len < 12 || len > buf.len() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
tcp_r.read_exact(&mut buf[head_reserve..head_reserve + len]).await?;
|
||||
if !buf_sender.send((buf, head_reserve, head_reserve + len, key)).await {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "buf_sender发送数据失败"));
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn start_tcp(mut worker: VntWorker, tcp_stream: TcpStream, mut receiver: tokio::sync::mpsc::Receiver<Vec<u8>>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
buf_sender: BufSenderGroup, head_reserve: usize) {
|
||||
let (tcp_r, mut tcp_w) = tcp_stream.into_split();
|
||||
{
|
||||
let buf_sender = buf_sender.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = Self::tcp_handle(tcp_r, buf_sender, head_reserve).await {
|
||||
log::info!("tcp链接断开:{:?}",e);
|
||||
}
|
||||
});
|
||||
}
|
||||
let mut head = [0; 4];
|
||||
loop {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
rs=receiver.recv()=>{
|
||||
if let Some(data) = rs{
|
||||
let len = data.len();
|
||||
head[2] = (len >> 8) as u8;
|
||||
head[3] = (len & 0xFF) as u8;
|
||||
let mut err = false;
|
||||
if let Err(e) = tcp_w.write_all(&head).await{
|
||||
err = true;
|
||||
log::info!("发送失败,需要重连:{:?}",e);
|
||||
}else if let Err(e) = tcp_w.write_all(&data).await{
|
||||
err = true;
|
||||
log::info!("发送失败,需要重连:{:?}",e);
|
||||
}
|
||||
if err {
|
||||
let _ = tcp_w.shutdown().await;
|
||||
match TcpStream::connect(current_device.load().connect_server).await {
|
||||
Ok(tcp_stream) => {
|
||||
let (r, w) = tcp_stream.into_split();
|
||||
tcp_w = w;
|
||||
let buf_sender = buf_sender.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = Self::tcp_handle(r, buf_sender, head_reserve).await {
|
||||
log::info!("tcp 链接断开:{:?}",e);
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
log::info!("重连失败:{:?}",e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
}
|
||||
|
||||
pub async fn start(self,
|
||||
mut worker: VntWorker,
|
||||
tcp: Option<(TcpStream, tokio::sync::mpsc::Receiver<Vec<u8>>)>,
|
||||
head_reserve: usize,//头部预留字节
|
||||
symmetric_channel_num: usize,//对称网络,则再加一组监听,提升打洞成功率
|
||||
relay: bool,
|
||||
parallel: usize,
|
||||
) {
|
||||
let handler = self.handler.clone();
|
||||
let context = self.context;
|
||||
let main_channel = context.inner.main_channel.clone();
|
||||
let buf_sender = if parallel > 1 || tcp.is_some() {
|
||||
let (buf_sender, buf_receiver) = buf_channel_group(parallel);
|
||||
for mut buf_receiver in buf_receiver.0 {
|
||||
let context = context.clone();
|
||||
let handler = handler.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some((mut buf, start, end, route_key)) = buf_receiver.recv().await {
|
||||
handler.handle(&mut buf, start, end, route_key, &context).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
Some(buf_sender)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some((tcp_stream, receiver)) = tcp {
|
||||
tokio::spawn(Self::start_tcp(worker.worker("main_channel_tcp"), tcp_stream, receiver, context.inner.current_device.clone(), buf_sender.clone().unwrap(), head_reserve));
|
||||
}
|
||||
tokio::spawn(Self::start_(worker.worker("main_channel_1"), context.clone(), main_channel.clone(), handler.clone(), buf_sender.clone(), head_reserve, true));
|
||||
if relay {
|
||||
worker.stop_wait().await;
|
||||
return;
|
||||
}
|
||||
let mut cur_status = Status::Cone;
|
||||
let mut status_receiver = context.inner.status_receiver.clone();
|
||||
loop {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
rs=status_receiver.changed()=>{
|
||||
match rs {
|
||||
Ok(_) => {
|
||||
let s = status_receiver.borrow().clone();
|
||||
match s {
|
||||
Status::Cone => {
|
||||
cur_status = Status::Cone;
|
||||
}
|
||||
Status::Symmetric => {
|
||||
if cur_status == Status::Symmetric {
|
||||
continue;
|
||||
}
|
||||
cur_status = Status::Symmetric;
|
||||
for _ in 0..symmetric_channel_num {
|
||||
match UdpSocket::bind("0.0.0.0:0").await {
|
||||
Ok(udp) => {
|
||||
let udp = Arc::new(udp);
|
||||
let context = context.clone();
|
||||
tokio::spawn(Self::start_(worker.worker("symmetric_channel"),context, udp,handler.clone(),buf_sender.clone(), head_reserve, false));
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Status::Close => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
}
|
||||
async fn start_(mut worker: VntWorker, context: Context,
|
||||
udp: Arc<UdpSocket>,
|
||||
handler: ChannelDataHandler,
|
||||
buf_sender: Option<BufSenderGroup>,
|
||||
head_reserve: usize,
|
||||
is_core: bool) {
|
||||
let mut status_receiver = context.inner.status_receiver.clone();
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::io::AsRawSocket;
|
||||
#[cfg(target_os = "windows")]
|
||||
let id = 1 + udp.as_raw_socket() as usize;
|
||||
#[cfg(any(unix))]
|
||||
use std::os::fd::AsRawFd;
|
||||
#[cfg(any(unix))]
|
||||
let id = 1 + udp.as_raw_fd() as usize;
|
||||
context.inner.udp_map.insert(id, udp.clone());
|
||||
match buf_sender {
|
||||
None => {
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
tokio::select! {
|
||||
rs=udp.recv_from(&mut buf[head_reserve..])=>{
|
||||
match rs {
|
||||
Ok((len, addr)) => {
|
||||
handler.handle(&mut buf, head_reserve, head_reserve + len, RouteKey::new(id, addr), &context).await;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e)
|
||||
}
|
||||
}
|
||||
}
|
||||
changed=status_receiver.changed()=>{
|
||||
match changed {
|
||||
Ok(_) => {
|
||||
match *status_receiver.borrow() {
|
||||
Status::Cone => {
|
||||
if !is_core{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Status::Close=>{
|
||||
break;
|
||||
}
|
||||
Status::Symmetric => {}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(mut buf_sender) => {
|
||||
loop {
|
||||
let mut buf = POOL.alloc(4096);
|
||||
tokio::select! {
|
||||
rs=udp.recv_from(&mut buf[head_reserve..])=>{
|
||||
match rs {
|
||||
Ok((len, addr)) => {
|
||||
if !buf_sender.send((buf,head_reserve,head_reserve+len,RouteKey::new(id, addr))).await{
|
||||
log::error!("udp buf_sender发送数据失败");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}",e)
|
||||
}
|
||||
}
|
||||
}
|
||||
changed=status_receiver.changed()=>{
|
||||
match changed {
|
||||
Ok(_) => {
|
||||
match *status_receiver.borrow() {
|
||||
Status::Cone => {
|
||||
if !is_core{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Status::Close=>{
|
||||
break;
|
||||
}
|
||||
Status::Symmetric => {}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
context.inner.udp_map.remove(&id);
|
||||
if is_core {
|
||||
worker.stop_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use std::io;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::time::Duration;
|
||||
use crate::channel::channel::Context;
|
||||
use crate::channel::RouteKey;
|
||||
|
||||
|
||||
pub struct Idle {
|
||||
read_idle: Duration,
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl Idle {
|
||||
pub fn new(read_idle: Duration,
|
||||
context: Context, ) -> Self {
|
||||
Self {
|
||||
read_idle,
|
||||
context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Idle {
|
||||
/// 获取空闲路由
|
||||
pub async fn next_idle(&self) -> io::Result<(Ipv4Addr, RouteKey)> {
|
||||
loop {
|
||||
let mut max = Duration::from_secs(0);
|
||||
for entry in self.context.inner.route_table_time.iter() {
|
||||
let last_read = entry.value().load().elapsed();
|
||||
if last_read >= self.read_idle {
|
||||
return Ok((entry.key().1.clone(), entry.key().0.clone()));
|
||||
} else {
|
||||
if max < last_read {
|
||||
max = last_read;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.read_idle > max {
|
||||
let sleep_time = self.read_idle - max;
|
||||
tokio::time::sleep(sleep_time).await;
|
||||
}
|
||||
if self.context.is_close() {
|
||||
return Err(Error::new(ErrorKind::Other, "closed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub mod channel;
|
||||
pub mod punch;
|
||||
pub mod idle;
|
||||
pub mod sender;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Status {
|
||||
Cone,
|
||||
Symmetric,
|
||||
Close,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Route {
|
||||
index: usize,
|
||||
pub addr: SocketAddr,
|
||||
pub metric: u8,
|
||||
pub rt: i64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct RouteSortKey {
|
||||
pub metric: u8,
|
||||
pub rt: i64,
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub fn new(index: usize,
|
||||
addr: SocketAddr, metric: u8, rt: i64, ) -> Self {
|
||||
Self {
|
||||
index,
|
||||
addr,
|
||||
metric,
|
||||
rt,
|
||||
}
|
||||
}
|
||||
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
|
||||
Self {
|
||||
index: route_key.index,
|
||||
addr: route_key.addr,
|
||||
metric,
|
||||
rt,
|
||||
}
|
||||
}
|
||||
pub fn route_key(&self) -> RouteKey {
|
||||
RouteKey {
|
||||
index: self.index,
|
||||
addr: self.addr,
|
||||
}
|
||||
}
|
||||
pub fn sort_key(&self) -> RouteSortKey {
|
||||
RouteSortKey {
|
||||
metric: self.metric,
|
||||
rt: self.rt,
|
||||
}
|
||||
}
|
||||
pub fn is_p2p(&self) -> bool {
|
||||
self.metric == 1
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct RouteKey {
|
||||
index: usize,
|
||||
pub addr: SocketAddr,
|
||||
}
|
||||
|
||||
impl RouteKey {
|
||||
pub(crate) fn new(index: usize,
|
||||
addr: SocketAddr, ) -> Self {
|
||||
Self {
|
||||
index,
|
||||
addr,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::time::Duration;
|
||||
|
||||
use rand::prelude::SliceRandom;
|
||||
|
||||
use crate::channel::channel::Context;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NatInfo {
|
||||
pub public_ips: Vec<Ipv4Addr>,
|
||||
pub public_port: u16,
|
||||
pub public_port_range: u16,
|
||||
pub local_ip: Ipv4Addr,
|
||||
pub local_port: u16,
|
||||
pub nat_type: NatType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum NatType {
|
||||
Symmetric,
|
||||
Cone,
|
||||
}
|
||||
|
||||
impl NatInfo {
|
||||
pub fn new(mut public_ips: Vec<Ipv4Addr>,
|
||||
public_port: u16,
|
||||
public_port_range: u16,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
nat_type: NatType, ) -> Self {
|
||||
public_ips.retain(|ip| {
|
||||
!ip.is_loopback() && !ip.is_private()
|
||||
});
|
||||
Self {
|
||||
public_ips,
|
||||
public_port,
|
||||
public_port_range,
|
||||
local_ip,
|
||||
local_port,
|
||||
nat_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Punch {
|
||||
context: Context,
|
||||
port_vec: Vec<u16>,
|
||||
port_index: HashMap<Ipv4Addr, usize>,
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
pub fn new(context: Context) -> Self {
|
||||
let mut port_vec: Vec<u16> = (1..65535).collect();
|
||||
port_vec.push(65535);
|
||||
let mut rng = rand::thread_rng();
|
||||
port_vec.shuffle(&mut rng);
|
||||
Punch {
|
||||
context,
|
||||
port_vec,
|
||||
port_index: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
pub async fn punch(&mut self, buf: &[u8], id: Ipv4Addr, nat_info: NatInfo) -> io::Result<()> {
|
||||
if !self.context.need_punch(&id) {
|
||||
return Ok(());
|
||||
}
|
||||
if !nat_info.local_ip.is_unspecified() || nat_info.local_port != 0 {
|
||||
let _ = self.context.send_main_udp(buf, SocketAddr::V4(SocketAddrV4::new(nat_info.local_ip, nat_info.local_port))).await;
|
||||
}
|
||||
match nat_info.nat_type {
|
||||
NatType::Symmetric => {
|
||||
// 假设对方绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,自己随机尝试k次的情况下
|
||||
// 猜中的概率 p = 1-((65535-n)/65535)*((65535-n-1)/(65535-1))*...*((65535-n-k+1)/(65535-k+1))
|
||||
// n取76,k取600,猜中的概率就超过50%了
|
||||
// 前提 自己是锥形网络,否则猜中了也通信不了
|
||||
|
||||
//预测范围内最多发送max_k1个包
|
||||
let max_k1 = 60;
|
||||
//全局最多发送max_k2个包
|
||||
let max_k2 = 800;
|
||||
if nat_info.public_port_range < max_k1 * 3 {
|
||||
//端口变化不大时,在预测的范围内随机发送
|
||||
let min_port = if nat_info.public_port > nat_info.public_port_range {
|
||||
nat_info.public_port - nat_info.public_port_range
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let (max_port, overflow) = nat_info.public_port.overflowing_add(nat_info.public_port_range);
|
||||
let max_port = if overflow {
|
||||
65535
|
||||
} else {
|
||||
max_port
|
||||
};
|
||||
let k = if max_port - min_port + 1 > max_k1 {
|
||||
max_k1 as usize
|
||||
} else {
|
||||
(max_port - min_port + 1) as usize
|
||||
};
|
||||
let mut nums: Vec<u16> = (min_port..max_port).collect();
|
||||
nums.push(max_port);
|
||||
{
|
||||
let mut rng = rand::thread_rng();
|
||||
nums.shuffle(&mut rng);
|
||||
}
|
||||
self.punch_symmetric(&nums[..k], buf, &nat_info.public_ips, max_k1 as usize).await?;
|
||||
}
|
||||
let start = *self.port_index.entry(id.clone()).or_insert(0);
|
||||
let mut end = start + max_k2;
|
||||
let mut index = end;
|
||||
if end >= self.port_vec.len() {
|
||||
end = self.port_vec.len();
|
||||
index = 0
|
||||
}
|
||||
self.punch_symmetric(&self.port_vec[start..end], buf, &nat_info.public_ips, max_k2).await?;
|
||||
self.port_index.insert(id, index);
|
||||
}
|
||||
NatType::Cone => {
|
||||
let is_cone = self.context.is_cone();
|
||||
for ip in nat_info.public_ips {
|
||||
let addr = SocketAddr::V4(SocketAddrV4::new(ip, nat_info.public_port));
|
||||
if is_cone {
|
||||
self.context.send_main_udp(buf, addr).await?;
|
||||
} else {
|
||||
//只有一方是对称,则对称方要使用全部端口发送数据,符合上述计算的概率
|
||||
self.context.send_all(buf, addr).await?;
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn punch_symmetric(&self, ports: &[u16], buf: &[u8], ips: &Vec<Ipv4Addr>, max: usize) -> io::Result<()> {
|
||||
let mut count = 0;
|
||||
for port in ports {
|
||||
for pub_ip in ips {
|
||||
count += 1;
|
||||
if count == max {
|
||||
return Ok(());
|
||||
}
|
||||
let addr = SocketAddr::V4(SocketAddrV4::new(*pub_ip, *port));
|
||||
self.context.send_main_udp(buf, addr).await?;
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use std::ops::Deref;
|
||||
use crate::channel::channel::Context;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChannelSender {
|
||||
context: Context,
|
||||
}
|
||||
|
||||
impl ChannelSender {
|
||||
pub fn new(context: Context) -> Self {
|
||||
Self {
|
||||
context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ChannelSender {
|
||||
type Target = Context;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.context
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
use std::io;
|
||||
|
||||
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||
use rand::RngCore;
|
||||
|
||||
use crate::cipher::Finger;
|
||||
use crate::protocol::body::AesCbcSecretBody;
|
||||
use crate::protocol::{HEAD_LEN, NetPacket};
|
||||
|
||||
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
|
||||
type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
|
||||
type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
|
||||
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AesCbcCipher {
|
||||
pub(crate) cipher: AesCbcEnum,
|
||||
pub(crate) finger: Finger,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum AesCbcEnum {
|
||||
AES128CBC([u8; 16]),
|
||||
AES256CBC([u8; 32]),
|
||||
}
|
||||
|
||||
impl AesCbcCipher {
|
||||
pub fn key(&self) -> &[u8] {
|
||||
match &self.cipher {
|
||||
AesCbcEnum::AES128CBC(key) => { key }
|
||||
AesCbcEnum::AES256CBC(key) => { key }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AesCbcCipher {
|
||||
pub fn new_128(key: [u8; 16], finger: Finger) -> Self {
|
||||
Self {
|
||||
cipher: AesCbcEnum::AES128CBC(key),
|
||||
finger,
|
||||
}
|
||||
}
|
||||
pub fn new_256(key: [u8; 32], finger: Finger) -> Self {
|
||||
Self {
|
||||
cipher: AesCbcEnum::AES256CBC(key),
|
||||
finger,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<()> {
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < 12 + 16 {
|
||||
log::error!("数据异常,长度{}小于{}",net_packet.payload().len(),12+16);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "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[12..16].copy_from_slice(&self.finger.hash[0..4]);
|
||||
|
||||
let mut secret_body = AesCbcSecretBody::new(net_packet.payload_mut())?;
|
||||
let finger = self.finger.calculate_finger(&iv[..12], secret_body.en_body());
|
||||
if &finger != secret_body.finger() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
||||
}
|
||||
let rs = match &self.cipher {
|
||||
AesCbcEnum::AES128CBC(key) => { Aes128CbcDec::new(&(*key).into(), &iv.into()).decrypt_padded_mut::<Pkcs7>(secret_body.en_body_mut()) }
|
||||
AesCbcEnum::AES256CBC(key) => { Aes256CbcDec::new(&(*key).into(), &iv.into()).decrypt_padded_mut::<Pkcs7>(secret_body.en_body_mut()) }
|
||||
};
|
||||
match rs {
|
||||
Ok(buf) => {
|
||||
let len = buf.len();
|
||||
net_packet.set_encrypt_flag(false);
|
||||
//减去末尾的随机数
|
||||
net_packet.set_data_len(HEAD_LEN + len - 4)?;
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<()> {
|
||||
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[12..16].copy_from_slice(&self.finger.hash[0..4]);
|
||||
//先扩充随机数
|
||||
let data_len = net_packet.data_len();
|
||||
net_packet.set_data_len(data_len + 16)?;
|
||||
let mut secret_body = AesCbcSecretBody::new(net_packet.payload_mut())?;
|
||||
secret_body.set_random(rand::thread_rng().next_u32());
|
||||
let p_len = secret_body.en_body().len();
|
||||
net_packet.set_data_len_max();
|
||||
let rs = match &self.cipher {
|
||||
AesCbcEnum::AES128CBC(key) => { Aes128CbcEnc::new(&(*key).into(), &iv.into()).encrypt_padded_mut::<Pkcs7>(net_packet.payload_mut(), p_len) }
|
||||
AesCbcEnum::AES256CBC(key) => { Aes256CbcEnc::new(&(*key).into(), &iv.into()).encrypt_padded_mut::<Pkcs7>(net_packet.payload_mut(), p_len) }
|
||||
};
|
||||
return match rs {
|
||||
Ok(buf) => {
|
||||
let len = buf.len();
|
||||
let finger = self.finger.calculate_finger(&iv[..12], buf);
|
||||
//设置实际长度
|
||||
net_packet.set_data_len(HEAD_LEN + len + finger.len())?;
|
||||
let mut secret_body = AesCbcSecretBody::new(net_packet.payload_mut())?;
|
||||
secret_body.set_finger(&finger)?;
|
||||
net_packet.set_encrypt_flag(true);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
use std::io;
|
||||
|
||||
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit, Nonce, Tag};
|
||||
use aes_gcm::aead::consts::{U12, U16};
|
||||
use aes_gcm::aead::generic_array::GenericArray;
|
||||
use rand::RngCore;
|
||||
|
||||
use crate::cipher::finger::Finger;
|
||||
use crate::protocol::{body::ENCRYPTION_RESERVED, body::SecretBody, NetPacket};
|
||||
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AesGcmCipher {
|
||||
pub(crate) cipher: AesGcmEnum,
|
||||
pub(crate) finger: Finger,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum AesGcmEnum {
|
||||
AES128GCM(Aes128Gcm),
|
||||
AES256GCM(Aes256Gcm),
|
||||
}
|
||||
|
||||
impl AesGcmCipher {
|
||||
pub fn new_128(key: [u8; 16], finger: Finger) -> Self {
|
||||
let key: &Key<Aes128Gcm> = &key.into();
|
||||
Self {
|
||||
cipher: AesGcmEnum::AES128GCM(Aes128Gcm::new(key)),
|
||||
finger,
|
||||
}
|
||||
}
|
||||
pub fn new_256(key: [u8; 32], finger: Finger) -> Self {
|
||||
let key: &Key<Aes256Gcm> = &key.into();
|
||||
Self {
|
||||
cipher: AesGcmEnum::AES256GCM(Aes256Gcm::new(key)),
|
||||
finger,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<()> {
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < ENCRYPTION_RESERVED {
|
||||
log::error!("数据异常,长度小于{}",ENCRYPTION_RESERVED);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "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: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
|
||||
|
||||
let mut secret_body = SecretBody::new(net_packet.payload_mut())?;
|
||||
let tag = secret_body.tag();
|
||||
let finger = self.finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
||||
if &finger != secret_body.finger() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
||||
}
|
||||
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(tag);
|
||||
let rs = match &self.cipher {
|
||||
AesGcmEnum::AES128GCM(aes_gcm) => { aes_gcm.decrypt_in_place_detached(nonce, &[], secret_body.body_mut(), &tag) }
|
||||
AesGcmEnum::AES256GCM(aes_gcm) => { aes_gcm.decrypt_in_place_detached(nonce, &[], secret_body.body_mut(), &tag) }
|
||||
};
|
||||
if let Err(e) = rs {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)));
|
||||
}
|
||||
net_packet.set_encrypt_flag(false);
|
||||
net_packet.set_data_len(net_packet.data_len() - ENCRYPTION_RESERVED)?;
|
||||
return Ok(());
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<()> {
|
||||
if net_packet.reserve() < ENCRYPTION_RESERVED {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "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: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
|
||||
let data_len = net_packet.data_len() + ENCRYPTION_RESERVED;
|
||||
net_packet.set_data_len(data_len)?;
|
||||
let mut secret_body = SecretBody::new(net_packet.payload_mut())?;
|
||||
secret_body.set_random(rand::thread_rng().next_u32());
|
||||
let rs = match &self.cipher {
|
||||
AesGcmEnum::AES128GCM(aes_gcm) => { aes_gcm.encrypt_in_place_detached(nonce, &[], secret_body.body_mut()) }
|
||||
AesGcmEnum::AES256GCM(aes_gcm) => { aes_gcm.encrypt_in_place_detached(nonce, &[], secret_body.body_mut()) }
|
||||
};
|
||||
return match rs {
|
||||
Ok(tag) => {
|
||||
secret_body.set_tag(tag.as_slice())?;
|
||||
let finger = self.finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
||||
secret_body.set_finger(&finger)?;
|
||||
net_packet.set_encrypt_flag(true);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
use std::io;
|
||||
use std::str::FromStr;
|
||||
use crate::cipher::{aes_cbc, Finger};
|
||||
use crate::protocol::NetPacket;
|
||||
use sha2::Digest;
|
||||
#[cfg(feature = "ring-cipher")]
|
||||
use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher;
|
||||
#[cfg(not(feature = "ring-cipher"))]
|
||||
use crate::cipher::aes_gcm_cipher::AesGcmCipher;
|
||||
use aes_cbc::AesCbcCipher;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum CipherModel {
|
||||
AesGcm,
|
||||
AesCbc,
|
||||
}
|
||||
|
||||
impl FromStr for CipherModel {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"aes_gcm" => {
|
||||
Ok(CipherModel::AesGcm)
|
||||
}
|
||||
"aes_cbc" => { Ok(CipherModel::AesCbc) }
|
||||
_ => {
|
||||
Err(format!("not match '{}'", s))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Cipher {
|
||||
AesGcm((AesGcmCipher, Vec<u8>)),
|
||||
AesCbc(AesCbcCipher),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Cipher {
|
||||
pub fn new_password(model: CipherModel, password: Option<String>, token: String) -> Self {
|
||||
let finger = Finger::new(&token);
|
||||
if let Some(password) = password {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(password.as_bytes());
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
match model {
|
||||
CipherModel::AesGcm => {
|
||||
if password.len() < 8 {
|
||||
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||
Cipher::AesGcm((aes, key[..16].to_vec()))
|
||||
} else {
|
||||
let aes = AesGcmCipher::new_256(key, finger);
|
||||
Cipher::AesGcm((aes, key.to_vec()))
|
||||
}
|
||||
}
|
||||
CipherModel::AesCbc => {
|
||||
if password.len() < 8 {
|
||||
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||
Cipher::AesCbc(aes)
|
||||
} else {
|
||||
let aes = AesCbcCipher::new_256(key, finger);
|
||||
Cipher::AesCbc(aes)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Cipher::None
|
||||
}
|
||||
}
|
||||
pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> {
|
||||
let finger = Finger::new(&token);
|
||||
match key.len() {
|
||||
16 => {
|
||||
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
|
||||
}
|
||||
32 => {
|
||||
let aes = AesGcmCipher::new_256(key, finger);
|
||||
Ok(Cipher::AesGcm((aes, key.to_vec())))
|
||||
}
|
||||
_ => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "key error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<()> {
|
||||
match self {
|
||||
Cipher::AesGcm((aes_gcm, _)) => {
|
||||
aes_gcm.decrypt_ipv4(net_packet)
|
||||
}
|
||||
Cipher::AesCbc(aes_cbc) => {
|
||||
aes_cbc.decrypt_ipv4(net_packet).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
Cipher::None => {
|
||||
if net_packet.is_encrypt() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not key"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<()> {
|
||||
match self {
|
||||
Cipher::AesGcm((aes_gcm, _)) => {
|
||||
aes_gcm.encrypt_ipv4(net_packet)
|
||||
}
|
||||
Cipher::AesCbc(aes_cbc) => {
|
||||
aes_cbc.encrypt_ipv4(net_packet).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
Cipher::None => {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
|
||||
match self {
|
||||
Cipher::AesGcm((aes_gcm, _)) => {
|
||||
aes_gcm.finger.check_finger(net_packet)
|
||||
}
|
||||
Cipher::AesCbc(aes_cbc) => {
|
||||
aes_cbc.finger.check_finger(net_packet)
|
||||
}
|
||||
Cipher::None => {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn key(&self) -> Option<&[u8]> {
|
||||
match self {
|
||||
Cipher::AesGcm((_, key)) => {
|
||||
Some(key)
|
||||
}
|
||||
Cipher::AesCbc(aes_cbc) => {
|
||||
Some(aes_cbc.key())
|
||||
}
|
||||
Cipher::None => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::io;
|
||||
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::protocol::NetPacket;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Finger {
|
||||
pub(crate) hash: [u8; 32],
|
||||
}
|
||||
|
||||
impl Finger {
|
||||
pub fn new(str: &str) -> Self {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(str.as_bytes());
|
||||
let hash: [u8; 32] = hasher.finalize().into();
|
||||
Finger { hash }
|
||||
}
|
||||
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "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"));
|
||||
}
|
||||
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 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"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn calculate_finger(&self, nonce: &[u8], secret_body: &[u8]) -> [u8; 12] {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(nonce);
|
||||
hasher.update(secret_body);
|
||||
hasher.update(&self.hash);
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
return key[20..].try_into().unwrap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#[cfg(feature = "ring-cipher")]
|
||||
mod ring_aes_gcm_cipher;
|
||||
#[cfg(not(feature = "ring-cipher"))]
|
||||
mod aes_gcm_cipher;
|
||||
mod rsa_cipher;
|
||||
mod aes_cbc;
|
||||
mod finger;
|
||||
mod cipher;
|
||||
|
||||
pub use cipher::Cipher;
|
||||
pub use finger::Finger;
|
||||
pub use rsa_cipher::RsaCipher;
|
||||
pub use cipher::CipherModel;
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
use std::io;
|
||||
use rand::RngCore;
|
||||
use ring::aead;
|
||||
use ring::aead::{LessSafeKey, UnboundKey};
|
||||
use crate::cipher::Finger;
|
||||
|
||||
use crate::protocol::NetPacket;
|
||||
use crate::protocol::body::{ENCRYPTION_RESERVED, SecretBody};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AesGcmCipher {
|
||||
pub(crate) cipher: AesGcmEnum,
|
||||
pub(crate) finger: Finger,
|
||||
}
|
||||
|
||||
pub enum AesGcmEnum {
|
||||
AesGCM128(LessSafeKey, [u8; 16]),
|
||||
AesGCM256(LessSafeKey, [u8; 32]),
|
||||
}
|
||||
|
||||
impl Clone for AesGcmEnum {
|
||||
fn clone(&self) -> Self {
|
||||
match &self {
|
||||
AesGcmEnum::AesGCM128(_, key) => {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, key.as_slice()).unwrap());
|
||||
AesGcmEnum::AesGCM128(c, *key)
|
||||
}
|
||||
AesGcmEnum::AesGCM256(_, key) => {
|
||||
let c = LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, key.as_slice()).unwrap());
|
||||
AesGcmEnum::AesGCM256(c, *key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AesGcmCipher {
|
||||
pub fn new_128(key: [u8; 16], finger: Finger) -> Self {
|
||||
let cipher = LessSafeKey::new(UnboundKey::new(&aead::AES_128_GCM, &key).unwrap());
|
||||
Self {
|
||||
cipher: AesGcmEnum::AesGCM128(cipher, key),
|
||||
finger,
|
||||
}
|
||||
}
|
||||
pub fn new_256(key: [u8; 32], finger: Finger) -> Self {
|
||||
let cipher = LessSafeKey::new(UnboundKey::new(&aead::AES_256_GCM, &key).unwrap());
|
||||
Self {
|
||||
cipher: AesGcmEnum::AesGCM256(cipher, key),
|
||||
finger,
|
||||
}
|
||||
}
|
||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<()> {
|
||||
if !net_packet.is_encrypt() {
|
||||
//未加密的数据直接丢弃
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
||||
}
|
||||
if net_packet.payload().len() < ENCRYPTION_RESERVED {
|
||||
log::error!("数据异常,长度小于{}",ENCRYPTION_RESERVED);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "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 = aead::Nonce::assume_unique_for_key(nonce_raw);
|
||||
let mut secret_body = SecretBody::new(net_packet.payload_mut())?;
|
||||
let tag = secret_body.tag();
|
||||
let finger = self.finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
||||
if &finger != secret_body.finger() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
||||
}
|
||||
|
||||
let rs = match &self.cipher {
|
||||
AesGcmEnum::AesGCM128(cipher, _) => {
|
||||
cipher.open_in_place(nonce, aead::Aad::empty(), secret_body.en_body_mut())
|
||||
}
|
||||
AesGcmEnum::AesGCM256(cipher, _) => {
|
||||
cipher.open_in_place(nonce, aead::Aad::empty(), secret_body.en_body_mut())
|
||||
}
|
||||
};
|
||||
if let Err(e) = rs {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("解密失败:{}", e)));
|
||||
}
|
||||
net_packet.set_encrypt_flag(false);
|
||||
net_packet.set_data_len(net_packet.data_len() - ENCRYPTION_RESERVED)?;
|
||||
return Ok(());
|
||||
}
|
||||
/// net_packet 必须预留足够长度
|
||||
/// data_len是有效载荷的长度
|
||||
/// 返回加密后载荷的长度
|
||||
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();
|
||||
let nonce = aead::Nonce::assume_unique_for_key(nonce_raw);
|
||||
let data_len = net_packet.data_len() + ENCRYPTION_RESERVED;
|
||||
net_packet.set_data_len(data_len)?;
|
||||
let mut secret_body = SecretBody::new(net_packet.payload_mut())?;
|
||||
secret_body.set_random(rand::thread_rng().next_u32());
|
||||
|
||||
let rs = match &self.cipher {
|
||||
AesGcmEnum::AesGCM128(cipher, _) => {
|
||||
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), secret_body.body_mut())
|
||||
}
|
||||
AesGcmEnum::AesGCM256(cipher, _) => {
|
||||
cipher.seal_in_place_separate_tag(nonce, aead::Aad::empty(), secret_body.body_mut())
|
||||
}
|
||||
};
|
||||
return match rs {
|
||||
Ok(tag) => {
|
||||
let tag = tag.as_ref();
|
||||
if tag.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("加密tag长度错误:{}", tag.len())));
|
||||
}
|
||||
secret_body.set_tag(tag)?;
|
||||
let finger = self.finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
||||
secret_body.set_finger(&finger)?;
|
||||
net_packet.set_encrypt_flag(true);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e)))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
use std::io;
|
||||
use rand::Rng;
|
||||
use rsa::pkcs8::der::Decode;
|
||||
use rsa::{PublicKey, RsaPublicKey};
|
||||
use spki::{DecodePublicKey, EncodePublicKey};
|
||||
use crate::protocol::body::{ENCRYPTION_RESERVED, RsaSecretBody};
|
||||
use crate::protocol::NetPacket;
|
||||
use sha2::Digest;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RsaCipher {
|
||||
inner: Inner,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Inner {
|
||||
public_key: RsaPublicKey,
|
||||
}
|
||||
|
||||
impl RsaCipher {
|
||||
pub fn new(der: &[u8]) -> io::Result<Self> {
|
||||
match RsaPublicKey::from_public_key_der(der) {
|
||||
Ok(public_key) => {
|
||||
let inner = Inner {
|
||||
public_key,
|
||||
};
|
||||
Ok(Self {
|
||||
inner
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("from_public_key_der failed {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn finger(&self) -> io::Result<String> {
|
||||
match self.inner.public_key.to_public_key_der() {
|
||||
Ok(der) => {
|
||||
match rsa::pkcs8::SubjectPublicKeyInfo::from_der(der.as_bytes()) {
|
||||
Ok(spki) => {
|
||||
match spki.fingerprint_base64() {
|
||||
Ok(finger) => {
|
||||
Ok(finger)
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("fingerprint_base64 error {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("from_der error {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("to_public_key_der error {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RsaCipher {
|
||||
/// net_packet 必须预留足够长度
|
||||
pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>(&self, net_packet: &mut NetPacket<B>) -> io::Result<NetPacket<Vec<u8>>> {
|
||||
if net_packet.reserve() < ENCRYPTION_RESERVED {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "too short"));
|
||||
}
|
||||
let data_len = net_packet.data_len() + ENCRYPTION_RESERVED;
|
||||
net_packet.set_data_len(data_len)?;
|
||||
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 mut secret_body = RsaSecretBody::new(net_packet.payload_mut())?;
|
||||
let mut rng = rand::thread_rng();
|
||||
rng.fill(secret_body.random_mut());
|
||||
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(secret_body.body());
|
||||
hasher.update(nonce_raw);
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
secret_body.set_finger(&key[16..])?;
|
||||
match self.inner.public_key.encrypt(&mut rng, rsa::PaddingScheme::PKCS1v15Encrypt, secret_body.buffer()) {
|
||||
Ok(enc_data) => {
|
||||
let mut net_packet_e = NetPacket::new(vec![0; 12 + enc_data.len()])?;
|
||||
net_packet_e.buffer_mut()[..12].copy_from_slice(&net_packet.buffer()[..12]);
|
||||
net_packet_e.set_payload(&enc_data)?;
|
||||
Ok(net_packet_e)
|
||||
}
|
||||
Err(e) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, format!("encrypt failed {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use dashmap::DashMap;
|
||||
use parking_lot::Mutex;
|
||||
use rand::Rng;
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
use tokio::sync::mpsc::channel;
|
||||
|
||||
use crate::channel::{Route, RouteKey};
|
||||
use crate::channel::channel::{Channel, Context};
|
||||
use crate::channel::idle::Idle;
|
||||
use crate::channel::punch::{NatInfo, Punch};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::{Cipher, CipherModel, RsaCipher};
|
||||
use crate::core::status::VntStatusManger;
|
||||
use crate::error::Error;
|
||||
use crate::external_route::{AllowExternalRoute, ExternalRoute};
|
||||
use crate::handle::{ConnectStatus, CurrentDeviceInfo, handshake_handler, heartbeat_handler, PeerDeviceInfo, punch_handler, registration_handler};
|
||||
use crate::handle::handshake_handler::HandshakeEnum;
|
||||
use crate::handle::recv_handler::ChannelDataHandler;
|
||||
use crate::handle::registration_handler::{RegResponse, ReqEnum};
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
use crate::handle::tun_tap::tap_handler;
|
||||
use crate::handle::tun_tap::tun_handler;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::nat::NatTest;
|
||||
use crate::tun_tap_device;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceWriter};
|
||||
|
||||
pub mod status;
|
||||
pub mod sync;
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vnt {
|
||||
config: Config,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
context: Context,
|
||||
vnt_status_manager: VntStatusManger,
|
||||
device_writer: DeviceWriter,
|
||||
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
|
||||
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
||||
/// 1. 网络中的虚拟ip列表
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
nat_test: NatTest,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<DashMap<Ipv4Addr, NatInfo>>,
|
||||
}
|
||||
|
||||
pub struct VntUtil {
|
||||
config: Config,
|
||||
main_channel: UdpSocket,
|
||||
main_tcp_channel: Option<TcpStream>,
|
||||
response: Option<RegResponse>,
|
||||
iface: Option<(DeviceWriter, DeviceReader)>,
|
||||
server_cipher: Cipher,
|
||||
rsa_cipher: Option<RsaCipher>,
|
||||
}
|
||||
|
||||
impl VntUtil {
|
||||
pub async fn new(config: Config) -> io::Result<VntUtil> {
|
||||
let main_channel = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
let server_cipher = if config.server_encrypt {
|
||||
let mut key = [0 as u8; 32];
|
||||
rand::thread_rng().fill(&mut key);
|
||||
Cipher::new_key(key, config.token.clone())?
|
||||
} else {
|
||||
Cipher::None
|
||||
};
|
||||
Ok(VntUtil {
|
||||
config,
|
||||
main_channel,
|
||||
main_tcp_channel: None,
|
||||
response: None,
|
||||
iface: None,
|
||||
server_cipher,
|
||||
rsa_cipher: None,
|
||||
})
|
||||
}
|
||||
///链接
|
||||
pub async fn connect(&mut self) -> io::Result<()> {
|
||||
if self.config.tcp {
|
||||
let tcp = TcpStream::connect(self.config.server_address).await?;
|
||||
let _ = self.main_tcp_channel.insert(tcp);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///握手 用于获取公钥
|
||||
pub async fn handshake(&mut self) -> Result<Option<RsaCipher>, HandshakeEnum> {
|
||||
let rsa_cipher = handshake_handler::handshake(&self.main_channel, self.main_tcp_channel.as_mut(), self.config.server_address, self.config.server_encrypt).await?;
|
||||
self.rsa_cipher = rsa_cipher.clone();
|
||||
Ok(rsa_cipher)
|
||||
}
|
||||
/// 加密握手 用于同步密钥
|
||||
pub async fn secret_handshake(&mut self) -> Result<(), HandshakeEnum> {
|
||||
handshake_handler::secret_handshake(&self.main_channel, self.main_tcp_channel.as_mut(), self.config.server_address, self.rsa_cipher.as_ref().unwrap(), &self.server_cipher, self.config.token.clone()).await
|
||||
}
|
||||
/// 注册
|
||||
pub async fn register(&mut self) -> Result<RegResponse, ReqEnum> {
|
||||
match registration_handler::registration(&self.main_channel, self.main_tcp_channel.as_mut(), &self.server_cipher, self.config.server_address,
|
||||
self.config.token.clone(), self.config.device_id.clone(),
|
||||
self.config.name.clone(), self.config.ip.unwrap_or(Ipv4Addr::UNSPECIFIED), self.config.password.is_some()).await {
|
||||
Ok(res) => {
|
||||
let _ = self.response.insert(res.clone());
|
||||
Ok(res)
|
||||
}
|
||||
Err(e) => {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "android"))]
|
||||
pub fn create_iface(&mut self, vpn_fd: i32) {
|
||||
let (device_writer, device_reader) = tun_tap_device::create(vpn_fd);
|
||||
let _ = self.iface.insert((device_writer, device_reader));
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
pub fn create_iface(&mut self) -> io::Result<tun_tap_device::DriverInfo> {
|
||||
if self.iface.is_some() {
|
||||
return Err(io::Error::from(io::ErrorKind::AlreadyExists));
|
||||
}
|
||||
let response = match &self.response {
|
||||
None => {
|
||||
return Err(io::Error::from(io::ErrorKind::AlreadyExists));
|
||||
}
|
||||
Some(res) => {
|
||||
res
|
||||
}
|
||||
};
|
||||
let device_type = if self.config.tap {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
//删除tun网卡避免ip冲突,因为非正常退出会保留网卡
|
||||
tun_tap_device::delete_device(tun_tap_device::DeviceType::Tun);
|
||||
}
|
||||
tun_tap_device::DeviceType::Tap
|
||||
} else {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
//删除tap网卡避免ip冲突,非正常退出会保留网卡
|
||||
tun_tap_device::delete_device(tun_tap_device::DeviceType::Tap);
|
||||
}
|
||||
tun_tap_device::DeviceType::Tun
|
||||
};
|
||||
let mtu = match self.config.mtu {
|
||||
None => {
|
||||
if self.config.password.is_none() {
|
||||
1430
|
||||
} else {
|
||||
1410
|
||||
}
|
||||
}
|
||||
Some(mtu) => {
|
||||
mtu
|
||||
}
|
||||
};
|
||||
let in_ips = self.config.in_ips.iter().map(|(dest, mask, _)| { (Ipv4Addr::from(*dest & *mask), Ipv4Addr::from(*mask)) }).collect::<Vec<(Ipv4Addr, Ipv4Addr)>>();
|
||||
|
||||
let (device_writer, device_reader, driver_info) = tun_tap_device::create_device(device_type, response.virtual_ip,
|
||||
response.virtual_netmask, response.virtual_gateway, in_ips, mtu)?;
|
||||
let _ = self.iface.insert((device_writer, device_reader));
|
||||
Ok(driver_info)
|
||||
}
|
||||
pub async fn build(self) -> crate::Result<Vnt> {
|
||||
let response = match self.response {
|
||||
None => {
|
||||
return Err(Error::Stop("response None".to_string()));
|
||||
}
|
||||
Some(res) => {
|
||||
res
|
||||
}
|
||||
};
|
||||
let (device_writer, device_reader) = match self.iface {
|
||||
None => {
|
||||
return Err(Error::Stop("iface None".to_string()));
|
||||
}
|
||||
Some(res) => {
|
||||
res
|
||||
}
|
||||
};
|
||||
let config = self.config.clone();
|
||||
let vnt_status_manager = VntStatusManger::new();
|
||||
let client_cipher = Cipher::new_password(config.cipher_model, config.password.clone(), config.token.clone());
|
||||
let virtual_ip = response.virtual_ip;
|
||||
let virtual_gateway = response.virtual_gateway;
|
||||
let virtual_netmask = response.virtual_netmask;
|
||||
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address)));
|
||||
|
||||
let (cone_sender, cone_receiver) = channel(3);
|
||||
let (symmetric_sender, symmetric_receiver) = channel(2);
|
||||
let (tcp_sender, tcp) = if let Some(main_tcp_channel) = self.main_tcp_channel {
|
||||
let (tcp_sender, tcp_receiver) = channel::<Vec<u8>>(100);
|
||||
(Some(tcp_sender), Some((main_tcp_channel, tcp_receiver)))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
let context = Context::new(Arc::new(self.main_channel), tcp_sender, current_device.clone(), 1);
|
||||
let punch = Punch::new(context.clone());
|
||||
let idle = Idle::new(Duration::from_secs(16), context.clone());
|
||||
let channel_sender = ChannelSender::new(context.clone());
|
||||
|
||||
let register = Arc::new(registration_handler::Register::new(self.server_cipher.clone(), channel_sender.clone(),
|
||||
config.server_address, config.token.clone(),
|
||||
config.device_id.clone(), config.name.clone(), config.password.is_some()));
|
||||
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> = Arc::new(Mutex::new((response.epoch, response.device_info_list)));
|
||||
let peer_nat_info_map: Arc<DashMap<Ipv4Addr, NatInfo>> = Arc::new(DashMap::new());
|
||||
let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected));
|
||||
|
||||
|
||||
let local_ip = crate::nat::local_ip()?;
|
||||
let local_port = context.main_local_port()?;
|
||||
// NAT检测
|
||||
let nat_test = NatTest::new(config.stun_server.clone(), response.public_ip, response.public_port, local_ip, local_port).await;
|
||||
let in_external_route = if config.in_ips.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ExternalRoute::new(config.in_ips))
|
||||
};
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = if config.out_ips.is_empty() {
|
||||
(None, None, None)
|
||||
} else {
|
||||
let (tcp_proxy, udp_proxy, ip_proxy_map) = crate::ip_proxy::init_proxy(channel_sender.clone(), current_device.clone(), client_cipher.clone()).await?;
|
||||
(Some(tcp_proxy), Some(udp_proxy), Some(ip_proxy_map))
|
||||
};
|
||||
let out_external_route = AllowExternalRoute::new(config.out_ips);
|
||||
|
||||
let igmp_server = if config.simulate_multicast {
|
||||
Some(IgmpServer::new(device_writer.clone()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
if config.tap {
|
||||
tap_handler::start(vnt_status_manager.worker("tap_handler"), channel_sender.clone(), device_reader, device_writer.clone(),
|
||||
igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(),
|
||||
client_cipher.clone(), self.server_cipher.clone(), config.parallel);
|
||||
} else {
|
||||
tun_handler::start(vnt_status_manager.worker("tun_handler"), channel_sender.clone(), device_reader, device_writer.clone(),
|
||||
igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(),
|
||||
client_cipher.clone(), self.server_cipher.clone(), config.parallel).await;
|
||||
}
|
||||
#[cfg(any(target_os = "android"))]
|
||||
tun_handler::start(vnt_status_manager.worker("android tun_handler"), channel_sender.clone(), device_reader, device_writer.clone(),
|
||||
igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone(), config.parallel).await;
|
||||
|
||||
//外部数据接收处理
|
||||
let channel_recv_handler = ChannelDataHandler::new(current_device.clone(), device_list.clone(),
|
||||
register.clone(), nat_test.clone(), igmp_server,
|
||||
device_writer.clone(), connect_status.clone(),
|
||||
peer_nat_info_map.clone(), ip_proxy_map, out_external_route,
|
||||
cone_sender, symmetric_sender, client_cipher.clone(),
|
||||
self.server_cipher.clone(), self.rsa_cipher.clone(), config.relay, config.token.clone());
|
||||
{
|
||||
let channel = Channel::new(context.clone(), channel_recv_handler);
|
||||
let channel_worker = vnt_status_manager.worker("channel_worker");
|
||||
let relay = config.relay;
|
||||
if let Some(tcp_proxy) = tcp_proxy {
|
||||
tokio::spawn(tcp_proxy.start());
|
||||
}
|
||||
if let Some(udp_proxy) = udp_proxy {
|
||||
tokio::spawn(udp_proxy.start());
|
||||
}
|
||||
tokio::spawn(async move {
|
||||
channel.start(channel_worker, tcp, 14, 65, relay, config.parallel).await
|
||||
});
|
||||
}
|
||||
{
|
||||
let other_worker = vnt_status_manager.worker("punch_handler");
|
||||
let nat_test = nat_test.clone();
|
||||
let device_list = device_list.clone();
|
||||
let current_device = current_device.clone();
|
||||
// 定时心跳
|
||||
heartbeat_handler::start_heartbeat(other_worker.worker("heartbeat"), channel_sender.clone(), device_list.clone(),
|
||||
current_device.clone(), config.server_address_str, client_cipher.clone(), self.server_cipher.clone());
|
||||
// 空闲检查
|
||||
heartbeat_handler::start_idle(other_worker.worker("idle"), idle, channel_sender.clone());
|
||||
if !config.relay {
|
||||
// 打洞处理
|
||||
punch_handler::start(other_worker.worker("cone_receiver"), cone_receiver, punch.clone(), current_device.clone(), client_cipher.clone());
|
||||
punch_handler::start(other_worker.worker("symmetric_receiver"), symmetric_receiver, punch, current_device.clone(), client_cipher.clone());
|
||||
tokio::spawn(punch_handler::start_punch(other_worker, nat_test,
|
||||
device_list, channel_sender, current_device, client_cipher.clone()));
|
||||
}
|
||||
}
|
||||
context.switch(nat_test.nat_info().nat_type);
|
||||
Ok(Vnt {
|
||||
config: self.config,
|
||||
current_device,
|
||||
context,
|
||||
vnt_status_manager,
|
||||
device_writer,
|
||||
nat_test,
|
||||
device_list,
|
||||
connect_status,
|
||||
peer_nat_info_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Vnt {
|
||||
pub fn name(&self) -> &str {
|
||||
&self.config.name
|
||||
}
|
||||
pub fn server_encrypt(&self) -> bool {
|
||||
self.config.server_encrypt
|
||||
}
|
||||
pub fn client_encrypt(&self) -> bool {
|
||||
self.config.password.is_some()
|
||||
}
|
||||
pub fn current_device(&self) -> CurrentDeviceInfo {
|
||||
self.current_device.load()
|
||||
}
|
||||
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
|
||||
self.peer_nat_info_map.get(ip).map(|e| e.value().clone())
|
||||
}
|
||||
pub fn connection_status(&self) -> ConnectStatus {
|
||||
self.connect_status.load()
|
||||
}
|
||||
pub fn nat_info(&self) -> NatInfo {
|
||||
self.nat_test.nat_info()
|
||||
}
|
||||
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
|
||||
let device_list_lock = self.device_list.lock();
|
||||
let (_epoch, device_list) = device_list_lock.clone();
|
||||
drop(device_list_lock);
|
||||
device_list
|
||||
}
|
||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
|
||||
self.context.route_one(ip)
|
||||
}
|
||||
pub fn route_key(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
|
||||
self.context.route_to_id(route_key)
|
||||
}
|
||||
pub fn route_table(&self) -> Vec<(Ipv4Addr, Route)> {
|
||||
self.context.route_table_one()
|
||||
}
|
||||
pub fn stop(&self) -> io::Result<()> {
|
||||
self.context.close();
|
||||
self.vnt_status_manager.stop_all();
|
||||
self.device_writer.close()?;
|
||||
let virtual_gateway = self.current_device.load().virtual_gateway;
|
||||
let _ = std::net::UdpSocket::bind("0.0.0.0:0")?.send_to(&[0],
|
||||
SocketAddr::V4(SocketAddrV4::new(virtual_gateway, 10000)));
|
||||
Ok(())
|
||||
}
|
||||
pub async fn wait_stop(&mut self) {
|
||||
self.vnt_status_manager.wait().await;
|
||||
let _ = self.stop();
|
||||
}
|
||||
pub async fn wait_stop_ms(&mut self, ms: Duration) -> bool {
|
||||
tokio::select! {
|
||||
_=self.vnt_status_manager.wait()=>{
|
||||
let _ = self.stop();
|
||||
return true;
|
||||
}
|
||||
_=tokio::time::sleep(ms)=>{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Vnt {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.stop();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
pub tap: bool,
|
||||
pub token: String,
|
||||
pub device_id: String,
|
||||
pub name: String,
|
||||
pub server_address: SocketAddr,
|
||||
pub server_address_str: String,
|
||||
pub stun_server: Vec<String>,
|
||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32)>,
|
||||
pub password: Option<String>,
|
||||
pub simulate_multicast: bool,
|
||||
pub mtu: Option<u16>,
|
||||
pub tcp: bool,
|
||||
pub ip: Option<Ipv4Addr>,
|
||||
pub relay: bool,
|
||||
pub server_encrypt: bool,
|
||||
pub parallel: usize,
|
||||
pub cipher_model: CipherModel,
|
||||
}
|
||||
|
||||
|
||||
impl Config {
|
||||
pub fn new(tap: bool, token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
server_address: SocketAddr,
|
||||
server_address_str: String,
|
||||
mut stun_server: Vec<String>,
|
||||
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32)>,
|
||||
password: Option<String>, simulate_multicast: bool, mtu: Option<u16>, tcp: bool,
|
||||
ip: Option<Ipv4Addr>,
|
||||
relay: bool, server_encrypt: bool, parallel: usize, cipher_model: CipherModel) -> Self {
|
||||
for x in stun_server.iter_mut() {
|
||||
if !x.contains(":") {
|
||||
x.push_str(":3478");
|
||||
}
|
||||
}
|
||||
Self {
|
||||
tap,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address,
|
||||
server_address_str,
|
||||
stun_server,
|
||||
in_ips,
|
||||
out_ips,
|
||||
password,
|
||||
simulate_multicast,
|
||||
mtu,
|
||||
tcp,
|
||||
ip,
|
||||
relay,
|
||||
server_encrypt,
|
||||
parallel,
|
||||
cipher_model,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::watch;
|
||||
use tokio::sync::watch::{Receiver, Sender};
|
||||
use crate::util::wait::WaitGroup;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum VntStatus {
|
||||
Starting,
|
||||
Stopping,
|
||||
}
|
||||
|
||||
pub struct VntWorker {
|
||||
_name: String,
|
||||
wg: WaitGroup,
|
||||
status_s: Arc<Sender<VntStatus>>,
|
||||
status_r: Receiver<VntStatus>,
|
||||
}
|
||||
|
||||
impl VntWorker {
|
||||
pub fn worker(&self, name: &str) -> Self {
|
||||
self.wg.add();
|
||||
VntWorker {
|
||||
_name: name.to_string(),
|
||||
wg: self.wg.clone(),
|
||||
status_s: self.status_s.clone(),
|
||||
status_r: self.status_r.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VntWorker {
|
||||
fn drop(&mut self) {
|
||||
self.wg.done();
|
||||
}
|
||||
}
|
||||
|
||||
impl VntWorker {
|
||||
pub fn stop_all(&self) {
|
||||
let _ = self.status_s.send(VntStatus::Stopping);
|
||||
}
|
||||
pub async fn stop_wait(&mut self) {
|
||||
loop {
|
||||
if *self.status_r.borrow() == VntStatus::Stopping {
|
||||
return;
|
||||
}
|
||||
match self.status_r.changed().await {
|
||||
Ok(_) => {
|
||||
if *self.status_r.borrow() == VntStatus::Stopping {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(_) => { return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VntStatusManger {
|
||||
wg: WaitGroup,
|
||||
status_s: Arc<Sender<VntStatus>>,
|
||||
status_r: Receiver<VntStatus>,
|
||||
}
|
||||
|
||||
impl VntStatusManger {
|
||||
pub fn new() -> Self {
|
||||
let (status_s, status_r) = watch::channel(VntStatus::Starting);
|
||||
Self {
|
||||
wg: WaitGroup::new(),
|
||||
status_s: Arc::new(status_s),
|
||||
status_r,
|
||||
}
|
||||
}
|
||||
pub fn stop_all(&self) {
|
||||
let _ = self.status_s.send(VntStatus::Stopping);
|
||||
}
|
||||
pub async fn wait(&mut self) {
|
||||
self.wg.wait().await
|
||||
}
|
||||
pub fn worker(&self, name: &str) -> VntWorker {
|
||||
self.wg.add();
|
||||
VntWorker {
|
||||
_name: name.to_string(),
|
||||
wg: self.wg.clone(),
|
||||
status_s: self.status_s.clone(),
|
||||
status_r: self.status_r.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
use std::io;
|
||||
use std::ops::Deref;
|
||||
use std::time::Duration;
|
||||
use tokio::runtime::Runtime;
|
||||
use crate::cipher::RsaCipher;
|
||||
use crate::core::{Config, Vnt, VntUtil};
|
||||
use crate::handle::handshake_handler::HandshakeEnum;
|
||||
use crate::handle::registration_handler::{RegResponse, ReqEnum};
|
||||
|
||||
pub struct VntUtilSync {
|
||||
vnt_util: VntUtil,
|
||||
runtime: Runtime,
|
||||
}
|
||||
|
||||
pub struct VntSync {
|
||||
vnt: Vnt,
|
||||
runtime: Runtime,
|
||||
}
|
||||
|
||||
impl VntUtilSync {
|
||||
pub fn new(config: Config) -> io::Result<VntUtilSync> {
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
|
||||
let vnt_util = runtime.block_on(VntUtil::new(config))?;
|
||||
Ok(VntUtilSync {
|
||||
vnt_util,
|
||||
runtime,
|
||||
})
|
||||
}
|
||||
pub fn connect(&mut self) -> io::Result<()> {
|
||||
self.runtime.block_on(self.vnt_util.connect())
|
||||
}
|
||||
pub fn handshake(&mut self) -> Result<Option<RsaCipher>, HandshakeEnum> {
|
||||
self.runtime.block_on(self.vnt_util.handshake())
|
||||
}
|
||||
pub fn secret_handshake(&mut self) -> Result<(), HandshakeEnum> {
|
||||
self.runtime.block_on(self.vnt_util.secret_handshake())
|
||||
}
|
||||
pub fn register(&mut self) -> Result<RegResponse, ReqEnum> {
|
||||
self.runtime.block_on(self.vnt_util.register())
|
||||
}
|
||||
#[cfg(any(target_os = "android"))]
|
||||
pub fn create_iface(&mut self, vpn_fd: i32) {
|
||||
self.vnt_util.create_iface(vpn_fd)
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
pub fn create_iface(&mut self) -> io::Result<crate::tun_tap_device::DriverInfo> {
|
||||
self.vnt_util.create_iface()
|
||||
}
|
||||
pub fn build(self) -> crate::Result<VntSync> {
|
||||
let runtime = self.runtime;
|
||||
let vnt = runtime.block_on(self.vnt_util.build())?;
|
||||
{
|
||||
let mut vnt = vnt.clone();
|
||||
std::thread::spawn(move || {
|
||||
runtime.block_on(vnt.wait_stop())
|
||||
});
|
||||
}
|
||||
Ok(VntSync {
|
||||
vnt,
|
||||
runtime: tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl VntSync {
|
||||
pub fn wait_stop(&mut self) {
|
||||
self.runtime.block_on(self.vnt.wait_stop())
|
||||
}
|
||||
pub fn wait_stop_ms(&mut self, ms: u64) -> bool {
|
||||
self.runtime.block_on(self.vnt.wait_stop_ms(Duration::from_millis(ms)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for VntSync {
|
||||
type Target = Vnt;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.vnt
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
use std::io;
|
||||
|
||||
use crossbeam::channel::RecvError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("packet error")]
|
||||
PacketError(#[from] packet::error::Error),
|
||||
#[error("Io error")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Channel error")]
|
||||
Channel(#[from] RecvError),
|
||||
#[error("Protobuf error")]
|
||||
Protobuf(#[from] protobuf::Error),
|
||||
#[error("Invalid packet")]
|
||||
@@ -19,6 +14,8 @@ pub enum Error {
|
||||
NotSupport,
|
||||
#[error("Stop")]
|
||||
Stop(String),
|
||||
#[error("Warn")]
|
||||
Warn(String),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -0,0 +1,48 @@
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
|
||||
// 目标ip,子网掩码,网关
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExternalRoute {
|
||||
route_table: Arc<Vec<(u32, u32, Ipv4Addr)>>,
|
||||
}
|
||||
|
||||
impl ExternalRoute {
|
||||
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
|
||||
Self {
|
||||
route_table: Arc::new(route_table)
|
||||
}
|
||||
}
|
||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
for (dest, mask, gateway) in self.route_table.iter() {
|
||||
if *mask & ip == *mask & *dest {
|
||||
return Some(*gateway);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AllowExternalRoute {
|
||||
route_table: Arc<Vec<(u32, u32)>>,
|
||||
}
|
||||
|
||||
impl AllowExternalRoute {
|
||||
pub fn new(route_table: Vec<(u32, u32)>) -> Self {
|
||||
Self {
|
||||
route_table: Arc::new(route_table)
|
||||
}
|
||||
}
|
||||
pub fn allow(&self, ip: &Ipv4Addr) -> bool {
|
||||
let ip = u32::from_be_bytes(ip.octets());
|
||||
for (dest, mask) in self.route_table.iter() {
|
||||
if *mask & ip == *mask & *dest {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
use std::net::SocketAddr;
|
||||
use std::time::Duration;
|
||||
|
||||
use protobuf::Message;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
|
||||
use crate::channel::channel::Context;
|
||||
use crate::cipher::{Cipher, RsaCipher};
|
||||
use crate::proto::message::{HandshakeRequest, HandshakeResponse, SecretHandshakeRequest};
|
||||
use crate::protocol::{MAX_TTL, NetPacket, Protocol, service_packet, Version};
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
|
||||
|
||||
pub enum HandshakeEnum {
|
||||
NotSecret,
|
||||
KeyError,
|
||||
Timeout,
|
||||
ServerError(String),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
fn handshake_request_packet(secret: bool) -> crate::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = HandshakeRequest::new();
|
||||
request.secret = secret;
|
||||
request.version = crate::VNT_VERSION.to_string();
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let buf = vec![0u8; 12 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_gateway_flag(true);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::HandshakeRequest.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_payload(&bytes)?;
|
||||
Ok(net_packet)
|
||||
}
|
||||
|
||||
fn secret_handshake_request_packet(rsa_cipher: &RsaCipher, token: String, key: &[u8]) -> crate::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = SecretHandshakeRequest::new();
|
||||
request.token = token;
|
||||
request.key = key.to_vec();
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_gateway_flag(true);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::SecretHandshakeRequest.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_payload(&bytes)?;
|
||||
Ok(rsa_cipher.encrypt(&mut net_packet)?)
|
||||
}
|
||||
|
||||
/// 第一次握手,拿到公钥
|
||||
pub async fn handshake(main_channel: &UdpSocket, main_tcp_channel: Option<&mut TcpStream>,
|
||||
server_address: SocketAddr, secret: bool) -> Result<Option<RsaCipher>, HandshakeEnum> {
|
||||
let request_packet = handshake_request_packet(secret).unwrap();
|
||||
let send_buf = request_packet.buffer();
|
||||
let mut recv_buf = [0u8; 10240];
|
||||
let len = send_recv(main_channel, main_tcp_channel, server_address, send_buf, &mut recv_buf).await?;
|
||||
let net_packet = match NetPacket::new(&recv_buf[..len]) {
|
||||
Ok(net_packet) => {
|
||||
net_packet
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(HandshakeEnum::Other(format!("net_packet {}", e)));
|
||||
}
|
||||
};
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::HandshakeResponse => {
|
||||
match HandshakeResponse::parse_from_bytes(net_packet.payload()) {
|
||||
Ok(response) => {
|
||||
if !response.secret && secret {
|
||||
//客户端要加密,服务端不支持加密
|
||||
return Err(HandshakeEnum::NotSecret);
|
||||
}
|
||||
if secret {
|
||||
//转换公钥
|
||||
match RsaCipher::new(&response.public_key) {
|
||||
Ok(rsa) => {
|
||||
match rsa.finger() {
|
||||
Ok(finger) => {
|
||||
if finger != response.key_finger {
|
||||
return Err(HandshakeEnum::Other("finger error".to_string()));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(HandshakeEnum::Other(format!("finger {}", e)));
|
||||
}
|
||||
}
|
||||
Ok(Some(rsa))
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(HandshakeEnum::Other(format!("RsaCipher {}", e)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(HandshakeEnum::Other(format!("parse_from_bytes {}", e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(HandshakeEnum::Other("not match".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(HandshakeEnum::Other("not match".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_recv(main_channel: &UdpSocket, main_tcp_channel: Option<&mut TcpStream>,
|
||||
server_address: SocketAddr, send_buf: &[u8], recv_buf: &mut [u8]) -> Result<usize, HandshakeEnum> {
|
||||
if let Some(main_tcp_channel) = main_tcp_channel {
|
||||
let mut head = [0; 4];
|
||||
let len = send_buf.len();
|
||||
head[2] = (len >> 8) as u8;
|
||||
head[3] = (len & 0xFF) as u8;
|
||||
if let Err(e) = main_tcp_channel.write_all(&head).await {
|
||||
return Err(HandshakeEnum::Other(format!("send error:{}", e)));
|
||||
}
|
||||
if let Err(e) = main_tcp_channel.write_all(send_buf).await {
|
||||
return Err(HandshakeEnum::Other(format!("send error:{}", e)));
|
||||
}
|
||||
if let Err(e) = main_tcp_channel.read_exact(&mut head).await {
|
||||
return Err(HandshakeEnum::Other(format!("read error:{}", e)));
|
||||
}
|
||||
let len = (((head[2] as u16) << 8) | head[3] as u16) as usize;
|
||||
if len > recv_buf.len() {
|
||||
return Err(HandshakeEnum::Other("too long".to_string()));
|
||||
}
|
||||
if let Err(e) = main_tcp_channel.read_exact(&mut recv_buf[..len]).await {
|
||||
return Err(HandshakeEnum::Other(format!("read error:{}", e)));
|
||||
}
|
||||
Ok(len)
|
||||
} else {
|
||||
if let Err(e) = main_channel.send_to(send_buf, server_address).await {
|
||||
return Err(HandshakeEnum::Other(format!("send error:{}", e)));
|
||||
}
|
||||
match tokio::time::timeout(Duration::from_millis(300), main_channel.recv_from(recv_buf)).await {
|
||||
Ok(rs) => {
|
||||
match rs {
|
||||
Ok((len, addr)) => {
|
||||
if server_address != addr {
|
||||
return Err(HandshakeEnum::Other(format!("invalid data,from {}", addr)));
|
||||
}
|
||||
Ok(len)
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(HandshakeEnum::Other(format!("receiver error:{}", e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(HandshakeEnum::Timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 第二次握手,同步对称密钥,后续将使用对称加密
|
||||
pub async fn secret_handshake(main_channel: &UdpSocket, main_tcp_channel: Option<&mut TcpStream>,
|
||||
server_address: SocketAddr, rsa_cipher: &RsaCipher, server_cipher: &Cipher, token: String)
|
||||
-> Result<(), HandshakeEnum> {
|
||||
let secret_packet = match secret_handshake_request_packet(rsa_cipher, token, server_cipher.key().unwrap()) {
|
||||
Ok(secret_packet) => {
|
||||
secret_packet
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(HandshakeEnum::Other(format!("secret_handshake_request_packet {}", e)));
|
||||
}
|
||||
};
|
||||
let send_buf = secret_packet.buffer();
|
||||
let mut recv_buf = [0u8; 10240];
|
||||
let len = send_recv(main_channel, main_tcp_channel, server_address, send_buf, &mut recv_buf).await?;
|
||||
let mut net_packet = match NetPacket::new(&mut recv_buf[..len]) {
|
||||
Ok(net_packet) => { net_packet }
|
||||
Err(e) => {
|
||||
return Err(HandshakeEnum::Other(format!("secret_net_packet {}", e)));
|
||||
}
|
||||
};
|
||||
match server_cipher.decrypt_ipv4(&mut net_packet) {
|
||||
Ok(_) => {
|
||||
if net_packet.is_gateway() && net_packet.protocol() == Protocol::Service
|
||||
&& service_packet::Protocol::from(net_packet.transport_protocol()) ==
|
||||
service_packet::Protocol::SecretHandshakeResponse {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(HandshakeEnum::Other("not match".to_string()))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Err(HandshakeEnum::Other(format!("decrypt_ipv4 {}", e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn secret_handshake_req(context: &Context,
|
||||
server_address: SocketAddr, rsa_cipher: &RsaCipher, server_cipher: &Cipher, token: String, ) -> crate::Result<()> {
|
||||
let secret_packet = secret_handshake_request_packet(rsa_cipher, token, server_cipher.key().unwrap())?;
|
||||
context.send_main(secret_packet.buffer(), server_address).await?;
|
||||
if context.is_main_tcp(){
|
||||
context.send_main_udp(secret_packet.buffer(),server_address).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::io;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use rand::prelude::SliceRandom;
|
||||
use crate::channel::idle::Idle;
|
||||
use crate::channel::Route;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntWorker;
|
||||
|
||||
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::protocol::control_packet::PingPacket;
|
||||
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, Version};
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
|
||||
pub fn start_idle(mut worker: VntWorker, idle: Idle, sender: ChannelSender) {
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
return;
|
||||
}
|
||||
rs=start_idle_(idle, sender)=>{
|
||||
if let Err(e) = rs {
|
||||
log::warn!("空闲检测任务停止:{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}
|
||||
|
||||
async fn start_idle_(idle: Idle, sender: ChannelSender) -> io::Result<()> {
|
||||
loop {
|
||||
let (peer_ip, route) = idle.next_idle().await?;
|
||||
log::info!(
|
||||
"peer_ip:{:?},route:{:?}",
|
||||
peer_ip,
|
||||
route
|
||||
);
|
||||
sender.remove_route(&peer_ip, route);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_heartbeat(
|
||||
mut worker: VntWorker,
|
||||
sender: ChannelSender,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
server_address_str: String,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
) {
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_=worker.stop_wait()=>{
|
||||
return;
|
||||
}
|
||||
rs=start_heartbeat_(sender, device_list, current_device,server_address_str,client_cipher,server_cipher)=>{
|
||||
if let Err(e) = rs {
|
||||
log::warn!("心跳任务停止:{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
fn heartbeat_packet(device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>, client_cipher: &Cipher, server_cipher: &Cipher, gateway: bool, src: Ipv4Addr, dest: Ipv4Addr) -> NetPacket<[u8; 48]> {
|
||||
let mut net_packet = NetPacket::new_encrypt([0u8; 12 + 4 + ENCRYPTION_RESERVED]).unwrap();
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::Control);
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
|
||||
//只寻找两跳以内能到的目标
|
||||
net_packet.first_set_ttl(2);
|
||||
net_packet.set_source(src);
|
||||
net_packet.set_destination(dest);
|
||||
{
|
||||
let mut ping = PingPacket::new(net_packet.payload_mut()).unwrap();
|
||||
let epoch = { device_list.lock().0 };
|
||||
ping.set_epoch(epoch);
|
||||
ping.set_time(crate::handle::now_time() as u16);
|
||||
}
|
||||
if gateway {
|
||||
net_packet.set_gateway_flag(true);
|
||||
server_cipher.encrypt_ipv4(&mut net_packet).unwrap();
|
||||
} else {
|
||||
client_cipher.encrypt_ipv4(&mut net_packet).unwrap();
|
||||
}
|
||||
net_packet
|
||||
}
|
||||
|
||||
async fn start_heartbeat_(
|
||||
sender: ChannelSender,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
server_address_str: String,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
) -> io::Result<()> {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
if sender.is_close() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut current_dev = current_device.load();
|
||||
//如果和服务端使用tcp连接,则维持udp洞的频率要更高些
|
||||
if (sender.is_main_tcp() && count % 2 == 0) || (!sender.is_main_tcp() && count % 20 == 1) {
|
||||
let mut packet = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
|
||||
packet.set_version(Version::V1);
|
||||
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(current_dev.virtual_ip());
|
||||
packet.set_destination(current_dev.virtual_gateway);
|
||||
server_cipher.encrypt_ipv4(&mut packet)?;
|
||||
let _ = sender.send_main_udp(packet.buffer(), current_dev.connect_server).await;
|
||||
}
|
||||
if count % 20 == 19 {
|
||||
if let Ok(mut addr) = server_address_str.to_socket_addrs() {
|
||||
if let Some(addr) = addr.next() {
|
||||
if addr != current_dev.connect_server {
|
||||
let mut tmp = current_dev.clone();
|
||||
tmp.connect_server = addr;
|
||||
if current_device.compare_exchange(current_dev, tmp).is_ok() {
|
||||
current_dev.connect_server = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let src = current_dev.virtual_ip();
|
||||
let server_packet = heartbeat_packet(&device_list, &client_cipher, &server_cipher, true, src, current_dev.virtual_gateway);
|
||||
if let Err(e) = sender.send_main(server_packet.buffer(), current_dev.connect_server).await
|
||||
{
|
||||
log::warn!(
|
||||
"connect_server:{:?},e:{:?}",
|
||||
current_dev.connect_server,
|
||||
e
|
||||
);
|
||||
}
|
||||
if count < 7 || count % 7 == 0 {
|
||||
let mut route_list: Option<Vec<(Ipv4Addr, Vec<Route>)>> = None;
|
||||
let peer_list = { device_list.lock().1.clone() };
|
||||
for peer in peer_list {
|
||||
if peer.virtual_ip == current_dev.virtual_ip {
|
||||
continue;
|
||||
}
|
||||
let client_packet = heartbeat_packet(&device_list, &client_cipher, &server_cipher, false, src, peer.virtual_ip);
|
||||
if let Some(route) = sender.route_one(&peer.virtual_ip) {
|
||||
let _ = sender.send_by_key(client_packet.buffer(), &route.route_key()).await;
|
||||
if route.is_p2p() {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
//没有直连路由则发送到网关
|
||||
let _ = sender.send_main(client_packet.buffer(), current_dev.connect_server).await;
|
||||
}
|
||||
|
||||
//再随机发送到其他地址,看有没有客户端符合转发条件
|
||||
let route_list = route_list.get_or_insert_with(|| {
|
||||
let mut l = sender.route_table();
|
||||
l.shuffle(&mut rand::thread_rng());
|
||||
l
|
||||
});
|
||||
let mut num = 0;
|
||||
'a: for (peer_ip, route_list) in route_list.iter() {
|
||||
for route in route_list {
|
||||
if peer_ip != &peer.virtual_ip && route.is_p2p() {
|
||||
let _ = sender.try_send_by_key(client_packet.buffer(), &route.route_key());
|
||||
num += 1;
|
||||
break;
|
||||
}
|
||||
if num >= 2 {
|
||||
break 'a;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||
}
|
||||
} else {
|
||||
for (peer_ip, route_list) in sender.route_table().iter() {
|
||||
if peer_ip == ¤t_dev.virtual_gateway {
|
||||
continue;
|
||||
}
|
||||
let client_packet = heartbeat_packet(&device_list, &client_cipher, &server_cipher, false, src, *peer_ip);
|
||||
for route in route_list {
|
||||
if let Err(e) = sender.send_by_key(client_packet.buffer(), &route.route_key()).await {
|
||||
log::warn!("peer_ip:{:?},route:{:?},e:{:?}", peer_ip, route, e);
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count += 1;
|
||||
tokio::time::sleep(Duration::from_millis(5000)).await;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
|
||||
pub mod handshake_handler;
|
||||
pub mod heartbeat_handler;
|
||||
pub mod punch_handler;
|
||||
pub mod recv_handler;
|
||||
pub mod registration_handler;
|
||||
pub mod tun_tap;
|
||||
|
||||
pub fn now_time() -> u64 {
|
||||
let now = std::time::SystemTime::now();
|
||||
if let Ok(timestamp) = now.duration_since(std::time::UNIX_EPOCH) {
|
||||
timestamp.as_secs() * 1000 + u64::from(timestamp.subsec_millis())
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否在一个网段
|
||||
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,
|
||||
pub name: String,
|
||||
pub status: PeerDeviceStatus,
|
||||
pub client_secret: bool,
|
||||
}
|
||||
|
||||
impl PeerDeviceInfo {
|
||||
pub fn new(virtual_ip: Ipv4Addr, name: String, status: u8,client_secret: bool) -> Self {
|
||||
Self {
|
||||
virtual_ip,
|
||||
name,
|
||||
status: PeerDeviceStatus::from(status),
|
||||
client_secret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq,Ord, PartialOrd)]
|
||||
pub enum PeerDeviceStatus {
|
||||
Online,
|
||||
Offline,
|
||||
}
|
||||
|
||||
impl Into<u8> for PeerDeviceStatus {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
PeerDeviceStatus::Online => 0,
|
||||
PeerDeviceStatus::Offline => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for PeerDeviceStatus {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
0 => PeerDeviceStatus::Online,
|
||||
_ => PeerDeviceStatus::Offline,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ConnectStatus {
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct CurrentDeviceInfo {
|
||||
virtual_ip: Ipv4Addr,
|
||||
pub virtual_gateway: Ipv4Addr,
|
||||
pub virtual_netmask: Ipv4Addr,
|
||||
//网络地址
|
||||
pub virtual_network: Ipv4Addr,
|
||||
//直接广播地址
|
||||
pub broadcast_address: Ipv4Addr,
|
||||
//链接的服务器地址
|
||||
pub connect_server: SocketAddr,
|
||||
|
||||
}
|
||||
|
||||
impl CurrentDeviceInfo {
|
||||
pub fn new(
|
||||
virtual_ip: Ipv4Addr,
|
||||
virtual_gateway: Ipv4Addr,
|
||||
virtual_netmask: Ipv4Addr,
|
||||
connect_server: SocketAddr,
|
||||
) -> Self {
|
||||
let broadcast_address = (!u32::from_be_bytes(virtual_netmask.octets()))
|
||||
| u32::from_be_bytes(virtual_gateway.octets());
|
||||
let broadcast_address = Ipv4Addr::from(broadcast_address);
|
||||
let virtual_network = u32::from_be_bytes(virtual_netmask.octets())
|
||||
& u32::from_be_bytes(virtual_gateway.octets());
|
||||
let virtual_network = Ipv4Addr::from(virtual_network);
|
||||
Self {
|
||||
virtual_ip,
|
||||
virtual_netmask,
|
||||
virtual_gateway,
|
||||
virtual_network,
|
||||
broadcast_address,
|
||||
connect_server,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn virtual_ip(&self) -> Ipv4Addr {
|
||||
self.virtual_ip
|
||||
}
|
||||
#[inline]
|
||||
pub fn virtual_gateway(&self) -> Ipv4Addr {
|
||||
self.virtual_gateway
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::nat::NatTest;
|
||||
use crate::proto::message::{PunchInfo, PunchNatType};
|
||||
use crate::protocol::{control_packet, other_turn_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use protobuf::Message;
|
||||
use rand::prelude::SliceRandom;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::io;
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
use crate::channel::punch::{NatInfo, Punch};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntWorker;
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
|
||||
pub fn start(mut worker: VntWorker, receiver: Receiver<(Ipv4Addr, NatInfo)>,
|
||||
punch: Punch, current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
client_cipher: Cipher, ) {
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_=start0(receiver, punch, current_device,client_cipher)=>{}
|
||||
_=worker.stop_wait()=>{
|
||||
return;
|
||||
}
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn start0(mut receiver: Receiver<(Ipv4Addr, NatInfo)>,
|
||||
mut punch: Punch, current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
client_cipher: Cipher, ) {
|
||||
while let Some((peer_ip, nat_info)) = receiver.recv().await {
|
||||
if let Err(e) = start_(&client_cipher, &mut punch, ¤t_device, peer_ip, nat_info).await {
|
||||
log::warn!("网络打洞异常 {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_(
|
||||
client_cipher: &Cipher,
|
||||
punch: &mut Punch,
|
||||
current_device: &Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
peer_ip: Ipv4Addr,
|
||||
nat_info: NatInfo,
|
||||
) -> io::Result<()> {
|
||||
let mut packet = NetPacket::new_encrypt([0u8; 12 + ENCRYPTION_RESERVED])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.first_set_ttl(1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
packet.set_source(current_device.load().virtual_ip());
|
||||
packet.set_destination(peer_ip);
|
||||
log::info!("发起打洞,目标:{:?},{:?}", peer_ip, nat_info);
|
||||
client_cipher.encrypt_ipv4(&mut packet)?;
|
||||
punch.punch(packet.buffer(), peer_ip, nat_info).await
|
||||
}
|
||||
|
||||
pub async fn start_punch(
|
||||
mut worker: VntWorker,
|
||||
nat_test: NatTest,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
sender: ChannelSender,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
client_cipher: Cipher,
|
||||
) {
|
||||
let mut num = 0;
|
||||
let sleep_time = [3, 5, 7, 11, 13, 17, 19, 23, 29];
|
||||
loop {
|
||||
if sender.is_close() {
|
||||
break;
|
||||
}
|
||||
tokio::select! {
|
||||
rs= start_punch_(Duration::from_secs(sleep_time[num % sleep_time.len()]),&nat_test, &device_list,
|
||||
&sender, ¤t_device,&client_cipher)=>{
|
||||
if let Err(e) = rs {
|
||||
log::warn!("打洞处理任务异常 {:?}", e);
|
||||
}
|
||||
}
|
||||
_=worker.stop_wait()=>{
|
||||
break;
|
||||
}
|
||||
}
|
||||
num += 1;
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_punch_(
|
||||
sleep_time: Duration,
|
||||
nat_test: &NatTest,
|
||||
device_list: &Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
sender: &ChannelSender,
|
||||
current_device: &Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
client_cipher: &Cipher,
|
||||
) -> crate::Result<()> {
|
||||
let current_device = current_device.load();
|
||||
let nat_info = nat_test.nat_info();
|
||||
let mut list = device_list.lock().clone().1;
|
||||
list.shuffle(&mut rand::thread_rng());
|
||||
let mut count = 0;
|
||||
for info in list {
|
||||
if info.virtual_ip <= current_device.virtual_ip {
|
||||
continue;
|
||||
}
|
||||
if !sender.need_punch(&info.virtual_ip) {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
if count > 2 {
|
||||
break;
|
||||
}
|
||||
let packet = punch_packet(client_cipher, current_device.virtual_ip(), &nat_info, info.virtual_ip)?;
|
||||
let _ = sender.send_main(packet.buffer(), current_device.connect_server).await;
|
||||
}
|
||||
tokio::time::sleep(sleep_time).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn punch_packet(
|
||||
client_cipher: &Cipher,
|
||||
virtual_ip: Ipv4Addr,
|
||||
nat_info: &NatInfo,
|
||||
dest: Ipv4Addr,
|
||||
) -> crate::Result<NetPacket<Vec<u8>>> {
|
||||
let mut punch_reply = PunchInfo::new();
|
||||
punch_reply.reply = false;
|
||||
punch_reply.public_ip_list = nat_info
|
||||
.public_ips
|
||||
.iter()
|
||||
.map(|ip| u32::from_be_bytes(ip.octets()))
|
||||
.collect();
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ip.octets());
|
||||
punch_reply.local_port = nat_info.local_port as u32;
|
||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::OtherTurn);
|
||||
net_packet.set_transport_protocol(other_turn_packet::Protocol::Punch.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_source(virtual_ip);
|
||||
net_packet.set_destination(dest);
|
||||
net_packet.set_payload(&bytes)?;
|
||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
Ok(net_packet)
|
||||
}
|
||||
@@ -0,0 +1,609 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use dashmap::DashMap;
|
||||
use parking_lot::Mutex;
|
||||
use protobuf::Message;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
|
||||
use packet::icmp::{icmp, Kind};
|
||||
use packet::icmp::icmp::HeaderOther;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::channel::{Route, RouteKey};
|
||||
use crate::channel::channel::Context;
|
||||
use crate::channel::punch::{NatInfo, NatType};
|
||||
use crate::cipher::{Cipher, RsaCipher};
|
||||
use crate::error::Error;
|
||||
use crate::external_route::AllowExternalRoute;
|
||||
use crate::handle::{ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, PeerDeviceStatus};
|
||||
use crate::handle::handshake_handler::secret_handshake_req;
|
||||
use crate::handle::registration_handler::Register;
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::nat;
|
||||
use crate::nat::NatTest;
|
||||
use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationResponse};
|
||||
use crate::protocol::{control_packet, ip_turn_packet, MAX_TTL, NetPacket, other_turn_packet, Protocol, service_packet, Version};
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
use crate::protocol::control_packet::ControlPacket;
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::tun_tap_device::DeviceWriter;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChannelDataHandler {
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
register: Arc<Register>,
|
||||
nat_test: NatTest,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
device_writer: DeviceWriter,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<DashMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
out_external_route: AllowExternalRoute,
|
||||
cone_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
symmetric_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
rsa_cipher: Option<RsaCipher>,
|
||||
relay: bool,
|
||||
token: String,
|
||||
}
|
||||
|
||||
impl ChannelDataHandler {
|
||||
pub fn new(current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
register: Arc<Register>,
|
||||
nat_test: NatTest,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
device_writer: DeviceWriter,
|
||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||
peer_nat_info_map: Arc<DashMap<Ipv4Addr, NatInfo>>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
out_external_route: AllowExternalRoute,
|
||||
cone_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
symmetric_sender: Sender<(Ipv4Addr, NatInfo)>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
rsa_cipher: Option<RsaCipher>,
|
||||
relay: bool, token: String, ) -> Self {
|
||||
Self {
|
||||
current_device,
|
||||
device_list,
|
||||
register,
|
||||
nat_test,
|
||||
igmp_server,
|
||||
device_writer,
|
||||
connect_status,
|
||||
peer_nat_info_map,
|
||||
ip_proxy_map,
|
||||
out_external_route,
|
||||
cone_sender,
|
||||
symmetric_sender,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
rsa_cipher,
|
||||
relay,
|
||||
token,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl ChannelDataHandler {
|
||||
pub async fn handle(&self, buf: &mut [u8], start: usize, end: usize, route_key: RouteKey, context: &Context) {
|
||||
assert_eq!(start, 14);
|
||||
match self.handle0(&mut buf[..end], &route_key, context).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn handle0(&self, buf: &mut [u8], route_key: &RouteKey, context: &Context) -> crate::Result<()> {
|
||||
let mut net_packet = NetPacket::new(&mut buf[14..])?;
|
||||
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
|
||||
return Ok(());
|
||||
}
|
||||
let source = net_packet.source();
|
||||
context.update_read_time(&source, route_key);
|
||||
let current_device = self.current_device.load();
|
||||
let destination = net_packet.destination();
|
||||
let not_broadcast = !destination.is_broadcast() && !destination.is_multicast() && destination != current_device.broadcast_address;
|
||||
if current_device.virtual_ip() != destination
|
||||
&& not_broadcast && !destination.is_unspecified() {
|
||||
//校验指纹,不需要解密
|
||||
self.client_cipher.check_finger(&net_packet)?;
|
||||
net_packet.set_ttl(net_packet.ttl() - 1);
|
||||
let ttl = net_packet.ttl();
|
||||
if ttl > 0 {
|
||||
// 转发
|
||||
if let Some(route) = context.route_one(&destination) {
|
||||
if route.metric <= net_packet.ttl() {
|
||||
context.send_by_key(net_packet.buffer(), &route.route_key()).await?;
|
||||
}
|
||||
} else if (ttl > 1 || destination == current_device.virtual_gateway())
|
||||
&& source != current_device.virtual_gateway() {
|
||||
//网关默认要转发一次,生存时间不够的发到网关也会被丢弃
|
||||
context.send_main(net_packet.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if net_packet.is_gateway() {
|
||||
if net_packet.protocol() == Protocol::Error && net_packet.transport_protocol() == crate::protocol::error_packet::Protocol::NoKey.into() {
|
||||
if let Some(rsa_cipher) = &self.rsa_cipher {
|
||||
secret_handshake_req(context, current_device.connect_server, rsa_cipher, &self.server_cipher, self.token.clone()).await?;
|
||||
}
|
||||
} else {
|
||||
//服务端解密
|
||||
self.server_cipher.decrypt_ipv4(&mut net_packet)?;
|
||||
let data_len = net_packet.data_len();
|
||||
self.server_packet_handle(context, current_device, buf, data_len, route_key).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
self.client_cipher.decrypt_ipv4(&mut net_packet)?;
|
||||
match net_packet.protocol() {
|
||||
Protocol::IpTurn => {
|
||||
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
ip_turn_packet::Protocol::Ipv4 => {
|
||||
let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?;
|
||||
match ipv4.protocol() {
|
||||
ipv4::protocol::Protocol::Igmp => {
|
||||
if let Some(igmp_server) = &self.igmp_server {
|
||||
igmp_server.handle(ipv4.payload(), source)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
ipv4::protocol::Protocol::Icmp => {
|
||||
if ipv4.destination_ip() == destination {
|
||||
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
|
||||
if icmp_packet.kind() == Kind::EchoRequest {
|
||||
//开启ping
|
||||
icmp_packet.set_kind(Kind::EchoReply);
|
||||
icmp_packet.update_checksum();
|
||||
ipv4.set_source_ip(destination);
|
||||
ipv4.set_destination_ip(source);
|
||||
ipv4.update_checksum();
|
||||
net_packet.set_source(destination);
|
||||
net_packet.set_destination(source);
|
||||
//不管加不加密,和接收到的数据长度都一致
|
||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
context.send_by_key(net_packet.buffer(), route_key).await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if not_broadcast && ipv4.destination_ip() != destination {
|
||||
if let Some(ip_proxy_map) = &self.ip_proxy_map {
|
||||
if self.out_external_route.allow(&ipv4.destination_ip()) {
|
||||
match ipv4.protocol() {
|
||||
ipv4::protocol::Protocol::Tcp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||
let source_port = tcp_packet.source_port();
|
||||
let dest_port = tcp_packet.destination_port();
|
||||
tcp_packet.set_destination_port(ip_proxy_map.tcp_proxy_port);
|
||||
tcp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
let key = SocketAddrV4::new(source, source_port);
|
||||
//https://github.com/crossbeam-rs/crossbeam/issues/1023
|
||||
ip_proxy_map.tcp_proxy_map.insert(key, SocketAddrV4::new(dest_ip, dest_port));
|
||||
}
|
||||
ipv4::protocol::Protocol::Udp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let mut udp_packet = packet::udp::udp::UdpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||
let source_port = udp_packet.source_port();
|
||||
let dest_port = udp_packet.destination_port();
|
||||
udp_packet.set_destination_port(ip_proxy_map.udp_proxy_port);
|
||||
udp_packet.update_checksum();
|
||||
ipv4.set_destination_ip(destination);
|
||||
ipv4.update_checksum();
|
||||
let key = SocketAddrV4::new(source, source_port);
|
||||
ip_proxy_map.udp_proxy_map.insert(key, SocketAddrV4::new(dest_ip, dest_port));
|
||||
}
|
||||
ipv4::protocol::Protocol::Icmp => {
|
||||
let dest_ip = ipv4.destination_ip();
|
||||
//转发到代理目标地址
|
||||
let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?;
|
||||
match icmp_packet.header_other() {
|
||||
HeaderOther::Identifier(id, seq) => {
|
||||
ip_proxy_map.icmp_proxy_map.insert((dest_ip, id, seq), source);
|
||||
ip_proxy_map.send_icmp(ipv4.payload(), &dest_ip)?;
|
||||
}
|
||||
_ => {
|
||||
log::warn!("不支持的ip代理Icmp协议:{}",destination);
|
||||
return Err(Error::Warn("不支持的ip代理Icmp协议".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
log::warn!("不支持的ip代理ipv4协议:{}",destination);
|
||||
return Err(Error::Warn("不支持的ip代理ipv4协议".to_string()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("没有ip代理规则:{}",destination);
|
||||
return Err(Error::Warn("没有ip代理规则".to_string()));
|
||||
}
|
||||
} else {
|
||||
log::warn!("不支持ip代理:{}",destination);
|
||||
return Err(Error::Warn("不支持ip代理".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
//传输协议12字节
|
||||
self.device_writer.write_ipv4(&mut buf[12..])?;
|
||||
return Ok(());
|
||||
}
|
||||
ip_turn_packet::Protocol::Ipv4Broadcast => {
|
||||
//客户端不帮忙转发广播包,所以不会出现这种类型的数据
|
||||
}
|
||||
ip_turn_packet::Protocol::Unknown(_) => {}
|
||||
}
|
||||
}
|
||||
Protocol::Service => {}
|
||||
Protocol::Error => {}
|
||||
Protocol::Control => {
|
||||
self.control(context, current_device, source, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::OtherTurn => {
|
||||
self.other_turn(context, current_device, source, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::UnKnow(e) => {
|
||||
log::info!("不支持的协议:{}",e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn pong_packet(&self, gateway: bool, metric: u8, context: &Context, current_device: CurrentDeviceInfo, source: Ipv4Addr, pong_packet: control_packet::PongPacket<&[u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
let current_time = crate::handle::now_time() as u16;
|
||||
if current_time < pong_packet.time() {
|
||||
return Ok(());
|
||||
}
|
||||
let rt = (current_time - pong_packet.time()) as i64;
|
||||
let route = Route::from(*route_key, metric, rt);
|
||||
context.add_route(source, route);
|
||||
if gateway {
|
||||
let epoch = self.device_list.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(source);
|
||||
poll_device.set_version(Version::V1);
|
||||
poll_device.set_gateway_flag(true);
|
||||
poll_device.first_set_ttl(MAX_TTL);
|
||||
poll_device.set_protocol(Protocol::Service);
|
||||
poll_device.set_transport_protocol(service_packet::Protocol::PollDeviceList.into());
|
||||
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
|
||||
context.send_main(poll_device.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn control(&self, context: &Context, current_device: CurrentDeviceInfo, source: Ipv4Addr, mut net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
||||
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).await?;
|
||||
let route = Route::from(*route_key, metric, 199);
|
||||
context.add_route_if_absent(source, route);
|
||||
}
|
||||
ControlPacket::PongPacket(pong_packet) => {
|
||||
self.pong_packet(false, metric, context, current_device, source, pong_packet, route_key).await?;
|
||||
}
|
||||
ControlPacket::PunchRequest => {
|
||||
if self.relay {
|
||||
return Ok(());
|
||||
}
|
||||
//回应
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::PunchResponse.into());
|
||||
net_packet.set_source(current_device.virtual_ip());
|
||||
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).await?;
|
||||
let route = Route::from(*route_key, 1, 199);
|
||||
context.add_route_if_absent(source, route);
|
||||
}
|
||||
ControlPacket::PunchResponse => {
|
||||
if self.relay {
|
||||
return Ok(());
|
||||
}
|
||||
let route = Route::from(*route_key, 1, 199);
|
||||
context.add_route_if_absent(source, route);
|
||||
}
|
||||
ControlPacket::AddrRequest => {
|
||||
match route_key.addr.ip() {
|
||||
std::net::IpAddr::V4(ipv4) => {
|
||||
let mut packet = NetPacket::new_encrypt([0; 12 + 6 + ENCRYPTION_RESERVED])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(
|
||||
control_packet::Protocol::AddrResponse.into(),
|
||||
);
|
||||
packet.first_set_ttl(MAX_TTL);
|
||||
packet.set_source(current_device.virtual_ip());
|
||||
packet.set_destination(source);
|
||||
let mut addr_packet = control_packet::AddrPacket::new(packet.payload_mut())?;
|
||||
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).await?;
|
||||
}
|
||||
std::net::IpAddr::V6(_) => {}
|
||||
}
|
||||
}
|
||||
ControlPacket::AddrResponse(addr_packet) => {
|
||||
if !addr_packet.ipv4().is_multicast()
|
||||
&& !addr_packet.ipv4().is_broadcast()
|
||||
&& !addr_packet.ipv4().is_unspecified()
|
||||
&& !addr_packet.ipv4().is_loopback()
|
||||
&& !addr_packet.ipv4().is_private() && addr_packet.port() != 0 {
|
||||
self.nat_test.update_addr(addr_packet.ipv4(), addr_packet.port())
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn other_turn(&self, context: &Context, current_device: CurrentDeviceInfo, source: Ipv4Addr, net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
if self.relay {
|
||||
return Ok(());
|
||||
}
|
||||
match other_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
other_turn_packet::Protocol::Punch => {
|
||||
let punch_info = PunchInfo::parse_from_bytes(net_packet.payload())?;
|
||||
let public_ips = punch_info.public_ip_list.
|
||||
iter().map(|v| { Ipv4Addr::from(v.to_be_bytes()) }).collect();
|
||||
let peer_nat_info = NatInfo::new(public_ips,
|
||||
punch_info.public_port as u16,
|
||||
punch_info.public_port_range as u16,
|
||||
Ipv4Addr::from(punch_info.local_ip.to_be_bytes()),
|
||||
punch_info.local_port as u16,
|
||||
punch_info.nat_type.enum_value_or_default().into());
|
||||
self.peer_nat_info_map.insert(source, peer_nat_info.clone());
|
||||
if !punch_info.reply {
|
||||
let mut punch_reply = PunchInfo::new();
|
||||
punch_reply.reply = true;
|
||||
let nat_info = self.nat_test.nat_info();
|
||||
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|ip| u32::from_be_bytes(ip.octets())).collect();
|
||||
punch_reply.public_port = nat_info.public_port as u32;
|
||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||
punch_reply.nat_type =
|
||||
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||
punch_reply.local_ip = u32::from_be_bytes(nat_info.local_ip.octets());
|
||||
punch_reply.local_port = nat_info.local_port as u32;
|
||||
let bytes = punch_reply.write_to_bytes()?;
|
||||
let mut punch_packet =
|
||||
NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
|
||||
punch_packet.set_version(Version::V1);
|
||||
punch_packet.set_protocol(Protocol::OtherTurn);
|
||||
punch_packet.set_transport_protocol(
|
||||
other_turn_packet::Protocol::Punch.into(),
|
||||
);
|
||||
punch_packet.first_set_ttl(MAX_TTL);
|
||||
punch_packet.set_source(current_device.virtual_ip());
|
||||
punch_packet.set_destination(source);
|
||||
punch_packet.set_payload(&bytes)?;
|
||||
if !peer_nat_info.local_ip.is_unspecified() && peer_nat_info.local_port != 0 {
|
||||
let mut packet = NetPacket::new_encrypt([0u8; 12 + ENCRYPTION_RESERVED])?;
|
||||
packet.set_version(Version::V1);
|
||||
packet.first_set_ttl(1);
|
||||
packet.set_protocol(Protocol::Control);
|
||||
packet.set_transport_protocol(control_packet::Protocol::PunchRequest.into());
|
||||
packet.set_source(current_device.virtual_ip());
|
||||
packet.set_destination(source);
|
||||
self.client_cipher.encrypt_ipv4(&mut packet)?;
|
||||
let _ = context.send_main(packet.buffer(), SocketAddr::V4(SocketAddrV4::new(peer_nat_info.local_ip, peer_nat_info.local_port))).await;
|
||||
}
|
||||
if self.punch(source, peer_nat_info).await {
|
||||
self.client_cipher.encrypt_ipv4(&mut punch_packet)?;
|
||||
context.send_by_key(punch_packet.buffer(), route_key).await?;
|
||||
}
|
||||
} else {
|
||||
self.punch(source, peer_nat_info).await;
|
||||
}
|
||||
}
|
||||
other_turn_packet::Protocol::Unknown(e) => {
|
||||
log::warn!("不支持的转发协议 {:?},source:{:?}",e,source);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn punch(&self, peer_ip: Ipv4Addr, peer_nat_info: NatInfo) -> bool {
|
||||
match peer_nat_info.nat_type {
|
||||
NatType::Symmetric => {
|
||||
self.symmetric_sender.try_send((peer_ip, peer_nat_info)).is_ok()
|
||||
}
|
||||
NatType::Cone => {
|
||||
self.cone_sender.try_send((peer_ip, peer_nat_info)).is_ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理服务端数据
|
||||
impl ChannelDataHandler {
|
||||
async fn server_packet_handle(&self, context: &Context, current_device: CurrentDeviceInfo, buf: &mut [u8], data_len: usize, route_key: &RouteKey) -> crate::Result<()> {
|
||||
let net_packet = NetPacket::new0(data_len, &buf[14..])?;
|
||||
let source = net_packet.source();
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
self.service(context, current_device, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::Error => {
|
||||
self.error(context, current_device, source, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::Control => {
|
||||
self.control_gateway(context, current_device, net_packet, route_key).await?;
|
||||
}
|
||||
Protocol::IpTurn => {
|
||||
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
ip_turn_packet::Protocol::Ipv4 => {
|
||||
let ipv4 = IpV4Packet::new(net_packet.payload())?;
|
||||
match ipv4.protocol() {
|
||||
ipv4::protocol::Protocol::Igmp => {
|
||||
if let Some(igmp_server) = &self.igmp_server {
|
||||
igmp_server.handle(ipv4.payload(), source)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
ipv4::protocol::Protocol::Icmp => {
|
||||
if ipv4.destination_ip() == current_device.virtual_ip {
|
||||
let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?;
|
||||
if icmp_packet.kind() == Kind::EchoReply {
|
||||
self.device_writer.write_ipv4(&mut buf[12..])?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ip_turn_packet::Protocol::Ipv4Broadcast => {}
|
||||
ip_turn_packet::Protocol::Unknown(_) => {}
|
||||
}
|
||||
}
|
||||
Protocol::OtherTurn => {}
|
||||
Protocol::UnKnow(_) => {}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
async fn control_gateway(&self, context: &Context, current_device: CurrentDeviceInfo, net_packet: NetPacket<&[u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
if net_packet.source() != current_device.virtual_gateway {
|
||||
return Ok(());
|
||||
}
|
||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
ControlPacket::PongPacket(pong_packet) => {
|
||||
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
||||
self.pong_packet(true, metric, context, current_device, net_packet.source(), pong_packet, route_key).await?;
|
||||
}
|
||||
ControlPacket::AddrResponse(addr_packet) => {
|
||||
if addr_packet.port() != 0
|
||||
&& !addr_packet.ipv4().is_multicast()
|
||||
&& !addr_packet.ipv4().is_broadcast()
|
||||
&& !addr_packet.ipv4().is_unspecified()
|
||||
&& !addr_packet.ipv4().is_loopback()
|
||||
&& !addr_packet.ipv4().is_private() {
|
||||
self.nat_test.update_addr(addr_packet.ipv4(), addr_packet.port())
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn service(&self, context: &Context, current_device: CurrentDeviceInfo, net_packet: NetPacket<&[u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationRequest => {}
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||
let local_port = context.main_local_port()?;
|
||||
let local_ip = nat::local_ip()?;
|
||||
let nat_info = self.nat_test.re_test(Ipv4Addr::from(response.public_ip),
|
||||
response.public_port as u16, local_ip, local_port).await;
|
||||
context.switch(nat_info.nat_type);
|
||||
let new_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let current_ip = current_device.virtual_ip();
|
||||
if current_ip != new_ip {
|
||||
// ip发生变化
|
||||
log::info!("ip发生变化,old_ip:{:?},new_ip:{:?}",current_ip,new_ip);
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
let old_netmask = current_device.virtual_netmask;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
let old_gateway = current_device.virtual_gateway();
|
||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
self.device_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
|
||||
let new_current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway,
|
||||
virtual_netmask, current_device.connect_server);
|
||||
if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) {
|
||||
log::warn!("替换失败:{:?}",e);
|
||||
}
|
||||
}
|
||||
self.connect_status.store(ConnectStatus::Connected);
|
||||
}
|
||||
service_packet::Protocol::PollDeviceList => {}
|
||||
service_packet::Protocol::PushDeviceList => {
|
||||
let device_list_t = DeviceList::parse_from_bytes(net_packet.payload())?;
|
||||
let ip_list: Vec<PeerDeviceInfo> = device_list_t
|
||||
.device_info_list
|
||||
.into_iter()
|
||||
.map(|info| {
|
||||
PeerDeviceInfo::new(
|
||||
Ipv4Addr::from(info.virtual_ip),
|
||||
info.name,
|
||||
info.device_status as u8,
|
||||
info.client_secret,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let route = Route::from(*route_key, 2, 99);
|
||||
for x in &ip_list {
|
||||
if x.status == PeerDeviceStatus::Online {
|
||||
context.add_route_if_absent(x.virtual_ip, route);
|
||||
}
|
||||
}
|
||||
let mut dev = self.device_list.lock();
|
||||
if dev.0 != device_list_t.epoch as u16 {
|
||||
dev.0 = device_list_t.epoch as u16;
|
||||
dev.1 = ip_list;
|
||||
}
|
||||
}
|
||||
service_packet::Protocol::Unknown(u) => {
|
||||
log::warn!("未知服务协议:{}",u);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn error(&self, _context: &Context, current_device: CurrentDeviceInfo, _source: Ipv4Addr, net_packet: NetPacket<&[u8]>, _route_key: &RouteKey) -> crate::Result<()> {
|
||||
log::info!("current_device:{:?}",current_device);
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
InErrorPacket::TokenError => {
|
||||
return Err(Error::Stop("Token error".to_string()));
|
||||
}
|
||||
InErrorPacket::Disconnect => {
|
||||
{
|
||||
//掉线epoch要归零
|
||||
let mut dev = self.device_list.lock();
|
||||
dev.0 = 0;
|
||||
}
|
||||
|
||||
self.connect_status.store(ConnectStatus::Connecting);
|
||||
self.register.fast_register(current_device.virtual_ip).await?;
|
||||
}
|
||||
InErrorPacket::AddressExhausted => {
|
||||
//地址用尽
|
||||
return Err(Error::Stop("IP address has been exhausted".to_string()));
|
||||
}
|
||||
InErrorPacket::OtherError(e) => {
|
||||
log::error!("OtherError {:?}", e.message());
|
||||
}
|
||||
InErrorPacket::IpAlreadyExists => {
|
||||
log::error!("IpAlreadyExists");
|
||||
}
|
||||
InErrorPacket::InvalidIp => {
|
||||
log::error!("InvalidIp");
|
||||
}
|
||||
InErrorPacket::NoKey => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::time::{Duration, Instant};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use protobuf::Message;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::{TcpStream, UdpSocket};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::handle::PeerDeviceInfo;
|
||||
|
||||
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::protocol::{service_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
|
||||
pub enum ReqEnum {
|
||||
TokenError,
|
||||
AddressExhausted,
|
||||
IpAlreadyExists,
|
||||
InvalidIp,
|
||||
Timeout,
|
||||
ServerError(String),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RegResponse {
|
||||
pub virtual_ip: Ipv4Addr,
|
||||
pub virtual_gateway: Ipv4Addr,
|
||||
pub virtual_netmask: Ipv4Addr,
|
||||
pub epoch: u16,
|
||||
pub device_info_list: Vec<PeerDeviceInfo>,
|
||||
pub public_ip: Ipv4Addr,
|
||||
pub public_port: u16,
|
||||
}
|
||||
|
||||
///向中继服务器注册,token标识一个虚拟网关,device_id防止多次注册时得到的ip不一致
|
||||
pub async fn registration(
|
||||
main_channel: &UdpSocket,
|
||||
main_tcp_channel: Option<&mut TcpStream>,
|
||||
server_cipher: &Cipher,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
ip: Ipv4Addr,
|
||||
client_secret: bool,
|
||||
) -> Result<RegResponse, ReqEnum> {
|
||||
let request_packet =
|
||||
registration_request_packet(server_cipher, token.clone(), device_id.clone(), name.clone(), ip, false, false, client_secret).unwrap();
|
||||
let buf = request_packet.buffer();
|
||||
let mut recv_buf = [0u8; 10240];
|
||||
let recv_buf = if let Some(main_tcp_channel) = main_tcp_channel {
|
||||
let mut vec = vec![0; 4 + buf.len()];
|
||||
let len = buf.len();
|
||||
vec[2] = (len >> 8) as u8;
|
||||
vec[3] = (len & 0xFF) as u8;
|
||||
vec[4..].copy_from_slice(buf);
|
||||
if let Err(e) = main_tcp_channel.write_all(&vec).await {
|
||||
return Err(ReqEnum::Other(format!("send error:{}", e)));
|
||||
}
|
||||
if let Err(e) = main_tcp_channel.read_exact(&mut recv_buf[..4]).await {
|
||||
return Err(ReqEnum::Other(format!("read error:{}", e)));
|
||||
}
|
||||
let len = 4 + (((recv_buf[2] as u16) << 8) | recv_buf[3] as u16) as usize;
|
||||
if len > recv_buf.len() {
|
||||
return Err(ReqEnum::Other("too long".to_string()));
|
||||
}
|
||||
if let Err(e) = main_tcp_channel.read_exact(&mut recv_buf[4..len]).await {
|
||||
return Err(ReqEnum::Other(format!("read error:{}", e)));
|
||||
}
|
||||
&mut recv_buf[4..len]
|
||||
} else {
|
||||
if let Err(e) = main_channel.send_to(buf, server_address).await {
|
||||
return Err(ReqEnum::Other(format!("send error:{}", e)));
|
||||
}
|
||||
match tokio::time::timeout(Duration::from_millis(300), main_channel.recv_from(&mut recv_buf)).await {
|
||||
Ok(rs) => {
|
||||
match rs {
|
||||
Ok((len, addr)) => {
|
||||
if server_address != addr {
|
||||
return Err(ReqEnum::Other(format!("invalid data,from {}", addr)));
|
||||
}
|
||||
&mut recv_buf[..len]
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ReqEnum::Other(format!("receiver error:{}", e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(ReqEnum::Timeout);
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut net_packet = match NetPacket::new(recv_buf) {
|
||||
Ok(net_packet) => {
|
||||
net_packet
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ReqEnum::ServerError(format!("{}", e)));
|
||||
}
|
||||
};
|
||||
if let Err(e) = server_cipher.decrypt_ipv4(&mut net_packet) {
|
||||
return Err(ReqEnum::ServerError(format!("decrypt_ipv4 {}", e)));
|
||||
}
|
||||
match net_packet.protocol() {
|
||||
Protocol::Service => {
|
||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||
service_packet::Protocol::RegistrationResponse => {
|
||||
match RegistrationResponse::parse_from_bytes(net_packet.payload()) {
|
||||
Ok(response) => {
|
||||
let device_info_list: Vec<PeerDeviceInfo> = response
|
||||
.device_info_list
|
||||
.into_iter()
|
||||
.map(|info| {
|
||||
PeerDeviceInfo::new(
|
||||
Ipv4Addr::from(info.virtual_ip),
|
||||
info.name,
|
||||
info.device_status as u8,
|
||||
info.client_secret,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
Ok(RegResponse {
|
||||
virtual_ip: Ipv4Addr::from(response.virtual_ip),
|
||||
virtual_gateway: Ipv4Addr::from(response.virtual_gateway),
|
||||
virtual_netmask: Ipv4Addr::from(response.virtual_netmask),
|
||||
epoch: response.epoch as u16,
|
||||
device_info_list,
|
||||
public_ip: Ipv4Addr::from(response.public_ip),
|
||||
public_port: response.public_port as u16,
|
||||
})
|
||||
}
|
||||
Err(_) => {
|
||||
Err(ReqEnum::ServerError("invalid data".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Err(ReqEnum::ServerError("invalid data".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
Protocol::Error => {
|
||||
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload()) {
|
||||
Ok(e) => match e {
|
||||
InErrorPacket::TokenError => Err(ReqEnum::TokenError),
|
||||
InErrorPacket::Disconnect => {
|
||||
Err(ReqEnum::ServerError("disconnect".to_string()))
|
||||
}
|
||||
InErrorPacket::AddressExhausted => {
|
||||
Err(ReqEnum::AddressExhausted)
|
||||
}
|
||||
InErrorPacket::OtherError(e) => match e.message() {
|
||||
Ok(str) => {
|
||||
Err(ReqEnum::ServerError(str))
|
||||
}
|
||||
Err(e) => Err(ReqEnum::Other(format!("{}", e))),
|
||||
},
|
||||
InErrorPacket::IpAlreadyExists => {
|
||||
Err(ReqEnum::IpAlreadyExists)
|
||||
}
|
||||
InErrorPacket::InvalidIp => {
|
||||
Err(ReqEnum::InvalidIp)
|
||||
}
|
||||
InErrorPacket::NoKey => {
|
||||
Err(ReqEnum::ServerError("no key".to_string()))
|
||||
}
|
||||
},
|
||||
Err(e) => Err(ReqEnum::Other(format!("{}", e))),
|
||||
}
|
||||
}
|
||||
_ => Err(ReqEnum::ServerError("invalid data".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn registration_request_packet(
|
||||
server_cipher: &Cipher,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
ip: Ipv4Addr,
|
||||
is_fast: bool,
|
||||
allow_ip_change: bool,
|
||||
client_secret: bool,
|
||||
) -> crate::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = RegistrationRequest::new();
|
||||
request.token = token;
|
||||
request.device_id = device_id;
|
||||
request.name = name;
|
||||
request.virtual_ip = ip.into();
|
||||
request.allow_ip_change = allow_ip_change;
|
||||
request.is_fast = is_fast;
|
||||
request.version = crate::VNT_VERSION.to_string();
|
||||
request.client_secret = client_secret;
|
||||
let bytes = request.write_to_bytes()?;
|
||||
let buf = vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED];
|
||||
let mut net_packet = NetPacket::new_encrypt(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_gateway_flag(true);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_payload(&bytes)?;
|
||||
server_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
Ok(net_packet)
|
||||
}
|
||||
|
||||
pub struct Register {
|
||||
server_cipher: Cipher,
|
||||
sender: ChannelSender,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
time: AtomicCell<Instant>,
|
||||
client_secret: bool,
|
||||
}
|
||||
|
||||
impl Register {
|
||||
pub fn new(
|
||||
server_cipher: Cipher,
|
||||
sender: ChannelSender,
|
||||
server_address: SocketAddr,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
client_secret: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
server_cipher,
|
||||
sender,
|
||||
server_address,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
time: AtomicCell::new(Instant::now()),
|
||||
client_secret,
|
||||
}
|
||||
}
|
||||
pub async fn fast_register(&self, ip: Ipv4Addr) -> crate::Result<()> {
|
||||
let last = self.time.load();
|
||||
if last.elapsed() < Duration::from_secs(2)
|
||||
|| self
|
||||
.time
|
||||
.compare_exchange(last, Instant::now())
|
||||
.is_err()
|
||||
{
|
||||
//短时间不重复注册
|
||||
return Ok(());
|
||||
}
|
||||
log::info!("重新连接");
|
||||
let request_packet = registration_request_packet(
|
||||
&self.server_cipher,
|
||||
self.token.clone(),
|
||||
self.device_id.clone(),
|
||||
self.name.clone(),
|
||||
ip,
|
||||
false,
|
||||
true,
|
||||
self.client_secret,
|
||||
)?;
|
||||
let buf = request_packet.buffer();
|
||||
self.sender.send_main(buf, self.server_address).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
use byte_pool::Block;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BufSenderGroup(usize, Vec<tokio::sync::mpsc::Sender<(Block<'static>, usize, usize)>>);
|
||||
|
||||
pub struct BufReceiverGroup(pub Vec<tokio::sync::mpsc::Receiver<(Block<'static>, usize, usize)>>);
|
||||
|
||||
impl BufSenderGroup {
|
||||
pub async fn send(&mut self, val: (Block<'static>, usize, usize)) -> bool {
|
||||
let index = self.0 % self.1.len();
|
||||
self.0 = self.0.wrapping_add(1);
|
||||
self.1[index].send(val).await.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buf_channel_group(size: usize) -> (BufSenderGroup, BufReceiverGroup) {
|
||||
let mut buf_sender_group = Vec::with_capacity(size);
|
||||
let mut buf_receiver_group = Vec::with_capacity(size);
|
||||
for _ in 0..size {
|
||||
let (buf_sender, buf_receiver) = tokio::sync::mpsc::channel::<(Block<'static>, usize, usize)>(10);
|
||||
buf_sender_group.push(buf_sender);
|
||||
buf_receiver_group.push(buf_receiver);
|
||||
}
|
||||
(BufSenderGroup(0, buf_sender_group), BufReceiverGroup(buf_receiver_group))
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
use std::io;
|
||||
use std::net::SocketAddrV4;
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use packet::ip::ipv4::protocol::Protocol;
|
||||
use packet::tcp::tcp::TcpPacket;
|
||||
use packet::udp::udp::UdpPacket;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::{check_dest, CurrentDeviceInfo};
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::protocol::{ip_turn_packet, MAX_TTL, NetPacket, Version};
|
||||
use crate::error::*;
|
||||
use crate::igmp_server::{IgmpServer, Multicast};
|
||||
use crate::protocol;
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
use crate::protocol::ip_turn_packet::BroadcastPacket;
|
||||
pub mod channel_group;
|
||||
pub mod tun_handler;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
|
||||
pub mod tap_handler;
|
||||
|
||||
async fn broadcast(server_cipher: &Cipher, multicast_members: Option<Arc<RwLock<Multicast>>>, sender: &ChannelSender, net_packet: &mut NetPacket<&mut [u8]>, current_device: &CurrentDeviceInfo) -> Result<()> {
|
||||
let mut peer_ips = Vec::with_capacity(8);
|
||||
let vec = sender.route_table_one();
|
||||
let mut relay_count = 0;
|
||||
const MAX_COUNT: usize = 8;
|
||||
for (peer_ip, route) in vec {
|
||||
if peer_ip == current_device.virtual_gateway {
|
||||
continue;
|
||||
}
|
||||
if peer_ips.len() == MAX_COUNT {
|
||||
break;
|
||||
}
|
||||
if let Some(members) = &multicast_members {
|
||||
if !members.read().is_send(&peer_ip) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if route.is_p2p()
|
||||
&& sender.send_by_key(net_packet.buffer(), &route.route_key()).await.is_ok() {
|
||||
peer_ips.push(peer_ip);
|
||||
} else {
|
||||
relay_count += 1;
|
||||
}
|
||||
}
|
||||
if relay_count == 0 && !peer_ips.is_empty() && peer_ips.len() != MAX_COUNT {
|
||||
//不需要转发
|
||||
return Ok(());
|
||||
}
|
||||
//转发到服务端的可选择广播,还要进行服务端加密
|
||||
if peer_ips.is_empty() {
|
||||
sender.send_main(net_packet.buffer(), current_device.connect_server).await?;
|
||||
} else {
|
||||
let buf = vec![0 as u8; 12 + 1 + peer_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED];
|
||||
//剩余的发送到服务端,需要告知哪些已发送过
|
||||
let mut server_packet = NetPacket::new_encrypt(buf)?;
|
||||
server_packet.set_version(Version::V1);
|
||||
server_packet.set_gateway_flag(true);
|
||||
server_packet.first_set_ttl(MAX_TTL);
|
||||
server_packet.set_source(net_packet.source());
|
||||
server_packet.set_destination(current_device.virtual_gateway);
|
||||
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(&peer_ips)?;
|
||||
broadcast.set_data(net_packet.buffer())?;
|
||||
server_cipher.encrypt_ipv4(&mut server_packet)?;
|
||||
sender.send_main(server_packet.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 实现一个原地发送,必须保证是如下结构
|
||||
/// |12字节开头|ip报文|至少1024字节结尾|
|
||||
///
|
||||
#[inline]
|
||||
pub async fn base_handle(sender: &ChannelSender, buf: &mut [u8],
|
||||
data_len: usize,//数据总长度=12+ip包长度
|
||||
igmp_server: &Option<IgmpServer>,
|
||||
current_device: CurrentDeviceInfo,
|
||||
ip_route: &Option<ExternalRoute>,
|
||||
proxy_map: &Option<IpProxyMap>,
|
||||
client_cipher: &Cipher,
|
||||
server_cipher: &Cipher) -> Result<()> {
|
||||
let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?;
|
||||
let protocol = ipv4_packet.protocol();
|
||||
let ip_head_len = ipv4_packet.header_len() as usize * 4;
|
||||
if 12 + ip_head_len >= data_len {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "ip_head_len err"))?
|
||||
}
|
||||
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_version(Version::V1);
|
||||
net_packet.set_protocol(protocol::Protocol::IpTurn);
|
||||
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
|
||||
net_packet.first_set_ttl(3);
|
||||
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)?;
|
||||
sender.send_main(net_packet.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if dest_ip.is_multicast() {
|
||||
match protocol {
|
||||
Protocol::Igmp => {
|
||||
if igmp_server.is_some() {
|
||||
//发送到服务端
|
||||
net_packet.set_destination(current_device.virtual_gateway);
|
||||
net_packet.set_gateway_flag(true);
|
||||
server_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
sender.send_main(net_packet.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
}
|
||||
Protocol::Udp => {
|
||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
let multicast_members = if let Some(igmp_server) = igmp_server {
|
||||
igmp_server.load(&dest_ip)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
broadcast(server_cipher, multicast_members, sender, &mut net_packet, ¤t_device).await?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if dest_ip.is_broadcast() || current_device.broadcast_address == dest_ip {
|
||||
// 广播 发送到直连目标
|
||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
broadcast(server_cipher, None, sender, &mut net_packet, ¤t_device).await?;
|
||||
return Ok(());
|
||||
}
|
||||
if !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) {
|
||||
if let Some(ip_route) = ip_route {
|
||||
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(());
|
||||
}
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
} else if let Some(proxy_map) = proxy_map {
|
||||
match protocol {
|
||||
Protocol::Tcp => {
|
||||
let dest_addr = {
|
||||
let tcp_packet = TcpPacket::new(src_ip, dest_ip,
|
||||
&mut net_packet.payload_mut()[ip_head_len..])?;
|
||||
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.tcp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value();
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut tcp_packet = TcpPacket::new(source_ip, dest_ip,
|
||||
&mut net_packet.payload_mut()[ip_head_len..])?;
|
||||
tcp_packet.set_source_port(source_addr.port());
|
||||
tcp_packet.update_checksum();
|
||||
let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?;
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}else{
|
||||
log::warn!("不存在接口 {:?}",dest_addr);
|
||||
}
|
||||
}
|
||||
Protocol::Udp => {
|
||||
let dest_addr = {
|
||||
let udp_packet = UdpPacket::new(src_ip, dest_ip,
|
||||
&mut net_packet.payload_mut()[ip_head_len..])?;
|
||||
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
|
||||
};
|
||||
if let Some(entry) = proxy_map.udp_proxy_map.get(&dest_addr) {
|
||||
let source_addr = entry.value();
|
||||
let source_ip = *source_addr.ip();
|
||||
let mut udp_packet = UdpPacket::new(source_ip, dest_ip,
|
||||
&mut net_packet.payload_mut()[ip_head_len..])?;
|
||||
udp_packet.set_source_port(source_addr.port());
|
||||
udp_packet.update_checksum();
|
||||
let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?;
|
||||
ipv4_packet.set_source_ip(source_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
//优先发到直连到地址
|
||||
if sender.send_by_id(net_packet.buffer(), &dest_ip).await.is_err() {
|
||||
sender.send_main(net_packet.buffer(), current_device.connect_server).await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
use std::{io, thread};
|
||||
use std::sync::Arc;
|
||||
use byte_pool::BytePool;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use packet::arp::arp::ArpPacket;
|
||||
use packet::ethernet;
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
use packet::icmp::icmp::IcmpPacket;
|
||||
use packet::icmp::Kind;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntWorker;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::handle::tun_tap::channel_group::{buf_channel_group, BufSenderGroup};
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceWriter};
|
||||
lazy_static! {
|
||||
static ref POOL:BytePool<Vec<u8>> = BytePool::<Vec<u8>>::new();
|
||||
}
|
||||
|
||||
pub fn start(worker: VntWorker, sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher, server_cipher: Cipher, parallel: usize) {
|
||||
if parallel == 1 {
|
||||
thread::Builder::new().name("tap_handler".into()).spawn(move || {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all().build().unwrap()
|
||||
.block_on(async move {
|
||||
if let Err(e) = start_simple(sender, device_reader,
|
||||
device_writer, igmp_server,
|
||||
current_device, ip_route, ip_proxy_map, client_cipher, server_cipher).await {
|
||||
log::warn!("tap:{:?}",e);
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}).unwrap();
|
||||
} else {
|
||||
let (buf_sender, buf_receiver) = buf_channel_group(parallel);
|
||||
for mut buf_receiver in buf_receiver.0 {
|
||||
let sender = sender.clone();
|
||||
let device_writer = device_writer.clone();
|
||||
let igmp_server = igmp_server.clone();
|
||||
let current_device = current_device.clone();
|
||||
let ip_route = ip_route.clone();
|
||||
let ip_proxy_map = ip_proxy_map.clone();
|
||||
let client_cipher = client_cipher.clone();
|
||||
let server_cipher = server_cipher.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some((mut buf, _, len)) = buf_receiver.recv().await {
|
||||
match handle(&mut buf, len, &igmp_server, ¤t_device, &device_writer, &sender,
|
||||
&ip_route, &ip_proxy_map, &client_cipher, &server_cipher).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
thread::Builder::new().name("tap_handler".into()).spawn(move || {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all().build().unwrap()
|
||||
.block_on(async move {
|
||||
if let Err(e) = start_(sender, device_reader, buf_sender).await {
|
||||
log::warn!("tap:{:?}",e);
|
||||
}
|
||||
worker.stop_all();
|
||||
});
|
||||
}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_(sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
mut buf_sender: BufSenderGroup) -> io::Result<()> {
|
||||
loop {
|
||||
let mut buf = POOL.alloc(4096);
|
||||
if sender.is_close() {
|
||||
return Ok(());
|
||||
}
|
||||
let start = 0;
|
||||
let len = device_reader.read(&mut buf)?;
|
||||
if !buf_sender.send((buf, start, len)).await {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "tap buf_sender发送失败"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_simple(sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher, server_cipher: Cipher) -> io::Result<()> {
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
let len = device_reader.read(&mut buf)?;
|
||||
if let Err(e) = handle(&mut buf, len, &igmp_server, ¤t_device, &device_writer, &sender, &ip_route, &ip_proxy_map, &client_cipher, &server_cipher).await {
|
||||
log::warn!("tap handle{:?}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle(buf: &mut [u8], len: usize, igmp_server: &Option<IgmpServer>, current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||
device_writer: &DeviceWriter, sender: &ChannelSender, ip_route: &Option<ExternalRoute>,
|
||||
proxy_map: &Option<IpProxyMap>, client_cipher: &Cipher, server_cipher: &Cipher) -> crate::Result<()> {
|
||||
let mut ethernet_packet = EthernetPacket::new(&mut buf[..len])?;
|
||||
let current_device = current_device.load();
|
||||
match ethernet_packet.protocol() {
|
||||
ethernet::protocol::Protocol::Arp => {
|
||||
let mut out_ethernet_packet = EthernetPacket::unchecked(ethernet_packet.buffer.to_vec());
|
||||
let arp_packet = ArpPacket::unchecked(ethernet_packet.payload());
|
||||
let mut out_arp_packet = ArpPacket::unchecked(out_ethernet_packet.payload_mut());
|
||||
let sender_h = arp_packet.sender_hardware_addr();
|
||||
let sender_p = arp_packet.sender_protocol_addr();
|
||||
let target_p = arp_packet.target_protocol_addr();
|
||||
if target_p == &[0, 0, 0, 0] || sender_p == &[0, 0, 0, 0] || target_p == sender_p {
|
||||
return Ok(());
|
||||
}
|
||||
//回复一个虚假的MAC地址
|
||||
out_arp_packet.set_sender_hardware_addr(&[target_p[0], target_p[1], target_p[2], target_p[3], !sender_h[5], 234]);
|
||||
out_arp_packet.set_sender_protocol_addr(target_p);
|
||||
out_arp_packet.set_target_hardware_addr(sender_h);
|
||||
out_arp_packet.set_target_protocol_addr(sender_p);
|
||||
out_arp_packet.set_op_code(2);
|
||||
out_ethernet_packet.set_source(&[target_p[0], target_p[1], target_p[2], target_p[3], !sender_h[5], 234]);
|
||||
out_ethernet_packet.set_destination(sender_h);
|
||||
device_writer.write_ethernet_tap(&out_ethernet_packet.buffer)?;
|
||||
}
|
||||
ethernet::protocol::Protocol::Ipv4 => {
|
||||
let mut ipv4_packet = IpV4Packet::unchecked(ethernet_packet.payload_mut());
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
if src_ip != current_device.virtual_ip() {
|
||||
return Ok(());
|
||||
}
|
||||
let dest_ip = ipv4_packet.destination_ip();
|
||||
let protocol = ipv4_packet.protocol();
|
||||
if src_ip == dest_ip {
|
||||
if protocol == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
ipv4_packet.set_source_ip(dest_ip);
|
||||
ipv4_packet.set_destination_ip(src_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
let source = ethernet_packet.source().to_vec();
|
||||
let dest = ethernet_packet.destination().to_vec();
|
||||
ethernet_packet.set_source(&dest);
|
||||
ethernet_packet.set_destination(&source);
|
||||
device_writer.write_ethernet_tap(ðernet_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// 以太网帧头部14字节,预留12字节
|
||||
return crate::handle::tun_tap::base_handle(sender, &mut buf[2..], len - 2, igmp_server, current_device,
|
||||
ip_route, proxy_map, client_cipher, server_cipher).await;
|
||||
}
|
||||
_ => {
|
||||
// log::warn!("不支持的二层协议:{:?}",p)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
use std::{io, thread};
|
||||
use std::sync::Arc;
|
||||
use byte_pool::BytePool;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
use packet::icmp::Kind;
|
||||
use packet::icmp::icmp::IcmpPacket;
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::core::status::VntWorker;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::handle::tun_tap::channel_group::{buf_channel_group, BufSenderGroup};
|
||||
use crate::igmp_server::IgmpServer;
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceWriter};
|
||||
lazy_static::lazy_static! {
|
||||
static ref POOL:BytePool<Vec<u8>> = BytePool::<Vec<u8>>::new();
|
||||
}
|
||||
fn icmp(device_writer: &DeviceWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
|
||||
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
if icmp.kind() == Kind::EchoRequest {
|
||||
icmp.set_kind(Kind::EchoReply);
|
||||
icmp.update_checksum();
|
||||
let src = ipv4_packet.source_ip();
|
||||
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||
ipv4_packet.set_destination_ip(src);
|
||||
ipv4_packet.update_checksum();
|
||||
device_writer.write_ipv4_tun(ipv4_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 接收tun数据,并且转发到udp上
|
||||
#[inline]
|
||||
async fn handle(sender: &ChannelSender, data: &mut [u8], len: usize, device_writer: &DeviceWriter,
|
||||
igmp_server: &Option<IgmpServer>, current_device: CurrentDeviceInfo,
|
||||
ip_route: &Option<ExternalRoute>, proxy_map: &Option<IpProxyMap>,
|
||||
client_cipher: &Cipher, server_cipher: &Cipher) -> Result<()> {
|
||||
let ipv4_packet = if let Ok(ipv4_packet) = IpV4Packet::new(&mut data[12..len]) {
|
||||
ipv4_packet
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
let src_ip = ipv4_packet.source_ip();
|
||||
let dest_ip = ipv4_packet.destination_ip();
|
||||
if src_ip != current_device.virtual_ip() {
|
||||
return Ok(());
|
||||
}
|
||||
if src_ip == dest_ip {
|
||||
return icmp(&device_writer, ipv4_packet);
|
||||
}
|
||||
return crate::handle::tun_tap::base_handle(sender, data, len, igmp_server,
|
||||
current_device, ip_route, proxy_map, client_cipher, server_cipher).await;
|
||||
}
|
||||
|
||||
pub async fn start(worker: VntWorker, sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher, server_cipher: Cipher, parallel: usize) {
|
||||
if parallel == 1 {
|
||||
thread::Builder::new().name("tun_handler".into()).spawn(move || {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all().build().unwrap()
|
||||
.block_on(async move {
|
||||
if let Err(e) = start_simple(sender, device_reader, &device_writer, igmp_server, current_device, ip_route, ip_proxy_map, client_cipher, server_cipher).await {
|
||||
log::warn!("stop:{}",e);
|
||||
}
|
||||
let _ = device_writer.close();
|
||||
worker.stop_all();
|
||||
})
|
||||
}).unwrap();
|
||||
} else {
|
||||
let (buf_sender, buf_receiver) = buf_channel_group(parallel);
|
||||
for mut buf_receiver in buf_receiver.0 {
|
||||
let sender = sender.clone();
|
||||
let device_writer = device_writer.clone();
|
||||
let igmp_server = igmp_server.clone();
|
||||
let current_device = current_device.clone();
|
||||
let ip_route = ip_route.clone();
|
||||
let ip_proxy_map = ip_proxy_map.clone();
|
||||
let client_cipher = client_cipher.clone();
|
||||
let server_cipher = server_cipher.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some((mut buf, start, len)) = buf_receiver.recv().await {
|
||||
match handle(&sender, &mut buf[start..], len, &device_writer, &igmp_server, current_device.load(),
|
||||
&ip_route, &ip_proxy_map, &client_cipher, &server_cipher).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
thread::Builder::new().name("tun_handler".into()).spawn(move || {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all().build().unwrap()
|
||||
.block_on(async move {
|
||||
if let Err(e) = start_(sender, device_reader, buf_sender).await {
|
||||
log::warn!("stop:{}",e);
|
||||
}
|
||||
let _ = device_writer.close();
|
||||
worker.stop_all();
|
||||
})
|
||||
}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_(sender: ChannelSender, device_reader: DeviceReader, mut buf_sender: BufSenderGroup) -> io::Result<()> {
|
||||
loop {
|
||||
let mut buf = POOL.alloc(4096);
|
||||
buf[..12].fill(0);
|
||||
if sender.is_close() {
|
||||
return Ok(());
|
||||
}
|
||||
let start = 0;
|
||||
let len = device_reader.read(&mut buf[12..])? + 12;
|
||||
#[cfg(any(target_os = "macos"))]
|
||||
let start = 4;
|
||||
if !buf_sender.send((buf, start, len)).await {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "tun buf_sender发送失败"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_simple(sender: ChannelSender,
|
||||
device_reader: DeviceReader,
|
||||
device_writer: &DeviceWriter,
|
||||
igmp_server: Option<IgmpServer>,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: Option<ExternalRoute>,
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher, server_cipher: Cipher) -> io::Result<()> {
|
||||
let mut buf = [0; 4096];
|
||||
loop {
|
||||
if sender.is_close() {
|
||||
return Ok(());
|
||||
}
|
||||
buf[..12].fill(0);
|
||||
let len = device_reader.read(&mut buf[12..])? + 12;
|
||||
#[cfg(any(target_os = "macos"))]
|
||||
let mut buf = &mut buf[4..];
|
||||
match handle(&sender, &mut buf, len, device_writer, &igmp_server, current_device.load(), &ip_route, &ip_proxy_map, &client_cipher, &server_cipher).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use dashmap::DashMap;
|
||||
use parking_lot::RwLock;
|
||||
use packet::igmp::igmp_v2::IgmpV2Packet;
|
||||
use packet::igmp::igmp_v3::{IgmpV3QueryPacket, IgmpV3RecordType, IgmpV3ReportPacket};
|
||||
use packet::igmp::IgmpType;
|
||||
use packet::ip::ipv4::protocol::Protocol;
|
||||
use crate::tun_tap_device::DeviceWriter;
|
||||
|
||||
//1. 定时发送query,启动时20秒一次,连发3次,之后8分钟一次
|
||||
//2. 接收网关的igmp report 维护组播源信息
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Multicast {
|
||||
//成员虚拟ip
|
||||
members: HashMap<Ipv4Addr, Instant>,
|
||||
//是否是过滤模式
|
||||
//成员过滤或包含的源ip
|
||||
map: HashMap<Ipv4Addr, (bool, HashSet<Ipv4Addr>)>,
|
||||
}
|
||||
|
||||
impl Multicast {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
members: Default::default(),
|
||||
map: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn is_send(&self, ip: &Ipv4Addr) -> bool {
|
||||
if self.members.contains_key(ip) {
|
||||
if let Some((is_include, set)) = self.map.get(ip) {
|
||||
if *is_include {
|
||||
set.contains(ip)
|
||||
} else {
|
||||
!set.contains(ip)
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IgmpServer {
|
||||
multicast: Arc<DashMap<Ipv4Addr, Arc<RwLock<Multicast>>>>,
|
||||
}
|
||||
|
||||
impl IgmpServer {
|
||||
pub fn new(device_writer: DeviceWriter) -> Self {
|
||||
let multicast: Arc<DashMap<Ipv4Addr, Arc<RwLock<Multicast>>>> = Arc::new(DashMap::new());
|
||||
std::thread::spawn(move || {
|
||||
//预留以太网帧头和ip头
|
||||
let mut buf = [0; 14 + 24 + 12];
|
||||
let dest = Ipv4Addr::new(224, 0, 0, 1);
|
||||
let src = Ipv4Addr::new(10, 26, 0, 1);
|
||||
{
|
||||
let buf = &mut buf[14..];
|
||||
let len = buf.len();
|
||||
// ipv4 头部20字节
|
||||
buf[0] = 0b0100_0110;
|
||||
//写入总长度
|
||||
buf[2..4].copy_from_slice(&(len as u16).to_be_bytes());
|
||||
//ttl
|
||||
buf[8] = 1;
|
||||
buf[20] = 0x94;
|
||||
buf[21] = 0x04;
|
||||
let mut ipv4 = packet::ip::ipv4::packet::IpV4Packet::unchecked(buf);
|
||||
ipv4.set_flags(2);
|
||||
ipv4.set_protocol(Protocol::Igmp);
|
||||
ipv4.set_source_ip(src);
|
||||
ipv4.set_destination_ip(dest);
|
||||
ipv4.update_checksum();
|
||||
}
|
||||
{
|
||||
let mut igmp_query = IgmpV3QueryPacket::unchecked(&mut buf[14 + 24..]);
|
||||
igmp_query.set_igmp_type();
|
||||
igmp_query.set_max_resp_code(50);
|
||||
igmp_query.set_group_address(Ipv4Addr::UNSPECIFIED);
|
||||
igmp_query.set_qrv(2);
|
||||
igmp_query.set_qqic(10);
|
||||
igmp_query.update_checksum();
|
||||
}
|
||||
loop {
|
||||
let _ = device_writer.write_ipv4(&mut buf);
|
||||
std::thread::sleep(Duration::from_secs(20))
|
||||
}
|
||||
});
|
||||
Self {
|
||||
multicast,
|
||||
}
|
||||
}
|
||||
pub fn load(&self, multicast_addr: &Ipv4Addr) -> Option<Arc<RwLock<Multicast>>> {
|
||||
if let Some(entry) = self.multicast.get(multicast_addr) {
|
||||
Some(entry.value().clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn handle(&self, buf: &[u8], source: Ipv4Addr) -> crate::Result<()> {
|
||||
for x in self.multicast.iter() {
|
||||
let mut list = Vec::new();
|
||||
let mut write_guard = x.value().write();
|
||||
for (ip, time) in &write_guard.members {
|
||||
if time.elapsed() > Duration::from_secs(30) {
|
||||
list.push(*ip);
|
||||
}
|
||||
}
|
||||
for ip in list {
|
||||
write_guard.members.remove(&ip);
|
||||
write_guard.map.remove(&ip);
|
||||
}
|
||||
}
|
||||
match IgmpType::from(buf[0]) {
|
||||
IgmpType::Query => {}
|
||||
IgmpType::ReportV1 | IgmpType::ReportV2 => {
|
||||
//加入组播,v1和v2差不多
|
||||
let report = IgmpV2Packet::new(buf)?;
|
||||
let multicast_addr = report.group_address();
|
||||
if !multicast_addr.is_multicast() {
|
||||
return Ok(());
|
||||
}
|
||||
let multi = {
|
||||
self.multicast.entry(multicast_addr).or_insert_with(|| {
|
||||
Arc::new(RwLock::new(Multicast::new()))
|
||||
}).value().clone()
|
||||
};
|
||||
let mut guard = multi.write();
|
||||
guard.members.insert(source, Instant::now());
|
||||
}
|
||||
IgmpType::LeaveV2 => {
|
||||
//退出组播
|
||||
let leave = IgmpV2Packet::new(buf)?;
|
||||
let multicast_addr = leave.group_address();
|
||||
if !multicast_addr.is_multicast() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(entry) = self.multicast.get(&multicast_addr) {
|
||||
let mut guard = entry.value().write();
|
||||
guard.map.remove(&source);
|
||||
guard.members.remove(&source);
|
||||
}
|
||||
}
|
||||
IgmpType::ReportV3 => {
|
||||
let report = IgmpV3ReportPacket::new(buf)?;
|
||||
if let Some(group_records) = report.group_records() {
|
||||
for group_record in group_records {
|
||||
let multicast_addr = group_record.multicast_address();
|
||||
if !multicast_addr.is_multicast() {
|
||||
return Ok(());
|
||||
}
|
||||
let multi = self.multicast.entry(multicast_addr).or_insert_with(|| {
|
||||
Arc::new(RwLock::new(Multicast::new()))
|
||||
}).value().clone();
|
||||
let mut guard = multi.write();
|
||||
|
||||
match group_record.record_type() {
|
||||
IgmpV3RecordType::ModeIsInclude | IgmpV3RecordType::ChangeToIncludeMode => {
|
||||
match group_record.source_addresses() {
|
||||
None => {
|
||||
//不接收所有
|
||||
guard.members.remove(&source);
|
||||
guard.map.remove(&source);
|
||||
}
|
||||
Some(src) => {
|
||||
guard.members.insert(source, Instant::now());
|
||||
guard.map.insert(source, (true, HashSet::from_iter(src)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IgmpV3RecordType::ModeIsExclude | IgmpV3RecordType::ChangeToExcludeMode => {
|
||||
match group_record.source_addresses() {
|
||||
None => {
|
||||
//接收所有
|
||||
guard.members.insert(source, Instant::now());
|
||||
guard.map.remove(&source);
|
||||
}
|
||||
Some(src) => {
|
||||
guard.members.insert(source, Instant::now());
|
||||
guard.map.insert(source, (false, HashSet::from_iter(src)));
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpV3RecordType::AllowNewSources => {
|
||||
//在已有源的基础上,接收目标源,如果是排除模式,则删除;是包含模式则添加
|
||||
match group_record.source_addresses() {
|
||||
None => {}
|
||||
Some(src) => {
|
||||
match guard.map.get_mut(&source) {
|
||||
None => {}
|
||||
Some((is_include, set)) => {
|
||||
for ip in src {
|
||||
if *is_include {
|
||||
set.insert(ip);
|
||||
} else {
|
||||
set.remove(&ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpV3RecordType::BlockOldSources => {
|
||||
//在已有源的基础上,不接收目标源
|
||||
match group_record.source_addresses() {
|
||||
None => {}
|
||||
Some(src) => {
|
||||
match guard.map.get_mut(&source) {
|
||||
None => {}
|
||||
Some((is_include, set)) => {
|
||||
for ip in src {
|
||||
if *is_include {
|
||||
set.remove(&ip);
|
||||
} else {
|
||||
set.insert(ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpV3RecordType::Unknown(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IgmpType::Unknown(_) => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
use std::io;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use dashmap::DashMap;
|
||||
|
||||
use socket2::{Domain, SockAddr, Socket, Type};
|
||||
|
||||
use packet::icmp::icmp;
|
||||
use packet::icmp::icmp::HeaderOther;
|
||||
use packet::ip::ipv4;
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
|
||||
pub struct IcmpProxy {
|
||||
icmp_socket: Arc<Socket>,
|
||||
// 对端-> 真实来源
|
||||
icmp_proxy_map: Arc<DashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||
sender: ChannelSender,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
client_cipher: Cipher,
|
||||
}
|
||||
|
||||
impl IcmpProxy {
|
||||
pub fn new(addr: SocketAddrV4, icmp_proxy_map: Arc<DashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||
sender: ChannelSender, current_device: Arc<AtomicCell<CurrentDeviceInfo>>, client_cipher: Cipher) -> io::Result<IcmpProxy> {
|
||||
let icmp_socket = Arc::new(Socket::new(Domain::IPV4, Type::RAW, Some(socket2::Protocol::ICMPV4))?);
|
||||
icmp_socket.bind(&SockAddr::from(addr))?;
|
||||
Ok(IcmpProxy {
|
||||
icmp_socket,
|
||||
icmp_proxy_map,
|
||||
sender,
|
||||
current_device,
|
||||
client_cipher,
|
||||
})
|
||||
}
|
||||
pub fn icmp_socket(&self) -> Arc<Socket> {
|
||||
self.icmp_socket.clone()
|
||||
}
|
||||
pub fn start(self) {
|
||||
let mut buf = [0 as u8; 1500];
|
||||
let data: &mut [MaybeUninit<u8>] =
|
||||
unsafe { std::mem::transmute(&mut buf[..]) };
|
||||
|
||||
loop {
|
||||
match self.recv(data) {
|
||||
Ok((len, peer_ip)) => {
|
||||
match peer_ip {
|
||||
IpAddr::V4(peer_ip) => {
|
||||
match ipv4::packet::IpV4Packet::new(&mut buf[..len]) {
|
||||
Ok(mut ipv4_packet) => {
|
||||
match icmp::IcmpPacket::new(ipv4_packet.payload()) {
|
||||
Ok(icmp_packet) => {
|
||||
match icmp_packet.header_other() {
|
||||
HeaderOther::Identifier(id, seq) => {
|
||||
if let Some(entry) = self.icmp_proxy_map.get(&(peer_ip, id, seq)) {
|
||||
//将数据发送到真实的来源
|
||||
let dest_ip = *entry.value();
|
||||
drop(entry);
|
||||
ipv4_packet.set_destination_ip(dest_ip);
|
||||
ipv4_packet.update_checksum();
|
||||
let current_device = self.current_device.load();
|
||||
let virtual_ip = current_device.virtual_ip();
|
||||
let connect_server = current_device.connect_server;
|
||||
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + len + ENCRYPTION_RESERVED]).unwrap();
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_protocol(Protocol::IpTurn);
|
||||
net_packet.set_transport_protocol(crate::protocol::ip_turn_packet::Protocol::Ipv4.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_source(virtual_ip);
|
||||
net_packet.set_destination(dest_ip);
|
||||
net_packet.set_payload(ipv4_packet.buffer).unwrap();
|
||||
if let Err(e) = self.client_cipher.encrypt_ipv4(&mut net_packet) {
|
||||
log::warn!("加密失败:{}",e);
|
||||
continue;
|
||||
}
|
||||
if self.sender.try_send_by_id(net_packet.buffer(), &dest_ip).is_err() {
|
||||
let _ = self.sender.try_send_main(net_packet.buffer(), connect_server);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
};
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
IpAddr::V6(_) => {}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("icmp代理异常:{:?}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, IpAddr)> {
|
||||
let (size, addr) = self.icmp_socket.recv_from(buf)?;
|
||||
let addr = match addr.as_socket() {
|
||||
None => {
|
||||
IpAddr::V4(Ipv4Addr::UNSPECIFIED)
|
||||
}
|
||||
Some(add) => {
|
||||
add.ip()
|
||||
}
|
||||
};
|
||||
Ok((size, addr))
|
||||
}
|
||||
// fn send_to(&self, buf: &[u8], addr: SocketAddrV4) -> io::Result<usize> {
|
||||
// self.icmp_socket.send_to(buf, &SockAddr::from(addr))
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
use std::{io, thread};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use dashmap::DashMap;
|
||||
use socket2::{SockAddr, Socket};
|
||||
use tokio::net::{TcpListener, UdpSocket};
|
||||
use crate::channel::sender::ChannelSender;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::ip_proxy::icmp_proxy::IcmpProxy;
|
||||
use crate::ip_proxy::tcp_proxy::TcpProxy;
|
||||
use crate::ip_proxy::udp_proxy::UdpProxy;
|
||||
|
||||
pub mod icmp_proxy;
|
||||
pub mod tcp_proxy;
|
||||
pub mod udp_proxy;
|
||||
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
Icmp,
|
||||
Tcp,
|
||||
Udp,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IpProxyMap {
|
||||
pub(crate) tcp_proxy_port: u16,
|
||||
pub(crate) udp_proxy_port: u16,
|
||||
//真实源地址 -> 目的地址
|
||||
pub(crate) tcp_proxy_map: Arc<DashMap<SocketAddrV4, SocketAddrV4>>,
|
||||
pub(crate) udp_proxy_map: Arc<DashMap<SocketAddrV4, SocketAddrV4>>,
|
||||
// icmp用Identifier来区分,没有Identifier的一律不转发
|
||||
pub(crate) icmp_proxy_map: Arc<DashMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||
icmp_socket: Arc<Socket>,
|
||||
}
|
||||
|
||||
impl IpProxyMap {
|
||||
pub fn send_icmp(&self, buf: &[u8], dest: &Ipv4Addr) -> io::Result<usize> {
|
||||
self.icmp_socket.send_to(buf, &SockAddr::from(SocketAddrV4::new(*dest, 0)))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init_proxy(sender: ChannelSender, current_device: Arc<AtomicCell<CurrentDeviceInfo>>, client_cipher: Cipher,) -> io::Result<(TcpProxy, UdpProxy, IpProxyMap)> {
|
||||
let tcp_proxy_map: Arc<DashMap<SocketAddrV4, SocketAddrV4>> = Arc::new(DashMap::new());
|
||||
let udp_proxy_map: Arc<DashMap<SocketAddrV4, SocketAddrV4>> = Arc::new(DashMap::new());
|
||||
let icmp_proxy_map: Arc<DashMap<(Ipv4Addr, u16, u16), Ipv4Addr>> = Arc::new(DashMap::new());
|
||||
let tcp_listener = TcpListener::bind("0.0.0.0:0").await?;
|
||||
let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
let tcp_proxy_port = tcp_listener.local_addr()?.port();
|
||||
let udp_proxy_port = udp_socket.local_addr()?.port();
|
||||
let tcp_proxy = TcpProxy::new(tcp_listener, tcp_proxy_map.clone());
|
||||
let udp_proxy = UdpProxy::new(udp_socket, udp_proxy_map.clone());
|
||||
let addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0);
|
||||
let icmp_proxy = IcmpProxy::new(addr, icmp_proxy_map.clone(),
|
||||
sender.clone(), current_device.clone(),client_cipher)?;
|
||||
let icmp_socket = icmp_proxy.icmp_socket();
|
||||
thread::spawn(move || {
|
||||
icmp_proxy.start();
|
||||
});
|
||||
|
||||
Ok((tcp_proxy, udp_proxy, IpProxyMap {
|
||||
tcp_proxy_port,
|
||||
udp_proxy_port,
|
||||
tcp_proxy_map,
|
||||
udp_proxy_map,
|
||||
icmp_proxy_map,
|
||||
icmp_socket,
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use dashmap::DashMap;
|
||||
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
|
||||
pub struct TcpProxy {
|
||||
tcp_listener: TcpListener,
|
||||
tcp_proxy_map: Arc<DashMap<SocketAddrV4, SocketAddrV4>>,
|
||||
}
|
||||
|
||||
impl TcpProxy {
|
||||
pub fn new(tcp_listener: TcpListener, tcp_proxy_map: Arc<DashMap<SocketAddrV4, SocketAddrV4>>) -> Self {
|
||||
Self {
|
||||
tcp_listener,
|
||||
tcp_proxy_map,
|
||||
}
|
||||
}
|
||||
pub async fn start(self) {
|
||||
let tcp_listener = self.tcp_listener;
|
||||
let tcp_proxy_map = self.tcp_proxy_map;
|
||||
loop {
|
||||
match tcp_listener.accept().await {
|
||||
Ok((tcp_stream, sender_addr)) => {
|
||||
match sender_addr {
|
||||
SocketAddr::V4(sender_addr) => {
|
||||
if let Some(entry) = tcp_proxy_map.get(&sender_addr) {
|
||||
let dest_addr = *entry.value();
|
||||
drop(entry);
|
||||
let peer_tcp_stream = match TcpStream::connect(dest_addr).await {
|
||||
Ok(peer_tcp_stream) => { peer_tcp_stream }
|
||||
Err(e) => {
|
||||
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = proxy(tcp_stream, peer_tcp_stream).await {
|
||||
log::warn!("{}->{},{}",sender_addr,dest_addr,e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
SocketAddr::V6(_) => {}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("tcp代理监听:{:?}",e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn proxy(mut client: TcpStream, mut server: TcpStream) -> io::Result<()> {
|
||||
let (mut client_reader, mut client_writer) = client.split();
|
||||
let (mut server_reader, mut server_writer) = server.split();
|
||||
|
||||
let client_to_server = tokio::io::copy(&mut client_reader, &mut server_writer);
|
||||
let server_to_client = tokio::io::copy(&mut server_reader, &mut client_writer);
|
||||
|
||||
let (r1, r2) = tokio::join!(client_to_server, server_to_client);
|
||||
r1?;
|
||||
r2?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use dashmap::DashMap;
|
||||
use tokio::net::UdpSocket;
|
||||
|
||||
/// 一个udp代理,作用是利用系统协议栈,将udp数据报解析出来再转发到目的地址
|
||||
pub struct UdpProxy {
|
||||
udp_socket: Arc<UdpSocket>,
|
||||
map: Arc<DashMap<SocketAddrV4, SocketAddrV4>>,
|
||||
}
|
||||
|
||||
impl UdpProxy {
|
||||
pub fn new(udp_socket: UdpSocket, map: Arc<DashMap<SocketAddrV4, SocketAddrV4>>) -> Self {
|
||||
let udp_socket = Arc::new(udp_socket);
|
||||
Self {
|
||||
udp_socket,
|
||||
map,
|
||||
}
|
||||
}
|
||||
pub async fn start(self) {
|
||||
let map = self.map;
|
||||
let udp_socket = self.udp_socket;
|
||||
let mut buf = [0u8; 65536];
|
||||
let inner_map: Arc<DashMap<SocketAddrV4, Arc<UdpSocket>>> = Arc::new(DashMap::new());
|
||||
|
||||
loop {
|
||||
match udp_socket.recv_from(&mut buf).await {
|
||||
Ok((len, sender_addr)) => {
|
||||
match sender_addr {
|
||||
SocketAddr::V4(sender_addr) => {
|
||||
match start0(&buf[..len], sender_addr, &inner_map, &map, &udp_socket).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("udp代理异常:{:?},来源:{}",e,sender_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
SocketAddr::V6(_) => {}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("udp代理异常:{:?}",e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<DashMap<SocketAddrV4, Arc<UdpSocket>>>, map: &Arc<DashMap<SocketAddrV4, SocketAddrV4>>, udp_socket: &Arc<UdpSocket>) -> io::Result<()> {
|
||||
if let Some(entry) = inner_map.get(&sender_addr) {
|
||||
let udp = entry.value().clone();
|
||||
drop(entry);
|
||||
udp.send(buf).await?;
|
||||
} else if let Some(entry) = map.get(&sender_addr) {
|
||||
let dest_addr = *entry.value();
|
||||
drop(entry);
|
||||
let peer_udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
peer_udp_socket.connect(dest_addr).await?;
|
||||
peer_udp_socket.send(buf).await?;
|
||||
let peer_udp_socket = Arc::new(peer_udp_socket);
|
||||
let inner_map = inner_map.clone();
|
||||
inner_map.insert(sender_addr, peer_udp_socket.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(300), 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代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
//超时关闭
|
||||
log::warn!("udp代理超时关闭,来源:{},目标:{}",sender_addr,dest_addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
inner_map.remove(&sender_addr);
|
||||
map.remove(&sender_addr);
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
use crate::error::Error;
|
||||
pub const VNT_VERSION:&'static str = "1.2.1";
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub mod error;
|
||||
pub mod handle;
|
||||
pub mod nat;
|
||||
pub mod proto;
|
||||
pub mod protocol;
|
||||
pub mod ip_proxy;
|
||||
pub mod external_route;
|
||||
pub mod igmp_server;
|
||||
pub mod tun_tap_device;
|
||||
pub mod core;
|
||||
pub mod channel;
|
||||
pub mod util;
|
||||
pub mod cipher;
|
||||
@@ -0,0 +1,138 @@
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::net::UdpSocket;
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::channel::punch::{NatInfo, NatType};
|
||||
use crate::proto::message::PunchNatType;
|
||||
|
||||
mod stun_test;
|
||||
|
||||
pub fn local_ip() -> io::Result<Ipv4Addr> {
|
||||
let socket = UdpSocket::bind("0.0.0.0:0")?;
|
||||
socket.connect("8.8.8.8:80")?;
|
||||
let addr = socket.local_addr()?;
|
||||
match addr.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
Ok(ip)
|
||||
}
|
||||
IpAddr::V6(_) => {
|
||||
Ok(Ipv4Addr::UNSPECIFIED)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NatTest {
|
||||
stun_server: Vec<String>,
|
||||
info: Arc<Mutex<NatInfo>>,
|
||||
}
|
||||
|
||||
impl From<NatType> for PunchNatType {
|
||||
fn from(value: NatType) -> Self {
|
||||
match value {
|
||||
NatType::Symmetric => PunchNatType::Symmetric,
|
||||
NatType::Cone => PunchNatType::Cone,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<NatType> for PunchNatType {
|
||||
fn into(self) -> NatType {
|
||||
match self {
|
||||
PunchNatType::Symmetric => NatType::Symmetric,
|
||||
PunchNatType::Cone => NatType::Cone,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NatTest {
|
||||
pub async fn new(
|
||||
mut stun_server: Vec<String>,
|
||||
public_ip: Ipv4Addr,
|
||||
public_port: u16,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
) -> NatTest {
|
||||
let server = stun_server[0].clone();
|
||||
stun_server.resize(3, server);
|
||||
let info = NatTest::re_test_(
|
||||
&stun_server,
|
||||
public_ip,
|
||||
public_port,
|
||||
local_ip,
|
||||
local_port,
|
||||
).await;
|
||||
NatTest {
|
||||
stun_server,
|
||||
info: Arc::new(Mutex::new(info)),
|
||||
}
|
||||
}
|
||||
pub fn nat_info(&self) -> NatInfo {
|
||||
self.info.lock().clone()
|
||||
}
|
||||
pub fn update_addr(&self, ip: Ipv4Addr, port: u16) {
|
||||
let mut guard = self.info.lock();
|
||||
guard.public_port = port;
|
||||
if !guard.public_ips.contains(&ip) {
|
||||
guard.public_ips.push(ip);
|
||||
}
|
||||
}
|
||||
pub async fn re_test(
|
||||
&self,
|
||||
public_ip: Ipv4Addr,
|
||||
public_port: u16,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
) -> NatInfo {
|
||||
let info = NatTest::re_test_(
|
||||
&self.stun_server,
|
||||
public_ip,
|
||||
public_port,
|
||||
local_ip,
|
||||
local_port,
|
||||
).await;
|
||||
*self.info.lock() = info.clone();
|
||||
info
|
||||
}
|
||||
async fn re_test_(
|
||||
stun_server: &Vec<String>,
|
||||
public_ip: Ipv4Addr,
|
||||
public_port: u16,
|
||||
local_ip: Ipv4Addr,
|
||||
local_port: u16,
|
||||
) -> NatInfo {
|
||||
return match stun_test::stun_test_nat(stun_server.clone()).await {
|
||||
Ok((nat_type, ips, port_range)) => {
|
||||
let mut public_ips = Vec::new();
|
||||
public_ips.push(Ipv4Addr::from(public_ip));
|
||||
for ip in ips {
|
||||
if ip != public_ip {
|
||||
public_ips.push(ip);
|
||||
}
|
||||
}
|
||||
NatInfo::new(
|
||||
public_ips,
|
||||
public_port,
|
||||
port_range,
|
||||
local_ip,
|
||||
local_port,
|
||||
nat_type,
|
||||
)
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
NatInfo::new(
|
||||
vec![public_ip],
|
||||
public_port,
|
||||
0,
|
||||
local_ip,
|
||||
local_port,
|
||||
NatType::Cone,
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::time::Duration;
|
||||
|
||||
use stun_format::Attr;
|
||||
use tokio::net::UdpSocket;
|
||||
use crate::channel::punch::NatType;
|
||||
|
||||
pub async fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
let mut h = Vec::new();
|
||||
for x in stun_servers {
|
||||
let handle = tokio::spawn(test_nat(x));
|
||||
h.push(handle);
|
||||
}
|
||||
let mut nat_type = NatType::Cone;
|
||||
let mut port_range = 0;
|
||||
let mut hash_set = HashSet::new();
|
||||
for x in h {
|
||||
if let Ok(rs) = x.await {
|
||||
if let Ok((nat_type_t, ip_list_t, port_range_t)) = rs {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((nat_type, hash_set.into_iter().collect(), port_range))
|
||||
}
|
||||
|
||||
async fn test_nat(stun_server: String) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
let udp = UdpSocket::bind("0.0.0.0:0").await?;
|
||||
udp.connect(stun_server).await?;
|
||||
let mut nat_type = NatType::Cone;
|
||||
let mut port_range = 0;
|
||||
let mut hash_set = HashSet::new();
|
||||
match test_nat_(&udp, true, true).await {
|
||||
Ok((mapped_addr1, changed_addr1)) => {
|
||||
match mapped_addr1.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
hash_set.insert(ip);
|
||||
}
|
||||
IpAddr::V6(_) => {}
|
||||
}
|
||||
if udp.connect(changed_addr1).await.is_ok() {
|
||||
if let Ok((mapped_addr2, _)) = test_nat_(&udp, false, false).await {
|
||||
match mapped_addr2.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
hash_set.insert(ip);
|
||||
}
|
||||
IpAddr::V6(_) => {}
|
||||
}
|
||||
port_range = mapped_addr2.port().abs_diff(mapped_addr1.port());
|
||||
if mapped_addr1 != mapped_addr2 {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
Ok((nat_type, hash_set.into_iter().collect(), port_range))
|
||||
}
|
||||
|
||||
async fn test_nat_(udp: &UdpSocket, change_ip: bool, change_port: bool) -> io::Result<(SocketAddr, 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(1).unwrap();
|
||||
msg.add_attr(Attr::ChangeRequest { change_ip, change_port }).unwrap();
|
||||
udp.send(msg.as_bytes()).await?;
|
||||
let mut buf = [0; 10240];
|
||||
let (len, addr) = match tokio::time::timeout(Duration::from_millis(300), udp.recv_from(&mut buf)).await {
|
||||
Ok(rs) => { rs? }
|
||||
Err(_) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let msg = stun_format::Msg::from(&buf[..len]);
|
||||
let mut mapped_addr = None;
|
||||
let mut changed_addr = None;
|
||||
for x in msg.attrs_iter() {
|
||||
match x {
|
||||
Attr::MappedAddress(addr) => {
|
||||
if mapped_addr.is_none() {
|
||||
let _ = mapped_addr.insert(stun_addr(addr));
|
||||
}
|
||||
}
|
||||
Attr::ChangedAddress(addr) => {
|
||||
if changed_addr.is_none() {
|
||||
let _ = changed_addr.insert(stun_addr(addr));
|
||||
}
|
||||
}
|
||||
Attr::XorMappedAddress(addr) => {
|
||||
if mapped_addr.is_none() {
|
||||
let _ = mapped_addr.insert(stun_addr(addr));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if changed_addr.is_some() && mapped_addr.is_some() {
|
||||
return Ok((mapped_addr.unwrap(), changed_addr.unwrap()));
|
||||
}
|
||||
}
|
||||
if mapped_addr.is_some() {
|
||||
return Ok((mapped_addr.unwrap(), changed_addr.unwrap_or(addr)));
|
||||
}
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::Other, "stun response err"))
|
||||
}
|
||||
|
||||
fn stun_addr(addr: stun_format::SocketAddr) -> SocketAddr {
|
||||
match addr {
|
||||
stun_format::SocketAddr::V4(ip, port) => {
|
||||
SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(ip), port))
|
||||
}
|
||||
stun_format::SocketAddr::V6(ip, port) => {
|
||||
SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::from(ip), port, 0, 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,1674 @@
|
||||
// This file is generated by rust-protobuf 3.2.0. Do not edit
|
||||
// .proto file is parsed by pure
|
||||
// @generated
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/702
|
||||
#![allow(unknown_lints)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
#![allow(unused_attributes)]
|
||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
|
||||
#![allow(box_pointers)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(unused_results)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
//! Generated file from `message.proto`
|
||||
|
||||
/// Generated files are compatible only with the same version
|
||||
/// of protobuf runtime.
|
||||
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:HandshakeRequest)
|
||||
pub struct HandshakeRequest {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:HandshakeRequest.version)
|
||||
pub version: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:HandshakeRequest.secret)
|
||||
pub secret: bool,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:HandshakeRequest.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a HandshakeRequest {
|
||||
fn default() -> &'a HandshakeRequest {
|
||||
<HandshakeRequest as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl HandshakeRequest {
|
||||
pub fn new() -> HandshakeRequest {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"version",
|
||||
|m: &HandshakeRequest| { &m.version },
|
||||
|m: &mut HandshakeRequest| { &mut m.version },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"secret",
|
||||
|m: &HandshakeRequest| { &m.secret },
|
||||
|m: &mut HandshakeRequest| { &mut m.secret },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<HandshakeRequest>(
|
||||
"HandshakeRequest",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for HandshakeRequest {
|
||||
const NAME: &'static str = "HandshakeRequest";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
10 => {
|
||||
self.version = is.read_string()?;
|
||||
},
|
||||
16 => {
|
||||
self.secret = is.read_bool()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if !self.version.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.version);
|
||||
}
|
||||
if self.secret != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if !self.version.is_empty() {
|
||||
os.write_string(1, &self.version)?;
|
||||
}
|
||||
if self.secret != false {
|
||||
os.write_bool(2, self.secret)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> HandshakeRequest {
|
||||
HandshakeRequest::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.version.clear();
|
||||
self.secret = false;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static HandshakeRequest {
|
||||
static instance: HandshakeRequest = HandshakeRequest {
|
||||
version: ::std::string::String::new(),
|
||||
secret: false,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for HandshakeRequest {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("HandshakeRequest").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for HandshakeRequest {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for HandshakeRequest {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:HandshakeResponse)
|
||||
pub struct HandshakeResponse {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:HandshakeResponse.version)
|
||||
pub version: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:HandshakeResponse.secret)
|
||||
pub secret: bool,
|
||||
// @@protoc_insertion_point(field:HandshakeResponse.public_key)
|
||||
pub public_key: ::std::vec::Vec<u8>,
|
||||
// @@protoc_insertion_point(field:HandshakeResponse.key_finger)
|
||||
pub key_finger: ::std::string::String,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:HandshakeResponse.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a HandshakeResponse {
|
||||
fn default() -> &'a HandshakeResponse {
|
||||
<HandshakeResponse as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl HandshakeResponse {
|
||||
pub fn new() -> HandshakeResponse {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(4);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"version",
|
||||
|m: &HandshakeResponse| { &m.version },
|
||||
|m: &mut HandshakeResponse| { &mut m.version },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"secret",
|
||||
|m: &HandshakeResponse| { &m.secret },
|
||||
|m: &mut HandshakeResponse| { &mut m.secret },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_key",
|
||||
|m: &HandshakeResponse| { &m.public_key },
|
||||
|m: &mut HandshakeResponse| { &mut m.public_key },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"key_finger",
|
||||
|m: &HandshakeResponse| { &m.key_finger },
|
||||
|m: &mut HandshakeResponse| { &mut m.key_finger },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<HandshakeResponse>(
|
||||
"HandshakeResponse",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for HandshakeResponse {
|
||||
const NAME: &'static str = "HandshakeResponse";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
10 => {
|
||||
self.version = is.read_string()?;
|
||||
},
|
||||
16 => {
|
||||
self.secret = is.read_bool()?;
|
||||
},
|
||||
26 => {
|
||||
self.public_key = is.read_bytes()?;
|
||||
},
|
||||
34 => {
|
||||
self.key_finger = is.read_string()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if !self.version.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.version);
|
||||
}
|
||||
if self.secret != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if !self.public_key.is_empty() {
|
||||
my_size += ::protobuf::rt::bytes_size(3, &self.public_key);
|
||||
}
|
||||
if !self.key_finger.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(4, &self.key_finger);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if !self.version.is_empty() {
|
||||
os.write_string(1, &self.version)?;
|
||||
}
|
||||
if self.secret != false {
|
||||
os.write_bool(2, self.secret)?;
|
||||
}
|
||||
if !self.public_key.is_empty() {
|
||||
os.write_bytes(3, &self.public_key)?;
|
||||
}
|
||||
if !self.key_finger.is_empty() {
|
||||
os.write_string(4, &self.key_finger)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> HandshakeResponse {
|
||||
HandshakeResponse::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.version.clear();
|
||||
self.secret = false;
|
||||
self.public_key.clear();
|
||||
self.key_finger.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static HandshakeResponse {
|
||||
static instance: HandshakeResponse = HandshakeResponse {
|
||||
version: ::std::string::String::new(),
|
||||
secret: false,
|
||||
public_key: ::std::vec::Vec::new(),
|
||||
key_finger: ::std::string::String::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for HandshakeResponse {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("HandshakeResponse").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for HandshakeResponse {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for HandshakeResponse {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:SecretHandshakeRequest)
|
||||
pub struct SecretHandshakeRequest {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:SecretHandshakeRequest.token)
|
||||
pub token: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:SecretHandshakeRequest.key)
|
||||
pub key: ::std::vec::Vec<u8>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:SecretHandshakeRequest.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a SecretHandshakeRequest {
|
||||
fn default() -> &'a SecretHandshakeRequest {
|
||||
<SecretHandshakeRequest as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretHandshakeRequest {
|
||||
pub fn new() -> SecretHandshakeRequest {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"token",
|
||||
|m: &SecretHandshakeRequest| { &m.token },
|
||||
|m: &mut SecretHandshakeRequest| { &mut m.token },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"key",
|
||||
|m: &SecretHandshakeRequest| { &m.key },
|
||||
|m: &mut SecretHandshakeRequest| { &mut m.key },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<SecretHandshakeRequest>(
|
||||
"SecretHandshakeRequest",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for SecretHandshakeRequest {
|
||||
const NAME: &'static str = "SecretHandshakeRequest";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
10 => {
|
||||
self.token = is.read_string()?;
|
||||
},
|
||||
18 => {
|
||||
self.key = is.read_bytes()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if !self.token.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.token);
|
||||
}
|
||||
if !self.key.is_empty() {
|
||||
my_size += ::protobuf::rt::bytes_size(2, &self.key);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if !self.token.is_empty() {
|
||||
os.write_string(1, &self.token)?;
|
||||
}
|
||||
if !self.key.is_empty() {
|
||||
os.write_bytes(2, &self.key)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> SecretHandshakeRequest {
|
||||
SecretHandshakeRequest::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.token.clear();
|
||||
self.key.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static SecretHandshakeRequest {
|
||||
static instance: SecretHandshakeRequest = SecretHandshakeRequest {
|
||||
token: ::std::string::String::new(),
|
||||
key: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for SecretHandshakeRequest {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("SecretHandshakeRequest").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for SecretHandshakeRequest {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for SecretHandshakeRequest {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:RegistrationRequest)
|
||||
pub struct RegistrationRequest {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.token)
|
||||
pub token: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.device_id)
|
||||
pub device_id: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.name)
|
||||
pub name: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.is_fast)
|
||||
pub is_fast: bool,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.version)
|
||||
pub version: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.allow_ip_change)
|
||||
pub allow_ip_change: bool,
|
||||
// @@protoc_insertion_point(field:RegistrationRequest.client_secret)
|
||||
pub client_secret: bool,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationRequest.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RegistrationRequest {
|
||||
fn default() -> &'a RegistrationRequest {
|
||||
<RegistrationRequest as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrationRequest {
|
||||
pub fn new() -> RegistrationRequest {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(8);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"token",
|
||||
|m: &RegistrationRequest| { &m.token },
|
||||
|m: &mut RegistrationRequest| { &mut m.token },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"device_id",
|
||||
|m: &RegistrationRequest| { &m.device_id },
|
||||
|m: &mut RegistrationRequest| { &mut m.device_id },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"name",
|
||||
|m: &RegistrationRequest| { &m.name },
|
||||
|m: &mut RegistrationRequest| { &mut m.name },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"is_fast",
|
||||
|m: &RegistrationRequest| { &m.is_fast },
|
||||
|m: &mut RegistrationRequest| { &mut m.is_fast },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"version",
|
||||
|m: &RegistrationRequest| { &m.version },
|
||||
|m: &mut RegistrationRequest| { &mut m.version },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &RegistrationRequest| { &m.virtual_ip },
|
||||
|m: &mut RegistrationRequest| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"allow_ip_change",
|
||||
|m: &RegistrationRequest| { &m.allow_ip_change },
|
||||
|m: &mut RegistrationRequest| { &mut m.allow_ip_change },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"client_secret",
|
||||
|m: &RegistrationRequest| { &m.client_secret },
|
||||
|m: &mut RegistrationRequest| { &mut m.client_secret },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationRequest>(
|
||||
"RegistrationRequest",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RegistrationRequest {
|
||||
const NAME: &'static str = "RegistrationRequest";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
10 => {
|
||||
self.token = is.read_string()?;
|
||||
},
|
||||
18 => {
|
||||
self.device_id = is.read_string()?;
|
||||
},
|
||||
26 => {
|
||||
self.name = is.read_string()?;
|
||||
},
|
||||
32 => {
|
||||
self.is_fast = is.read_bool()?;
|
||||
},
|
||||
42 => {
|
||||
self.version = is.read_string()?;
|
||||
},
|
||||
53 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
56 => {
|
||||
self.allow_ip_change = is.read_bool()?;
|
||||
},
|
||||
64 => {
|
||||
self.client_secret = is.read_bool()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if !self.token.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.token);
|
||||
}
|
||||
if !self.device_id.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(2, &self.device_id);
|
||||
}
|
||||
if !self.name.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(3, &self.name);
|
||||
}
|
||||
if self.is_fast != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if !self.version.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(5, &self.version);
|
||||
}
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.allow_ip_change != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if self.client_secret != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if !self.token.is_empty() {
|
||||
os.write_string(1, &self.token)?;
|
||||
}
|
||||
if !self.device_id.is_empty() {
|
||||
os.write_string(2, &self.device_id)?;
|
||||
}
|
||||
if !self.name.is_empty() {
|
||||
os.write_string(3, &self.name)?;
|
||||
}
|
||||
if self.is_fast != false {
|
||||
os.write_bool(4, self.is_fast)?;
|
||||
}
|
||||
if !self.version.is_empty() {
|
||||
os.write_string(5, &self.version)?;
|
||||
}
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(6, self.virtual_ip)?;
|
||||
}
|
||||
if self.allow_ip_change != false {
|
||||
os.write_bool(7, self.allow_ip_change)?;
|
||||
}
|
||||
if self.client_secret != false {
|
||||
os.write_bool(8, self.client_secret)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> RegistrationRequest {
|
||||
RegistrationRequest::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.token.clear();
|
||||
self.device_id.clear();
|
||||
self.name.clear();
|
||||
self.is_fast = false;
|
||||
self.version.clear();
|
||||
self.virtual_ip = 0;
|
||||
self.allow_ip_change = false;
|
||||
self.client_secret = false;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RegistrationRequest {
|
||||
static instance: RegistrationRequest = RegistrationRequest {
|
||||
token: ::std::string::String::new(),
|
||||
device_id: ::std::string::String::new(),
|
||||
name: ::std::string::String::new(),
|
||||
is_fast: false,
|
||||
version: ::std::string::String::new(),
|
||||
virtual_ip: 0,
|
||||
allow_ip_change: false,
|
||||
client_secret: false,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for RegistrationRequest {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationRequest").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for RegistrationRequest {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RegistrationRequest {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:RegistrationResponse)
|
||||
pub struct RegistrationResponse {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_gateway)
|
||||
pub virtual_gateway: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.virtual_netmask)
|
||||
pub virtual_netmask: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.epoch)
|
||||
pub epoch: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.device_info_list)
|
||||
pub device_info_list: ::std::vec::Vec<DeviceInfo>,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_ip)
|
||||
pub public_ip: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_port)
|
||||
pub public_port: u32,
|
||||
// @@protoc_insertion_point(field:RegistrationResponse.public_ipv6)
|
||||
pub public_ipv6: ::std::vec::Vec<u8>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:RegistrationResponse.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RegistrationResponse {
|
||||
fn default() -> &'a RegistrationResponse {
|
||||
<RegistrationResponse as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrationResponse {
|
||||
pub fn new() -> RegistrationResponse {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(8);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &RegistrationResponse| { &m.virtual_ip },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_gateway",
|
||||
|m: &RegistrationResponse| { &m.virtual_gateway },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_gateway },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_netmask",
|
||||
|m: &RegistrationResponse| { &m.virtual_netmask },
|
||||
|m: &mut RegistrationResponse| { &mut m.virtual_netmask },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"epoch",
|
||||
|m: &RegistrationResponse| { &m.epoch },
|
||||
|m: &mut RegistrationResponse| { &mut m.epoch },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"device_info_list",
|
||||
|m: &RegistrationResponse| { &m.device_info_list },
|
||||
|m: &mut RegistrationResponse| { &mut m.device_info_list },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_ip",
|
||||
|m: &RegistrationResponse| { &m.public_ip },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port",
|
||||
|m: &RegistrationResponse| { &m.public_port },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_port },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_ipv6",
|
||||
|m: &RegistrationResponse| { &m.public_ipv6 },
|
||||
|m: &mut RegistrationResponse| { &mut m.public_ipv6 },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<RegistrationResponse>(
|
||||
"RegistrationResponse",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RegistrationResponse {
|
||||
const NAME: &'static str = "RegistrationResponse";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
13 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
21 => {
|
||||
self.virtual_gateway = is.read_fixed32()?;
|
||||
},
|
||||
29 => {
|
||||
self.virtual_netmask = is.read_fixed32()?;
|
||||
},
|
||||
32 => {
|
||||
self.epoch = is.read_uint32()?;
|
||||
},
|
||||
42 => {
|
||||
self.device_info_list.push(is.read_message()?);
|
||||
},
|
||||
53 => {
|
||||
self.public_ip = is.read_fixed32()?;
|
||||
},
|
||||
56 => {
|
||||
self.public_port = is.read_uint32()?;
|
||||
},
|
||||
66 => {
|
||||
self.public_ipv6 = is.read_bytes()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.virtual_gateway != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.virtual_netmask != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.epoch != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(4, self.epoch);
|
||||
}
|
||||
for value in &self.device_info_list {
|
||||
let len = value.compute_size();
|
||||
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
|
||||
};
|
||||
if self.public_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.public_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(7, self.public_port);
|
||||
}
|
||||
if !self.public_ipv6.is_empty() {
|
||||
my_size += ::protobuf::rt::bytes_size(8, &self.public_ipv6);
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(1, self.virtual_ip)?;
|
||||
}
|
||||
if self.virtual_gateway != 0 {
|
||||
os.write_fixed32(2, self.virtual_gateway)?;
|
||||
}
|
||||
if self.virtual_netmask != 0 {
|
||||
os.write_fixed32(3, self.virtual_netmask)?;
|
||||
}
|
||||
if self.epoch != 0 {
|
||||
os.write_uint32(4, self.epoch)?;
|
||||
}
|
||||
for v in &self.device_info_list {
|
||||
::protobuf::rt::write_message_field_with_cached_size(5, v, os)?;
|
||||
};
|
||||
if self.public_ip != 0 {
|
||||
os.write_fixed32(6, self.public_ip)?;
|
||||
}
|
||||
if self.public_port != 0 {
|
||||
os.write_uint32(7, self.public_port)?;
|
||||
}
|
||||
if !self.public_ipv6.is_empty() {
|
||||
os.write_bytes(8, &self.public_ipv6)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> RegistrationResponse {
|
||||
RegistrationResponse::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.virtual_ip = 0;
|
||||
self.virtual_gateway = 0;
|
||||
self.virtual_netmask = 0;
|
||||
self.epoch = 0;
|
||||
self.device_info_list.clear();
|
||||
self.public_ip = 0;
|
||||
self.public_port = 0;
|
||||
self.public_ipv6.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RegistrationResponse {
|
||||
static instance: RegistrationResponse = RegistrationResponse {
|
||||
virtual_ip: 0,
|
||||
virtual_gateway: 0,
|
||||
virtual_netmask: 0,
|
||||
epoch: 0,
|
||||
device_info_list: ::std::vec::Vec::new(),
|
||||
public_ip: 0,
|
||||
public_port: 0,
|
||||
public_ipv6: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for RegistrationResponse {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("RegistrationResponse").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for RegistrationResponse {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RegistrationResponse {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:DeviceInfo)
|
||||
pub struct DeviceInfo {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:DeviceInfo.name)
|
||||
pub name: ::std::string::String,
|
||||
// @@protoc_insertion_point(field:DeviceInfo.virtual_ip)
|
||||
pub virtual_ip: u32,
|
||||
// @@protoc_insertion_point(field:DeviceInfo.device_status)
|
||||
pub device_status: u32,
|
||||
// @@protoc_insertion_point(field:DeviceInfo.client_secret)
|
||||
pub client_secret: bool,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:DeviceInfo.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a DeviceInfo {
|
||||
fn default() -> &'a DeviceInfo {
|
||||
<DeviceInfo as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceInfo {
|
||||
pub fn new() -> DeviceInfo {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(4);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"name",
|
||||
|m: &DeviceInfo| { &m.name },
|
||||
|m: &mut DeviceInfo| { &mut m.name },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"virtual_ip",
|
||||
|m: &DeviceInfo| { &m.virtual_ip },
|
||||
|m: &mut DeviceInfo| { &mut m.virtual_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"device_status",
|
||||
|m: &DeviceInfo| { &m.device_status },
|
||||
|m: &mut DeviceInfo| { &mut m.device_status },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"client_secret",
|
||||
|m: &DeviceInfo| { &m.client_secret },
|
||||
|m: &mut DeviceInfo| { &mut m.client_secret },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DeviceInfo>(
|
||||
"DeviceInfo",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for DeviceInfo {
|
||||
const NAME: &'static str = "DeviceInfo";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
10 => {
|
||||
self.name = is.read_string()?;
|
||||
},
|
||||
21 => {
|
||||
self.virtual_ip = is.read_fixed32()?;
|
||||
},
|
||||
24 => {
|
||||
self.device_status = is.read_uint32()?;
|
||||
},
|
||||
32 => {
|
||||
self.client_secret = is.read_bool()?;
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if !self.name.is_empty() {
|
||||
my_size += ::protobuf::rt::string_size(1, &self.name);
|
||||
}
|
||||
if self.virtual_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.device_status != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(3, self.device_status);
|
||||
}
|
||||
if self.client_secret != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if !self.name.is_empty() {
|
||||
os.write_string(1, &self.name)?;
|
||||
}
|
||||
if self.virtual_ip != 0 {
|
||||
os.write_fixed32(2, self.virtual_ip)?;
|
||||
}
|
||||
if self.device_status != 0 {
|
||||
os.write_uint32(3, self.device_status)?;
|
||||
}
|
||||
if self.client_secret != false {
|
||||
os.write_bool(4, self.client_secret)?;
|
||||
}
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> DeviceInfo {
|
||||
DeviceInfo::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.name.clear();
|
||||
self.virtual_ip = 0;
|
||||
self.device_status = 0;
|
||||
self.client_secret = false;
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static DeviceInfo {
|
||||
static instance: DeviceInfo = DeviceInfo {
|
||||
name: ::std::string::String::new(),
|
||||
virtual_ip: 0,
|
||||
device_status: 0,
|
||||
client_secret: false,
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for DeviceInfo {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("DeviceInfo").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for DeviceInfo {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for DeviceInfo {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:DeviceList)
|
||||
pub struct DeviceList {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:DeviceList.epoch)
|
||||
pub epoch: u32,
|
||||
// @@protoc_insertion_point(field:DeviceList.device_info_list)
|
||||
pub device_info_list: ::std::vec::Vec<DeviceInfo>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:DeviceList.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a DeviceList {
|
||||
fn default() -> &'a DeviceList {
|
||||
<DeviceList as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceList {
|
||||
pub fn new() -> DeviceList {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(2);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"epoch",
|
||||
|m: &DeviceList| { &m.epoch },
|
||||
|m: &mut DeviceList| { &mut m.epoch },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"device_info_list",
|
||||
|m: &DeviceList| { &m.device_info_list },
|
||||
|m: &mut DeviceList| { &mut m.device_info_list },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<DeviceList>(
|
||||
"DeviceList",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for DeviceList {
|
||||
const NAME: &'static str = "DeviceList";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
8 => {
|
||||
self.epoch = is.read_uint32()?;
|
||||
},
|
||||
18 => {
|
||||
self.device_info_list.push(is.read_message()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
if self.epoch != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(1, self.epoch);
|
||||
}
|
||||
for value in &self.device_info_list {
|
||||
let len = value.compute_size();
|
||||
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
|
||||
};
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
if self.epoch != 0 {
|
||||
os.write_uint32(1, self.epoch)?;
|
||||
}
|
||||
for v in &self.device_info_list {
|
||||
::protobuf::rt::write_message_field_with_cached_size(2, v, os)?;
|
||||
};
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> DeviceList {
|
||||
DeviceList::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.epoch = 0;
|
||||
self.device_info_list.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static DeviceList {
|
||||
static instance: DeviceList = DeviceList {
|
||||
epoch: 0,
|
||||
device_info_list: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for DeviceList {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("DeviceList").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for DeviceList {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for DeviceList {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default,Debug)]
|
||||
// @@protoc_insertion_point(message:PunchInfo)
|
||||
pub struct PunchInfo {
|
||||
// message fields
|
||||
// @@protoc_insertion_point(field:PunchInfo.public_ip_list)
|
||||
pub public_ip_list: ::std::vec::Vec<u32>,
|
||||
// @@protoc_insertion_point(field:PunchInfo.public_port)
|
||||
pub public_port: u32,
|
||||
// @@protoc_insertion_point(field:PunchInfo.public_port_range)
|
||||
pub public_port_range: u32,
|
||||
// @@protoc_insertion_point(field:PunchInfo.nat_type)
|
||||
pub nat_type: ::protobuf::EnumOrUnknown<PunchNatType>,
|
||||
// @@protoc_insertion_point(field:PunchInfo.reply)
|
||||
pub reply: bool,
|
||||
// @@protoc_insertion_point(field:PunchInfo.local_ip)
|
||||
pub local_ip: u32,
|
||||
// @@protoc_insertion_point(field:PunchInfo.local_port)
|
||||
pub local_port: u32,
|
||||
// @@protoc_insertion_point(field:PunchInfo.public_ipv6_list)
|
||||
pub public_ipv6_list: ::std::vec::Vec<::std::vec::Vec<u8>>,
|
||||
// special fields
|
||||
// @@protoc_insertion_point(special_field:PunchInfo.special_fields)
|
||||
pub special_fields: ::protobuf::SpecialFields,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a PunchInfo {
|
||||
fn default() -> &'a PunchInfo {
|
||||
<PunchInfo as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl PunchInfo {
|
||||
pub fn new() -> PunchInfo {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
|
||||
let mut fields = ::std::vec::Vec::with_capacity(8);
|
||||
let mut oneofs = ::std::vec::Vec::with_capacity(0);
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"public_ip_list",
|
||||
|m: &PunchInfo| { &m.public_ip_list },
|
||||
|m: &mut PunchInfo| { &mut m.public_ip_list },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port",
|
||||
|m: &PunchInfo| { &m.public_port },
|
||||
|m: &mut PunchInfo| { &mut m.public_port },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"public_port_range",
|
||||
|m: &PunchInfo| { &m.public_port_range },
|
||||
|m: &mut PunchInfo| { &mut m.public_port_range },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"nat_type",
|
||||
|m: &PunchInfo| { &m.nat_type },
|
||||
|m: &mut PunchInfo| { &mut m.nat_type },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"reply",
|
||||
|m: &PunchInfo| { &m.reply },
|
||||
|m: &mut PunchInfo| { &mut m.reply },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"local_ip",
|
||||
|m: &PunchInfo| { &m.local_ip },
|
||||
|m: &mut PunchInfo| { &mut m.local_ip },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
|
||||
"local_port",
|
||||
|m: &PunchInfo| { &m.local_port },
|
||||
|m: &mut PunchInfo| { &mut m.local_port },
|
||||
));
|
||||
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
|
||||
"public_ipv6_list",
|
||||
|m: &PunchInfo| { &m.public_ipv6_list },
|
||||
|m: &mut PunchInfo| { &mut m.public_ipv6_list },
|
||||
));
|
||||
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<PunchInfo>(
|
||||
"PunchInfo",
|
||||
fields,
|
||||
oneofs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for PunchInfo {
|
||||
const NAME: &'static str = "PunchInfo";
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
|
||||
while let Some(tag) = is.read_raw_tag_or_eof()? {
|
||||
match tag {
|
||||
18 => {
|
||||
is.read_repeated_packed_fixed32_into(&mut self.public_ip_list)?;
|
||||
},
|
||||
21 => {
|
||||
self.public_ip_list.push(is.read_fixed32()?);
|
||||
},
|
||||
24 => {
|
||||
self.public_port = is.read_uint32()?;
|
||||
},
|
||||
32 => {
|
||||
self.public_port_range = is.read_uint32()?;
|
||||
},
|
||||
40 => {
|
||||
self.nat_type = is.read_enum_or_unknown()?;
|
||||
},
|
||||
48 => {
|
||||
self.reply = is.read_bool()?;
|
||||
},
|
||||
61 => {
|
||||
self.local_ip = is.read_fixed32()?;
|
||||
},
|
||||
64 => {
|
||||
self.local_port = is.read_uint32()?;
|
||||
},
|
||||
74 => {
|
||||
self.public_ipv6_list.push(is.read_bytes()?);
|
||||
},
|
||||
tag => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u64 {
|
||||
let mut my_size = 0;
|
||||
my_size += 5 * self.public_ip_list.len() as u64;
|
||||
if self.public_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(3, self.public_port);
|
||||
}
|
||||
if self.public_port_range != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(4, self.public_port_range);
|
||||
}
|
||||
if self.nat_type != ::protobuf::EnumOrUnknown::new(PunchNatType::Symmetric) {
|
||||
my_size += ::protobuf::rt::int32_size(5, self.nat_type.value());
|
||||
}
|
||||
if self.reply != false {
|
||||
my_size += 1 + 1;
|
||||
}
|
||||
if self.local_ip != 0 {
|
||||
my_size += 1 + 4;
|
||||
}
|
||||
if self.local_port != 0 {
|
||||
my_size += ::protobuf::rt::uint32_size(8, self.local_port);
|
||||
}
|
||||
for value in &self.public_ipv6_list {
|
||||
my_size += ::protobuf::rt::bytes_size(9, &value);
|
||||
};
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
|
||||
self.special_fields.cached_size().set(my_size as u32);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
|
||||
for v in &self.public_ip_list {
|
||||
os.write_fixed32(2, *v)?;
|
||||
};
|
||||
if self.public_port != 0 {
|
||||
os.write_uint32(3, self.public_port)?;
|
||||
}
|
||||
if self.public_port_range != 0 {
|
||||
os.write_uint32(4, self.public_port_range)?;
|
||||
}
|
||||
if self.nat_type != ::protobuf::EnumOrUnknown::new(PunchNatType::Symmetric) {
|
||||
os.write_enum(5, ::protobuf::EnumOrUnknown::value(&self.nat_type))?;
|
||||
}
|
||||
if self.reply != false {
|
||||
os.write_bool(6, self.reply)?;
|
||||
}
|
||||
if self.local_ip != 0 {
|
||||
os.write_fixed32(7, self.local_ip)?;
|
||||
}
|
||||
if self.local_port != 0 {
|
||||
os.write_uint32(8, self.local_port)?;
|
||||
}
|
||||
for v in &self.public_ipv6_list {
|
||||
os.write_bytes(9, &v)?;
|
||||
};
|
||||
os.write_unknown_fields(self.special_fields.unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn special_fields(&self) -> &::protobuf::SpecialFields {
|
||||
&self.special_fields
|
||||
}
|
||||
|
||||
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
|
||||
&mut self.special_fields
|
||||
}
|
||||
|
||||
fn new() -> PunchInfo {
|
||||
PunchInfo::new()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.public_ip_list.clear();
|
||||
self.public_port = 0;
|
||||
self.public_port_range = 0;
|
||||
self.nat_type = ::protobuf::EnumOrUnknown::new(PunchNatType::Symmetric);
|
||||
self.reply = false;
|
||||
self.local_ip = 0;
|
||||
self.local_port = 0;
|
||||
self.public_ipv6_list.clear();
|
||||
self.special_fields.clear();
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static PunchInfo {
|
||||
static instance: PunchInfo = PunchInfo {
|
||||
public_ip_list: ::std::vec::Vec::new(),
|
||||
public_port: 0,
|
||||
public_port_range: 0,
|
||||
nat_type: ::protobuf::EnumOrUnknown::from_i32(0),
|
||||
reply: false,
|
||||
local_ip: 0,
|
||||
local_port: 0,
|
||||
public_ipv6_list: ::std::vec::Vec::new(),
|
||||
special_fields: ::protobuf::SpecialFields::new(),
|
||||
};
|
||||
&instance
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::MessageFull for PunchInfo {
|
||||
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().message_by_package_relative_name("PunchInfo").unwrap()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for PunchInfo {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for PunchInfo {
|
||||
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,PartialEq,Eq,Debug,Hash)]
|
||||
// @@protoc_insertion_point(enum:PunchNatType)
|
||||
pub enum PunchNatType {
|
||||
// @@protoc_insertion_point(enum_value:PunchNatType.Symmetric)
|
||||
Symmetric = 0,
|
||||
// @@protoc_insertion_point(enum_value:PunchNatType.Cone)
|
||||
Cone = 1,
|
||||
}
|
||||
|
||||
impl ::protobuf::Enum for PunchNatType {
|
||||
const NAME: &'static str = "PunchNatType";
|
||||
|
||||
fn value(&self) -> i32 {
|
||||
*self as i32
|
||||
}
|
||||
|
||||
fn from_i32(value: i32) -> ::std::option::Option<PunchNatType> {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(PunchNatType::Symmetric),
|
||||
1 => ::std::option::Option::Some(PunchNatType::Cone),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
|
||||
const VALUES: &'static [PunchNatType] = &[
|
||||
PunchNatType::Symmetric,
|
||||
PunchNatType::Cone,
|
||||
];
|
||||
}
|
||||
|
||||
impl ::protobuf::EnumFull for PunchNatType {
|
||||
fn enum_descriptor() -> ::protobuf::reflect::EnumDescriptor {
|
||||
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
descriptor.get(|| file_descriptor().enum_by_package_relative_name("PunchNatType").unwrap()).clone()
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> ::protobuf::reflect::EnumValueDescriptor {
|
||||
let index = *self as usize;
|
||||
Self::enum_descriptor().value_by_index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::default::Default for PunchNatType {
|
||||
fn default() -> Self {
|
||||
PunchNatType::Symmetric
|
||||
}
|
||||
}
|
||||
|
||||
impl PunchNatType {
|
||||
fn generated_enum_descriptor_data() -> ::protobuf::reflect::GeneratedEnumDescriptorData {
|
||||
::protobuf::reflect::GeneratedEnumDescriptorData::new::<PunchNatType>("PunchNatType")
|
||||
}
|
||||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\rmessage.proto\"D\n\x10HandshakeRequest\x12\x18\n\x07version\x18\x01\
|
||||
\x20\x01(\tR\x07version\x12\x16\n\x06secret\x18\x02\x20\x01(\x08R\x06sec\
|
||||
ret\"\x83\x01\n\x11HandshakeResponse\x12\x18\n\x07version\x18\x01\x20\
|
||||
\x01(\tR\x07version\x12\x16\n\x06secret\x18\x02\x20\x01(\x08R\x06secret\
|
||||
\x12\x1d\n\npublic_key\x18\x03\x20\x01(\x0cR\tpublicKey\x12\x1d\n\nkey_f\
|
||||
inger\x18\x04\x20\x01(\tR\tkeyFinger\"@\n\x16SecretHandshakeRequest\x12\
|
||||
\x14\n\x05token\x18\x01\x20\x01(\tR\x05token\x12\x10\n\x03key\x18\x02\
|
||||
\x20\x01(\x0cR\x03key\"\xfb\x01\n\x13RegistrationRequest\x12\x14\n\x05to\
|
||||
ken\x18\x01\x20\x01(\tR\x05token\x12\x1b\n\tdevice_id\x18\x02\x20\x01(\t\
|
||||
R\x08deviceId\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04name\x12\x17\n\
|
||||
\x07is_fast\x18\x04\x20\x01(\x08R\x06isFast\x12\x18\n\x07version\x18\x05\
|
||||
\x20\x01(\tR\x07version\x12\x1d\n\nvirtual_ip\x18\x06\x20\x01(\x07R\tvir\
|
||||
tualIp\x12&\n\x0fallow_ip_change\x18\x07\x20\x01(\x08R\rallowIpChange\
|
||||
\x12#\n\rclient_secret\x18\x08\x20\x01(\x08R\x0cclientSecret\"\xb3\x02\n\
|
||||
\x14RegistrationResponse\x12\x1d\n\nvirtual_ip\x18\x01\x20\x01(\x07R\tvi\
|
||||
rtualIp\x12'\n\x0fvirtual_gateway\x18\x02\x20\x01(\x07R\x0evirtualGatewa\
|
||||
y\x12'\n\x0fvirtual_netmask\x18\x03\x20\x01(\x07R\x0evirtualNetmask\x12\
|
||||
\x14\n\x05epoch\x18\x04\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\
|
||||
\x18\x05\x20\x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\x12\x1b\n\tpubl\
|
||||
ic_ip\x18\x06\x20\x01(\x07R\x08publicIp\x12\x1f\n\x0bpublic_port\x18\x07\
|
||||
\x20\x01(\rR\npublicPort\x12\x1f\n\x0bpublic_ipv6\x18\x08\x20\x01(\x0cR\
|
||||
\npublicIpv6\"\x89\x01\n\nDeviceInfo\x12\x12\n\x04name\x18\x01\x20\x01(\
|
||||
\tR\x04name\x12\x1d\n\nvirtual_ip\x18\x02\x20\x01(\x07R\tvirtualIp\x12#\
|
||||
\n\rdevice_status\x18\x03\x20\x01(\rR\x0cdeviceStatus\x12#\n\rclient_sec\
|
||||
ret\x18\x04\x20\x01(\x08R\x0cclientSecret\"Y\n\nDeviceList\x12\x14\n\x05\
|
||||
epoch\x18\x01\x20\x01(\rR\x05epoch\x125\n\x10device_info_list\x18\x02\
|
||||
\x20\x03(\x0b2\x0b.DeviceInfoR\x0edeviceInfoList\"\xa2\x02\n\tPunchInfo\
|
||||
\x12$\n\x0epublic_ip_list\x18\x02\x20\x03(\x07R\x0cpublicIpList\x12\x1f\
|
||||
\n\x0bpublic_port\x18\x03\x20\x01(\rR\npublicPort\x12*\n\x11public_port_\
|
||||
range\x18\x04\x20\x01(\rR\x0fpublicPortRange\x12(\n\x08nat_type\x18\x05\
|
||||
\x20\x01(\x0e2\r.PunchNatTypeR\x07natType\x12\x14\n\x05reply\x18\x06\x20\
|
||||
\x01(\x08R\x05reply\x12\x19\n\x08local_ip\x18\x07\x20\x01(\x07R\x07local\
|
||||
Ip\x12\x1d\n\nlocal_port\x18\x08\x20\x01(\rR\tlocalPort\x12(\n\x10public\
|
||||
_ipv6_list\x18\t\x20\x03(\x0cR\x0epublicIpv6List*'\n\x0cPunchNatType\x12\
|
||||
\r\n\tSymmetric\x10\0\x12\x08\n\x04Cone\x10\x01b\x06proto3\
|
||||
";
|
||||
|
||||
/// `FileDescriptorProto` object which was a source for this generated file
|
||||
fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new();
|
||||
file_descriptor_proto_lazy.get(|| {
|
||||
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
/// `FileDescriptor` object which allows dynamic access to files
|
||||
pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
|
||||
static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new();
|
||||
file_descriptor.get(|| {
|
||||
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
|
||||
let mut deps = ::std::vec::Vec::with_capacity(0);
|
||||
let mut messages = ::std::vec::Vec::with_capacity(8);
|
||||
messages.push(HandshakeRequest::generated_message_descriptor_data());
|
||||
messages.push(HandshakeResponse::generated_message_descriptor_data());
|
||||
messages.push(SecretHandshakeRequest::generated_message_descriptor_data());
|
||||
messages.push(RegistrationRequest::generated_message_descriptor_data());
|
||||
messages.push(RegistrationResponse::generated_message_descriptor_data());
|
||||
messages.push(DeviceInfo::generated_message_descriptor_data());
|
||||
messages.push(DeviceList::generated_message_descriptor_data());
|
||||
messages.push(PunchInfo::generated_message_descriptor_data());
|
||||
let mut enums = ::std::vec::Vec::with_capacity(1);
|
||||
enums.push(PunchNatType::generated_enum_descriptor_data());
|
||||
::protobuf::reflect::GeneratedFileDescriptor::new_generated(
|
||||
file_descriptor_proto(),
|
||||
deps,
|
||||
messages,
|
||||
enums,
|
||||
)
|
||||
});
|
||||
::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
use std::{fmt, io};
|
||||
|
||||
pub const ENCRYPTION_RESERVED: usize = 32;
|
||||
/* 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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 数据体 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| random(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| tag(32) |
|
||||
| tag(32) |
|
||||
| tag(32) |
|
||||
| tag(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| finger(32) |
|
||||
| finger(32) |
|
||||
| finger(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
注:finger用于快速校验数据是否被修改,上层可使用token、协议头参与计算finger,
|
||||
确保服务端和客户端都能感知修改(服务端不能解密也能校验指纹)
|
||||
*/
|
||||
pub struct SecretBody<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> SecretBody<B> {
|
||||
pub fn new(buffer: B) -> io::Result<SecretBody<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
// 不能大于udp最大载荷长度
|
||||
if len < 32 || len > 65535 - 20 - 8 - 12 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
Ok(SecretBody { buffer })
|
||||
}
|
||||
pub fn data(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 32;
|
||||
&self.buffer.as_ref()[..end]
|
||||
}
|
||||
pub fn random(&self) -> u32 {
|
||||
let end = self.buffer.as_ref().len() - 16 - 12;
|
||||
u32::from_be_bytes(self.buffer.as_ref()[end - 4..end].try_into().unwrap())
|
||||
}
|
||||
pub fn body(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 16 - 12;
|
||||
&self.buffer.as_ref()[..end]
|
||||
}
|
||||
pub fn tag(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 12;
|
||||
&self.buffer.as_ref()[end - 16..end]
|
||||
}
|
||||
/// 数据部分+tag部分
|
||||
pub fn en_body(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 12;
|
||||
&self.buffer.as_ref()[..end]
|
||||
}
|
||||
pub fn finger(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len();
|
||||
&self.buffer.as_ref()[end - 12..end]
|
||||
}
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
self.buffer.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretBody<B> {
|
||||
pub fn set_data(&mut self, data: &[u8]) -> io::Result<()> {
|
||||
let end = self.buffer.as_ref().len() - 32;
|
||||
if end - 4 != data.len() {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "end-4 != data.len"));
|
||||
}
|
||||
self.buffer.as_mut()[..end].copy_from_slice(data);
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_random(&mut self, random: u32) {
|
||||
let end = self.buffer.as_ref().len() - 16 - 12;
|
||||
self.buffer.as_mut()[end - 4..end].copy_from_slice(&random.to_be_bytes());
|
||||
}
|
||||
|
||||
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 end = self.buffer.as_ref().len() - 12;
|
||||
self.buffer.as_mut()[end - 16..end].copy_from_slice(tag);
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
|
||||
if finger.len() != 12 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "finger.len != 12"));
|
||||
}
|
||||
let end = self.buffer.as_ref().len();
|
||||
self.buffer.as_mut()[end - 12..end].copy_from_slice(finger);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn data_mut(&mut self) -> &mut [u8] {
|
||||
let end = self.buffer.as_ref().len() - 32;
|
||||
&mut self.buffer.as_mut()[..end]
|
||||
}
|
||||
/// 数据部分
|
||||
pub fn body_mut(&mut self) -> &mut [u8] {
|
||||
let end = self.buffer.as_ref().len() - 12 - 16;
|
||||
&mut self.buffer.as_mut()[..end]
|
||||
}
|
||||
pub fn tag_mut(&mut self) -> &mut [u8] {
|
||||
let end = self.buffer.as_ref().len() - 12;
|
||||
&mut self.buffer.as_mut()[end - 16..end]
|
||||
}
|
||||
/// 数据部分+tag部分
|
||||
pub fn en_body_mut(&mut self) -> &mut [u8] {
|
||||
let end = self.buffer.as_ref().len() - 12;
|
||||
&mut self.buffer.as_mut()[..end]
|
||||
}
|
||||
pub fn buffer_mut(&mut self) -> &mut [u8] {
|
||||
self.buffer.as_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for SecretBody<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SecretBody")
|
||||
.field("random", &self.random())
|
||||
.field("body", &self.body())
|
||||
.field("tag", &self.tag())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
/* aes_cbc加密数据体
|
||||
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用于快速校验数据是否被修改,上层可使用token、协议头参与计算finger,
|
||||
确保服务端和客户端都能感知修改(服务端不能解密也能校验指纹)
|
||||
*/
|
||||
pub struct AesCbcSecretBody<B> {
|
||||
buffer: B,
|
||||
}
|
||||
impl<B: AsRef<[u8]>> AesCbcSecretBody<B> {
|
||||
pub fn new(buffer: B) -> io::Result<AesCbcSecretBody<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
// 不能大于udp最大载荷长度
|
||||
if len < 16 || len > 65535 - 20 - 8 - 12 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
Ok(AesCbcSecretBody { buffer })
|
||||
}
|
||||
pub fn en_body(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 12;
|
||||
&self.buffer.as_ref()[..end]
|
||||
}
|
||||
pub fn finger(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len();
|
||||
&self.buffer.as_ref()[end - 12..end]
|
||||
}
|
||||
}
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> AesCbcSecretBody<B> {
|
||||
pub fn set_random(&mut self, random: u32) {
|
||||
let end = self.buffer.as_ref().len() - 12;
|
||||
self.buffer.as_mut()[end - 4..end].copy_from_slice(&random.to_be_bytes());
|
||||
}
|
||||
pub fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
|
||||
if finger.len() != 12 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "finger.len != 12"));
|
||||
}
|
||||
let end = self.buffer.as_ref().len();
|
||||
self.buffer.as_mut()[end - 12..end].copy_from_slice(finger);
|
||||
Ok(())
|
||||
}
|
||||
pub fn en_body_mut(&mut self) -> &mut [u8] {
|
||||
let end = self.buffer.as_ref().len() - 12;
|
||||
&mut self.buffer.as_mut()[..end]
|
||||
}
|
||||
}
|
||||
|
||||
/* rsa加密数据体
|
||||
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) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| random(32) |
|
||||
| random(32) |
|
||||
| random(32) |
|
||||
| random(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| finger(32) |
|
||||
| finger(32) |
|
||||
| finger(32) |
|
||||
| finger(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
pub struct RsaSecretBody<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> RsaSecretBody<B> {
|
||||
pub fn new(buffer: B) -> io::Result<RsaSecretBody<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
// 不能大于udp最大载荷长度
|
||||
if len < 32 || len > 65535 - 20 - 8 - 12 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
Ok(RsaSecretBody { buffer })
|
||||
}
|
||||
pub fn data(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 32;
|
||||
&self.buffer.as_ref()[..end]
|
||||
}
|
||||
pub fn random(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 16;
|
||||
&self.buffer.as_ref()[end - 16..end]
|
||||
}
|
||||
pub fn body(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 16;
|
||||
&self.buffer.as_ref()[..end]
|
||||
}
|
||||
pub fn finger(&self) -> &[u8] {
|
||||
let end = self.buffer.as_ref().len() - 16;
|
||||
&self.buffer.as_ref()[end..]
|
||||
}
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> RsaSecretBody<B> {
|
||||
pub fn set_random(&mut self, random: &[u8]) -> io::Result<()> {
|
||||
if random.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "random.len != 16"));
|
||||
}
|
||||
let end = self.buffer.as_ref().len() - 16;
|
||||
self.buffer.as_mut()[end - 16..end].copy_from_slice(random);
|
||||
Ok(())
|
||||
}
|
||||
pub fn random_mut(&mut self) -> &mut [u8] {
|
||||
let end = self.buffer.as_ref().len() - 16;
|
||||
&mut self.buffer.as_mut()[end - 16..end]
|
||||
}
|
||||
pub fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
|
||||
if finger.len() != 16 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "finger.len != 16"));
|
||||
}
|
||||
let end = self.buffer.as_ref().len();
|
||||
self.buffer.as_mut()[end - 16..end].copy_from_slice(finger);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
/// ping请求
|
||||
/*
|
||||
0 1 2 3
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| time | echo |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
Ping,
|
||||
/// 维持连接,内容同ping
|
||||
Pong,
|
||||
/// 打洞请求
|
||||
PunchRequest,
|
||||
/// 打洞响应
|
||||
PunchResponse,
|
||||
///获取对端看到的地址
|
||||
AddrRequest,
|
||||
AddrResponse,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Ping,
|
||||
2 => Protocol::Pong,
|
||||
3 => Protocol::PunchRequest,
|
||||
4 => Protocol::PunchResponse,
|
||||
5 => Protocol::AddrRequest,
|
||||
6 => Protocol::AddrResponse,
|
||||
val => Protocol::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Ping => 1,
|
||||
Protocol::Pong => 2,
|
||||
Protocol::PunchRequest => 3,
|
||||
Protocol::PunchResponse => 4,
|
||||
Protocol::AddrRequest => 5,
|
||||
Protocol::AddrResponse => 6,
|
||||
Protocol::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ControlPacket<B> {
|
||||
PingPacket(PingPacket<B>),
|
||||
PongPacket(PongPacket<B>),
|
||||
PunchRequest,
|
||||
PunchResponse,
|
||||
AddrRequest,
|
||||
AddrResponse(AddrPacket<B>),
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> ControlPacket<B> {
|
||||
pub fn new(protocol: u8, buffer: B) -> io::Result<ControlPacket<B>> {
|
||||
match Protocol::from(protocol) {
|
||||
Protocol::Ping => Ok(ControlPacket::PingPacket(PingPacket::new(buffer)?)),
|
||||
Protocol::Pong => Ok(ControlPacket::PongPacket(PongPacket::new(buffer)?)),
|
||||
Protocol::PunchRequest => Ok(ControlPacket::PunchRequest),
|
||||
Protocol::PunchResponse => Ok(ControlPacket::PunchResponse),
|
||||
Protocol::AddrRequest => Ok(ControlPacket::AddrRequest),
|
||||
Protocol::AddrResponse => Ok(ControlPacket::AddrResponse(AddrPacket::new(buffer)?)),
|
||||
Protocol::Unknown(_) => Err(io::Error::new(io::ErrorKind::InvalidData, "Unsupported")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 网络探针
|
||||
pub struct PingPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
pub type PongPacket<B> = PingPacket<B>;
|
||||
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<PingPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 4 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "len != 4"));
|
||||
}
|
||||
Ok(PingPacket { buffer })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn time(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[..2].try_into().unwrap())
|
||||
}
|
||||
pub fn epoch(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> PingPacket<B> {
|
||||
pub fn set_time(&mut self, time: u16) {
|
||||
self.buffer.as_mut()[..2].copy_from_slice(&time.to_be_bytes())
|
||||
}
|
||||
pub fn set_epoch(&mut self, epoch: u16) {
|
||||
self.buffer.as_mut()[2..4].copy_from_slice(&epoch.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PingPacket")
|
||||
.field("time", &self.time())
|
||||
.field("epoch", &self.epoch())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AddrPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> AddrPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<AddrPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 6 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "len != 6"));
|
||||
}
|
||||
Ok(AddrPacket { buffer })
|
||||
}
|
||||
pub fn ipv4(&self) -> Ipv4Addr {
|
||||
let buf = self.buffer.as_ref();
|
||||
Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])
|
||||
}
|
||||
pub fn port(&self) -> u16 {
|
||||
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> AddrPacket<B> {
|
||||
pub fn set_ipv4(&mut self, ip: Ipv4Addr) {
|
||||
self.buffer.as_mut()[..4].copy_from_slice(&ip.octets())
|
||||
}
|
||||
pub fn set_port(&mut self, port: u16) {
|
||||
self.buffer.as_mut()[4..6].copy_from_slice(&port.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for AddrPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AddrPacket")
|
||||
.field("ipv4", &self.ipv4())
|
||||
.field("port", &self.port())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,10 @@ use crate::error::*;
|
||||
pub enum Protocol {
|
||||
TokenError,
|
||||
Disconnect,
|
||||
AddressExhausted,
|
||||
IpAlreadyExists,
|
||||
InvalidIp,
|
||||
NoKey,
|
||||
Other(u8),
|
||||
}
|
||||
|
||||
@@ -12,6 +16,10 @@ impl From<u8> for Protocol {
|
||||
match value {
|
||||
1 => Self::TokenError,
|
||||
2 => Self::Disconnect,
|
||||
3 => Self::AddressExhausted,
|
||||
4 => Self::IpAlreadyExists,
|
||||
5 => Self::InvalidIp,
|
||||
6 => Self::NoKey,
|
||||
val => Self::Other(val),
|
||||
}
|
||||
}
|
||||
@@ -22,6 +30,10 @@ impl Into<u8> for Protocol {
|
||||
match self {
|
||||
Protocol::TokenError => 1,
|
||||
Protocol::Disconnect => 2,
|
||||
Protocol::AddressExhausted => 3,
|
||||
Protocol::IpAlreadyExists => 4,
|
||||
Protocol::InvalidIp => 5,
|
||||
Protocol::NoKey => 6,
|
||||
Protocol::Other(val) => val,
|
||||
}
|
||||
}
|
||||
@@ -30,6 +42,10 @@ impl Into<u8> for Protocol {
|
||||
pub enum InErrorPacket<B> {
|
||||
TokenError,
|
||||
Disconnect,
|
||||
AddressExhausted,
|
||||
IpAlreadyExists,
|
||||
InvalidIp,
|
||||
NoKey,
|
||||
OtherError(ErrorPacket<B>),
|
||||
}
|
||||
|
||||
@@ -38,6 +54,10 @@ impl<B: AsRef<[u8]>> InErrorPacket<B> {
|
||||
match Protocol::from(protocol) {
|
||||
Protocol::TokenError => Ok(InErrorPacket::TokenError),
|
||||
Protocol::Disconnect => Ok(InErrorPacket::Disconnect),
|
||||
Protocol::AddressExhausted => Ok(InErrorPacket::AddressExhausted),
|
||||
Protocol::IpAlreadyExists => Ok(InErrorPacket::IpAlreadyExists),
|
||||
Protocol::InvalidIp => Ok(InErrorPacket::InvalidIp),
|
||||
Protocol::NoKey => Ok(InErrorPacket::NoKey),
|
||||
Protocol::Other(_) => Ok(InErrorPacket::OtherError(ErrorPacket::new(buffer)?)),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Protocol {
|
||||
Ipv4,
|
||||
Ipv4Broadcast,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
4 => Protocol::Ipv4,
|
||||
201 => Protocol::Ipv4Broadcast,
|
||||
val => Protocol::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Ipv4 => 4,
|
||||
Protocol::Ipv4Broadcast => 201,
|
||||
Protocol::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BroadcastPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> BroadcastPacket<B> {
|
||||
pub fn unchecked(buffer: B) -> Self {
|
||||
Self { buffer }
|
||||
}
|
||||
pub fn new(buffer: B) -> io::Result<Self> {
|
||||
let len = buffer.as_ref().len();
|
||||
let packet = Self::unchecked(buffer);
|
||||
if len < 2 + 4 || packet.addr_num() == 0 {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"InvalidData",
|
||||
))
|
||||
} else {
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> BroadcastPacket<B> {
|
||||
pub fn addr_num(&self) -> u8 {
|
||||
self.buffer.as_ref()[1]
|
||||
}
|
||||
/// 已经发送给了这些地址
|
||||
pub fn addresses(&self) -> Vec<Ipv4Addr> {
|
||||
let num = self.addr_num() as usize;
|
||||
let mut list = Vec::with_capacity(num);
|
||||
let buf = self.buffer.as_ref();
|
||||
let mut offset = 1;
|
||||
for _ in 0..num {
|
||||
list.push(Ipv4Addr::new(buf[offset], buf[offset + 1], buf[offset + 2], buf[offset + 3]));
|
||||
offset += 4;
|
||||
}
|
||||
list
|
||||
}
|
||||
pub fn data(&self) -> io::Result<&[u8]> {
|
||||
let start = 1 + self.addr_num() as usize * 4;
|
||||
if start > self.buffer.as_ref().len() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"InvalidData",
|
||||
))
|
||||
} else {
|
||||
Ok(&self.buffer.as_ref()[start..])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> BroadcastPacket<B> {
|
||||
pub fn set_address(&mut self, addr: &[Ipv4Addr]) -> io::Result<()> {
|
||||
let buf = self.buffer.as_mut();
|
||||
if buf.len() < 1 + addr.len() * 4 || addr.len() > u8::MAX as usize {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"InvalidData",
|
||||
))
|
||||
} else {
|
||||
buf[0] = addr.len() as u8;
|
||||
let mut offset = 1;
|
||||
for ip in addr {
|
||||
buf[offset..offset + 4].copy_from_slice(&ip.octets());
|
||||
offset += 4;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
pub fn set_data(&mut self, data: &[u8]) -> io::Result<()> {
|
||||
let num = self.addr_num() as usize;
|
||||
let start = 1 + 4 * num;
|
||||
let buf = self.buffer.as_mut();
|
||||
if start > buf.len() || start + data.len() != buf.len() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"InvalidData",
|
||||
));
|
||||
}
|
||||
buf[start..].copy_from_slice(data);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
use std::{fmt, io};
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
|
||||
/*
|
||||
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) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 源ip地址(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 目的ip地址(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 数据体 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
注:e为是否加密标志,s为服务端通信包标志,u未使用
|
||||
*/
|
||||
pub const HEAD_LEN: usize = 12;
|
||||
|
||||
pub mod body;
|
||||
pub mod control_packet;
|
||||
pub mod error_packet;
|
||||
pub mod service_packet;
|
||||
pub mod ip_turn_packet;
|
||||
pub mod other_turn_packet;
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Version {
|
||||
V1,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Version {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Version::V1,
|
||||
val => Version::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Version {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Version::V1 => 1,
|
||||
Version::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
/// 服务包 用于和服务端交互
|
||||
Service,
|
||||
/// 响应异常
|
||||
Error,
|
||||
/// 控制协议
|
||||
Control,
|
||||
/// 转发ip数据
|
||||
IpTurn,
|
||||
/// 转发其他数据
|
||||
OtherTurn,
|
||||
UnKnow(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Service,
|
||||
2 => Protocol::Error,
|
||||
3 => Protocol::Control,
|
||||
4 => Protocol::IpTurn,
|
||||
5 => Protocol::OtherTurn,
|
||||
val => Protocol::UnKnow(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Service => 1,
|
||||
Protocol::Error => 2,
|
||||
Protocol::Control => 3,
|
||||
Protocol::IpTurn => 4,
|
||||
Protocol::OtherTurn => 5,
|
||||
Protocol::UnKnow(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const MAX_TTL: u8 = 0b1111;
|
||||
pub const MAX_SOURCE: u8 = 0b11110000;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NetPacket<B> {
|
||||
data_len: usize,
|
||||
buffer: B,
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<NetPacket<B>> {
|
||||
let data_len = buffer.as_ref().len();
|
||||
Self::new0(data_len, buffer)
|
||||
}
|
||||
pub fn new_encrypt(buffer: B) -> io::Result<NetPacket<B>> {
|
||||
if 12 + ENCRYPTION_RESERVED > buffer.as_ref().len() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
//加密需要预留32字节
|
||||
let data_len = buffer.as_ref().len() - ENCRYPTION_RESERVED;
|
||||
Self::new0(data_len, buffer)
|
||||
}
|
||||
pub fn new0(data_len: usize, buffer: B) -> io::Result<NetPacket<B>> {
|
||||
if data_len > buffer.as_ref().len() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
// 不能大于udp最大载荷长度
|
||||
if data_len < 12 || buffer.as_ref().len() > 65535 - 20 - 8 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
Ok(NetPacket { data_len, buffer })
|
||||
}
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[..self.data_len]
|
||||
}
|
||||
pub fn raw_buffer(&self) -> &[u8] {
|
||||
self.buffer.as_ref()
|
||||
}
|
||||
pub fn data_len(&self) -> usize {
|
||||
self.data_len
|
||||
}
|
||||
pub fn reserve(&self) -> usize {
|
||||
self.buffer.as_ref().len() - self.data_len
|
||||
}
|
||||
pub fn into_buffer(self) -> B {
|
||||
self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
/// 数据加密
|
||||
pub fn is_encrypt(&self) -> bool {
|
||||
self.buffer.as_ref()[0] & 0x80 == 0x80
|
||||
}
|
||||
/// 网关通信的标识
|
||||
pub fn is_gateway(&self) -> bool {
|
||||
self.buffer.as_ref()[0] & 0x50 == 0x50
|
||||
}
|
||||
pub fn version(&self) -> Version {
|
||||
Version::from(self.buffer.as_ref()[0] & 0x0F)
|
||||
}
|
||||
pub fn protocol(&self) -> Protocol {
|
||||
Protocol::from(self.buffer.as_ref()[1])
|
||||
}
|
||||
pub fn transport_protocol(&self) -> u8 {
|
||||
self.buffer.as_ref()[2]
|
||||
}
|
||||
pub fn ttl(&self) -> u8 {
|
||||
self.buffer.as_ref()[3] & MAX_TTL
|
||||
}
|
||||
pub fn source_ttl(&self) -> u8 {
|
||||
self.buffer.as_ref()[3] >> 4
|
||||
}
|
||||
pub fn source(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn destination(&self) -> Ipv4Addr {
|
||||
let tmp: [u8; 4] = self.buffer.as_ref()[8..12].try_into().unwrap();
|
||||
Ipv4Addr::from(tmp)
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[12..self.data_len]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
||||
pub fn buffer_mut(&mut self) -> &mut [u8] {
|
||||
self.buffer.as_mut()
|
||||
}
|
||||
pub fn set_encrypt_flag(&mut self, is_encrypt: bool) {
|
||||
if is_encrypt {
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x80
|
||||
} else {
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0x7F
|
||||
};
|
||||
}
|
||||
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
|
||||
if is_gateway {
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
|
||||
} else {
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
|
||||
};
|
||||
}
|
||||
pub fn set_version(&mut self, version: Version) {
|
||||
let v: u8 = version.into();
|
||||
self.buffer.as_mut()[0] = (self.buffer.as_ref()[0] & 0xF0) | (0x0F & v);
|
||||
}
|
||||
pub fn set_protocol(&mut self, protocol: Protocol) {
|
||||
self.buffer.as_mut()[1] = protocol.into();
|
||||
}
|
||||
pub fn set_transport_protocol(&mut self, transport_protocol: u8) {
|
||||
self.buffer.as_mut()[2] = transport_protocol;
|
||||
}
|
||||
pub fn first_set_ttl(&mut self, ttl: u8) {
|
||||
self.buffer.as_mut()[3] = ttl << 4 | ttl;
|
||||
}
|
||||
pub fn set_ttl(&mut self, ttl: u8) {
|
||||
self.buffer.as_mut()[3] = (self.buffer.as_mut()[3] & MAX_SOURCE) | (MAX_TTL & ttl);
|
||||
}
|
||||
pub fn set_source_ttl(&mut self, source_ttl: u8) {
|
||||
self.buffer.as_mut()[3] = (source_ttl << 4) | (MAX_TTL & self.buffer.as_ref()[3]);
|
||||
}
|
||||
pub fn set_source(&mut self, source: Ipv4Addr) {
|
||||
self.buffer.as_mut()[4..8].copy_from_slice(&source.octets());
|
||||
}
|
||||
pub fn set_destination(&mut self, destination: Ipv4Addr) {
|
||||
self.buffer.as_mut()[8..12].copy_from_slice(&destination.octets());
|
||||
}
|
||||
pub fn set_payload(&mut self, payload: &[u8]) -> io::Result<()> {
|
||||
if self.data_len - 12 != payload.len() {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "data_len - 12 != payload.len"));
|
||||
}
|
||||
self.buffer.as_mut()[12..self.data_len].copy_from_slice(payload);
|
||||
Ok(())
|
||||
}
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[12..self.data_len]
|
||||
}
|
||||
pub fn set_data_len(&mut self, data_len: usize) -> io::Result<()> {
|
||||
if data_len > self.buffer.as_ref().len() || data_len < 12 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "data_len invalid"));
|
||||
}
|
||||
self.data_len = data_len;
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_data_len_max(&mut self) {
|
||||
self.data_len = self.buffer.as_ref().len();
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> fmt::Debug for NetPacket<B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("NetPacket")
|
||||
.field("version", &self.version())
|
||||
.field("gateway", &self.is_gateway())
|
||||
.field("encrypt", &self.is_encrypt())
|
||||
.field("protocol", &self.protocol())
|
||||
.field("transport_protocol", &self.transport_protocol())
|
||||
.field("ttl", &self.ttl())
|
||||
.field("source_ttl", &self.source_ttl())
|
||||
.field("source", &self.source())
|
||||
.field("destination", &self.destination())
|
||||
.field("payload", &self.payload())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum Protocol {
|
||||
Punch,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Protocol::Punch,
|
||||
val => Protocol::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Protocol::Punch => 1,
|
||||
Protocol::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum Protocol {
|
||||
/// 注册请求
|
||||
RegistrationRequest,
|
||||
/// 注册响应
|
||||
RegistrationResponse,
|
||||
/// 拉取设备列表
|
||||
PollDeviceList,
|
||||
/// 推送设备列表
|
||||
PushDeviceList,
|
||||
/// 和服务端握手
|
||||
HandshakeRequest,
|
||||
HandshakeResponse,
|
||||
SecretHandshakeRequest,
|
||||
SecretHandshakeResponse,
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
impl From<u8> for Protocol {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => Self::RegistrationRequest,
|
||||
2 => Self::RegistrationResponse,
|
||||
3 => Self::PollDeviceList,
|
||||
4 => Self::PushDeviceList,
|
||||
5 => Self::HandshakeRequest,
|
||||
6 => Self::HandshakeResponse,
|
||||
7 => Self::SecretHandshakeRequest,
|
||||
8 => Self::SecretHandshakeResponse,
|
||||
val => Self::Unknown(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for Protocol {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Self::RegistrationRequest => 1,
|
||||
Self::RegistrationResponse => 2,
|
||||
Self::PollDeviceList => 3,
|
||||
Self::PushDeviceList => 4,
|
||||
Self::HandshakeRequest => 5,
|
||||
Self::HandshakeResponse => 6,
|
||||
Self::SecretHandshakeRequest => 7,
|
||||
Self::SecretHandshakeResponse => 8,
|
||||
Self::Unknown(val) => val,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use std::io;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter(RawFd);
|
||||
|
||||
pub struct DeviceReader(RawFd);
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
unsafe {
|
||||
let amount = libc::write(self.0, buf.as_ptr() as *const _, buf.len());
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,为了兼容其他代码,头部空了14个字节
|
||||
pub fn write_ipv4(&self, buf: &[u8]) -> io::Result<()> {
|
||||
let buf = &buf[14..];
|
||||
self.write_ipv4_tun(buf)
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
// unsafe {
|
||||
// libc::close(self.0);
|
||||
// }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
unsafe {
|
||||
let amount = libc::read(self.0, buf.as_mut_ptr() as *mut _, buf.len());
|
||||
|
||||
if amount < 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(amount as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(fd: i32) -> (DeviceWriter, DeviceReader) {
|
||||
(DeviceWriter(fd as _), DeviceReader(fd as _))
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter, DriverInfo};
|
||||
use tun::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use crate::tun_tap_device::linux_mac::DeviceW;
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let mut config = tun::Configuration::default();
|
||||
let broadcast_address = (!u32::from_be_bytes(netmask.octets()))
|
||||
| u32::from_be_bytes(gateway.octets());
|
||||
let broadcast_address = Ipv4Addr::from(broadcast_address);
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.broadcast(broadcast_address)
|
||||
// .queues(2)
|
||||
.up();
|
||||
let mut dev = self.lock.lock();
|
||||
if let Err(e) = dev.configure(&config) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &self.in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
// add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!(
|
||||
"ip route add {:?}/{:?} dev {}",
|
||||
address, netmask, name
|
||||
);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: cmd:{},out:{:?}", route_add_str, route_add_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_device(device_type: DeviceType,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader,DriverInfo)> {
|
||||
let mut config = tun::Configuration::default();
|
||||
let broadcast_address = (!u32::from_be_bytes(netmask.octets()))
|
||||
| u32::from_be_bytes(gateway.octets());
|
||||
let broadcast_address = Ipv4Addr::from(broadcast_address);
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(mtu.into())
|
||||
.broadcast(broadcast_address)
|
||||
// .queues(2) 用多个队列有兼容性问题
|
||||
.up();
|
||||
match device_type {
|
||||
DeviceType::Tun => {}
|
||||
DeviceType::Tap => {
|
||||
config.layer(tun::Layer::L2);
|
||||
}
|
||||
}
|
||||
let dev = tun::create(&config).expect("tun/tap failed to create");
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
// add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
let device_w = match device_type {
|
||||
DeviceType::Tun => {
|
||||
DeviceW::Tun(writer)
|
||||
}
|
||||
DeviceType::Tap => {
|
||||
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
|
||||
let mac_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(get_mac_cmd)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !mac_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("获取mac地址错误: {:?}", mac_out)));
|
||||
}
|
||||
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();
|
||||
}
|
||||
DeviceW::Tap((writer, mac))
|
||||
}
|
||||
};
|
||||
let driver_info = DriverInfo {
|
||||
device_type,
|
||||
name:name.to_string(),
|
||||
version:String::new(),
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(device_w, Arc::new(Mutex::new(dev)), in_ips, address, packet_information),
|
||||
DeviceReader::new(reader),
|
||||
driver_info,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn delete_device(_device_type: DeviceType) {}
|
||||
@@ -0,0 +1,137 @@
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::BufMut;
|
||||
use tun::platform::posix::{Reader, Writer};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
use tun::platform::linux::Device;
|
||||
#[cfg(any(target_os = "macos"))]
|
||||
use tun::platform::macos::Device;
|
||||
use parking_lot::Mutex;
|
||||
use packet::ethernet;
|
||||
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
#[derive(Clone)]
|
||||
pub enum DeviceW {
|
||||
Tun(Writer),
|
||||
Tap((Writer, [u8; 6])),
|
||||
}
|
||||
|
||||
impl DeviceW {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
match self {
|
||||
DeviceW::Tun(_) => {
|
||||
true
|
||||
}
|
||||
DeviceW::Tap(_) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter {
|
||||
writer: DeviceW,
|
||||
pub lock: Arc<Mutex<Device>>,
|
||||
pub in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
packet_information: bool,
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn new(writer: DeviceW,lock: Arc<Mutex<Device>>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, _ip: Ipv4Addr, packet_information: bool) -> Self {
|
||||
Self {
|
||||
writer,
|
||||
lock,
|
||||
in_ips,
|
||||
packet_information,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn write(packet_information: bool, writer: &Writer, packet: &[u8]) -> io::Result<()> {
|
||||
if packet_information {
|
||||
let mut buf = Vec::<u8>::with_capacity(4 + packet.len());
|
||||
buf.put_u16(0);
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
buf.put_u16(libc::PF_INET as u16);
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
buf.put_u16(libc::ETH_P_IP as u16);
|
||||
buf.extend_from_slice(packet);
|
||||
writer.write_all(&buf)
|
||||
} else {
|
||||
writer.write_all(packet)
|
||||
}
|
||||
}
|
||||
///tun网卡写入ipv4数据
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => {
|
||||
Self::write(self.packet_information, writer, buf)
|
||||
}
|
||||
DeviceW::Tap(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
}
|
||||
}
|
||||
/// tap网卡写入以太网帧
|
||||
pub fn write_ethernet_tap(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
DeviceW::Tap((writer, _)) => {
|
||||
Self::write(self.packet_information, writer, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,头部必须留14字节,给tap写入以太网帧头
|
||||
pub fn write_ipv4(&self, buf: &mut [u8]) -> io::Result<()> {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => {
|
||||
Self::write(self.packet_information, writer, &buf[14..])
|
||||
}
|
||||
DeviceW::Tap((writer, mac)) => {
|
||||
let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], !mac[5], 234];
|
||||
let mut ethernet_packet = EthernetPacket::unchecked(buf);
|
||||
ethernet_packet.set_source(&source_mac);
|
||||
ethernet_packet.set_destination(mac);
|
||||
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||
Self::write(self.packet_information, writer, ðernet_packet.buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
unsafe {
|
||||
match &self.writer {
|
||||
DeviceW::Tun(writer) => {
|
||||
libc::close(writer.as_raw_fd());
|
||||
}
|
||||
DeviceW::Tap((writer, _)) => {
|
||||
libc::close(writer.as_raw_fd());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn is_tun(&self) -> bool {
|
||||
self.writer.is_tun()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeviceReader(Reader);
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn new(device: Reader) -> Self {
|
||||
DeviceReader(device)
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use crate::tun_tap_device::{DeviceReader, DeviceType, DeviceWriter, DriverInfo};
|
||||
use tun::Device;
|
||||
use parking_lot::Mutex;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use crate::tun_tap_device::linux_mac::DeviceW;
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let mut config = tun::Configuration::default();
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.up();
|
||||
let mut dev = self.lock.lock();
|
||||
if let Err(e) = dev.configure(&config) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
||||
}
|
||||
if let Err(e) = config_ip(dev.name(), address, netmask, gateway) {
|
||||
log::error!("{}",e);
|
||||
}
|
||||
let name = dev.name();
|
||||
for (address, netmask) in &self.in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_device(device_type: DeviceType,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
match device_type {
|
||||
DeviceType::Tun => {}
|
||||
DeviceType::Tap => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
let mut config = tun::Configuration::default();
|
||||
|
||||
config
|
||||
.destination(gateway)
|
||||
.address(address)
|
||||
.netmask(netmask)
|
||||
.mtu(mtu.into())
|
||||
.up();
|
||||
|
||||
let dev = tun::create(&config).unwrap();
|
||||
let name = dev.name();
|
||||
config_ip(name, address, netmask, gateway)?;
|
||||
for (address, netmask) in &in_ips {
|
||||
add_route(name, *address, *netmask)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
add_route(name, address, netmask)?;
|
||||
// 广播和组播路由
|
||||
add_route(name, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)?;
|
||||
add_route(name, Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]))?;
|
||||
let packet_information = dev.has_packet_information();
|
||||
let queue = dev.queue(0).unwrap();
|
||||
let reader = queue.reader();
|
||||
let writer = queue.writer();
|
||||
let driver_info = DriverInfo {
|
||||
device_type,
|
||||
name: name.to_string(),
|
||||
version: String::new(),
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(DeviceW::Tun(writer), Arc::new(Mutex::new(dev)), in_ips, address, packet_information),
|
||||
DeviceReader::new(reader),
|
||||
driver_info
|
||||
))
|
||||
}
|
||||
|
||||
fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||
let route_add_str: String = format!(
|
||||
"route -n add {} -netmask {} -interface {}",
|
||||
address, netmask, name
|
||||
);
|
||||
let route_add_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&route_add_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !route_add_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: cmd:{},out:{:?}", route_add_str, route_add_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn config_ip(name: &str, address: Ipv4Addr, _netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, address, gateway);
|
||||
let up_eth_out = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(&up_eth_str)
|
||||
.output()
|
||||
.expect("sh exec error!");
|
||||
if !up_eth_out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: cmd:{},out:{:?}", up_eth_str, up_eth_out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_device(_device_type: DeviceType) {}
|
||||
@@ -0,0 +1,53 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
mod linux;
|
||||
#[cfg(target_os = "macos")]
|
||||
mod mac;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
mod linux_mac;
|
||||
#[cfg(target_os = "android")]
|
||||
mod android;
|
||||
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
pub use linux::create_device;
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
pub use linux::delete_device;
|
||||
#[cfg(target_os = "android")]
|
||||
pub use android::create;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub use linux_mac::{DeviceWriter, DeviceReader};
|
||||
#[cfg(target_os = "android")]
|
||||
pub use android::{DeviceWriter, DeviceReader};
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::create_device;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use mac::delete_device;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::create_device;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::delete_device;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{DeviceWriter, DeviceReader};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DeviceType {
|
||||
Tun,
|
||||
Tap,
|
||||
}
|
||||
|
||||
impl DeviceType {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
*self == DeviceType::Tun
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DriverInfo {
|
||||
pub device_type: DeviceType,
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub mac: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
use std::{io, thread};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use libloading::Library;
|
||||
use parking_lot::Mutex;
|
||||
use packet::ethernet;
|
||||
use packet::ethernet::packet::EthernetPacket;
|
||||
use win_tun_tap::{IFace, TapDevice, TunDevice};
|
||||
use crate::tun_tap_device::{DriverInfo, DeviceType};
|
||||
|
||||
pub const TUN_INTERFACE_NAME: &str = "Vnt-Tun-V1";
|
||||
pub const TUN_POOL_NAME: &str = "Vnt-Tun-V1";
|
||||
pub const TAP_INTERFACE_NAME: &str = "Vnt-Tap-V1";
|
||||
|
||||
pub enum Device {
|
||||
Tun(TunDevice),
|
||||
Tap((TapDevice, [u8; 6])),
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn is_tun(&self) -> bool {
|
||||
match self {
|
||||
Device::Tun(_) => {
|
||||
true
|
||||
}
|
||||
Device::Tap(_) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceWriter {
|
||||
device: Arc<Device>,
|
||||
lock: Arc<Mutex<()>>,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
pub fn new(device: Arc<Device>, in_ips: Vec<(Ipv4Addr, Ipv4Addr)>, _ip: Ipv4Addr) -> Self {
|
||||
Self {
|
||||
device,
|
||||
lock: Arc::new(Default::default()),
|
||||
in_ips,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceWriter {
|
||||
///tun网卡写入ipv4数据
|
||||
pub fn write_ipv4_tun(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let mut packet = dev.allocate_send_packet(buf.len() as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(buf);
|
||||
dev.send_packet(packet);
|
||||
Ok(())
|
||||
}
|
||||
Device::Tap(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
}
|
||||
}
|
||||
/// tap网卡写入以太网帧
|
||||
pub fn write_ethernet_tap(&self, buf: &[u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(_) => {
|
||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev.write(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
///写入ipv4数据,头部必须留14字节,给tap写入以太网帧头
|
||||
pub fn write_ipv4(&self, buf: &mut [u8]) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let mut packet = dev.allocate_send_packet((buf.len() - 14) as u16)?;
|
||||
packet.bytes_mut().copy_from_slice(&buf[14..]);
|
||||
dev.send_packet(packet);
|
||||
}
|
||||
Device::Tap((dev, mac)) => {
|
||||
let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], !mac[5], 234];
|
||||
let mut ethernet_packet = EthernetPacket::unchecked(buf);
|
||||
ethernet_packet.set_source(&source_mac);
|
||||
ethernet_packet.set_destination(mac);
|
||||
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||
dev.write(ðernet_packet.buffer)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn change_ip(
|
||||
&self,
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
old_netmask: Ipv4Addr,
|
||||
old_gateway: Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
let _guard = self.lock.lock();
|
||||
let dev: &dyn IFace = match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
dev as &dyn IFace
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev as &dyn IFace
|
||||
}
|
||||
};
|
||||
if let Err(e) =
|
||||
dev.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
|
||||
{
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
dev.set_ip(address, netmask)?;
|
||||
for (address, netmask) in &self.in_ips {
|
||||
dev.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
dev.add_route(address, netmask, gateway, 1)?;
|
||||
// 广播和组播路由
|
||||
dev.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
dev.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?;
|
||||
delete_cache();
|
||||
Ok(())
|
||||
}
|
||||
pub fn close(&self) -> io::Result<()> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
dev.shutdown()
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev.shutdown()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn is_tun(&self) -> bool {
|
||||
self.device.is_tun()
|
||||
}
|
||||
}
|
||||
|
||||
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
|
||||
let ip = ip.octets();
|
||||
let mask = mask.octets();
|
||||
Ipv4Addr::from([
|
||||
ip[0] & mask[0],
|
||||
ip[1] & mask[1],
|
||||
ip[2] & mask[2],
|
||||
ip[3] & mask[3],
|
||||
])
|
||||
}
|
||||
|
||||
pub struct DeviceReader {
|
||||
device: Arc<Device>,
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn new(device: Arc<Device>) -> Self {
|
||||
Self {
|
||||
device,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceReader {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self.device.as_ref() {
|
||||
Device::Tun(dev) => {
|
||||
let packet = dev.receive_blocking()?;
|
||||
let packet = packet.bytes();
|
||||
let len = packet.len();
|
||||
if len > buf.len() {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "data too long"));
|
||||
}
|
||||
buf[..len].copy_from_slice(packet);
|
||||
Ok(len)
|
||||
}
|
||||
Device::Tap((dev, _)) => {
|
||||
dev.read(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tun(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(_) => {
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("wintun.dll not found {:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
let tun_device = match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(_) => {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
match TunDevice::create(
|
||||
Library::new("wintun.dll").unwrap(),
|
||||
TUN_POOL_NAME,
|
||||
TUN_INTERFACE_NAME,
|
||||
) {
|
||||
Ok(tun_device) => tun_device,
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("{:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let name = tun_device.get_name()?;
|
||||
let version = format!("{:?}", tun_device.version()?);
|
||||
tun_device.set_ip(address, netmask)?;
|
||||
tun_device.set_metric(1)?;
|
||||
tun_device.set_mtu(mtu)?;
|
||||
// ip代理路由
|
||||
for (address, netmask) in &in_ips {
|
||||
tun_device.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 当前网段路由
|
||||
tun_device.add_route(address, netmask, gateway, 1)?;
|
||||
// 广播和组播路由
|
||||
tun_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
tun_device.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?;
|
||||
delete_cache();
|
||||
let device = Arc::new(Device::Tun(tun_device));
|
||||
let driver_info = DriverInfo {
|
||||
device_type: DeviceType::Tun,
|
||||
name,
|
||||
version,
|
||||
mac: None,
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(device.clone(), in_ips, address),
|
||||
DeviceReader::new(device),
|
||||
driver_info
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_cache() {
|
||||
//清除路由缓存
|
||||
let delete_cache = "netsh interface ip delete destinationcache";
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(delete_cache)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
log::warn!("删除缓存失败:{:?}",out);
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_tun() {
|
||||
unsafe {
|
||||
match Library::new("wintun.dll") {
|
||||
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {}
|
||||
},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tap(
|
||||
address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16,
|
||||
) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
let tap_device = TapDevice::create()?;
|
||||
tap_device.set_name(TAP_INTERFACE_NAME)?;
|
||||
tap_device
|
||||
}
|
||||
};
|
||||
let mac = tap_device.get_mac()?;
|
||||
let name = tap_device.get_name()?;
|
||||
let version = format!("{:?}", tap_device.get_version()?);
|
||||
let mac_str = format!("mac:{:x?}", mac);
|
||||
tap_device.set_ip(address, netmask)?;
|
||||
tap_device.set_metric(1)?;
|
||||
tap_device.set_mtu(mtu)?;
|
||||
tap_device.set_status(true)?;
|
||||
tap_device.add_route(address, netmask, gateway, 1)?;
|
||||
for (address, netmask) in &in_ips {
|
||||
tap_device.add_route(*address, *netmask, gateway, 1)?;
|
||||
}
|
||||
// 广播和组播路由
|
||||
tap_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?;
|
||||
tap_device.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?;
|
||||
delete_cache();
|
||||
let tap = Arc::new(Device::Tap((tap_device, mac)));
|
||||
let driver_info = DriverInfo {
|
||||
device_type: DeviceType::Tap,
|
||||
name,
|
||||
version,
|
||||
mac: Some(mac_str),
|
||||
};
|
||||
Ok((
|
||||
DeviceWriter::new(tap.clone(), in_ips, address),
|
||||
DeviceReader::new(tap),
|
||||
driver_info
|
||||
))
|
||||
}
|
||||
|
||||
fn delete_tap() {
|
||||
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||
Ok(tap_device) => tap_device,
|
||||
Err(_) => {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let _ = tap_device.delete();
|
||||
}
|
||||
|
||||
pub fn create_device(device_type: DeviceType, address: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr,
|
||||
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
mtu: u16) -> io::Result<(DeviceWriter, DeviceReader, DriverInfo)> {
|
||||
match device_type {
|
||||
DeviceType::Tun => {
|
||||
create_tun(address, netmask, gateway, in_ips, mtu)
|
||||
}
|
||||
DeviceType::Tap => {
|
||||
create_tap(address, netmask, gateway, in_ips, mtu)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_device(device_type: DeviceType) {
|
||||
match device_type {
|
||||
DeviceType::Tun => {
|
||||
delete_tun()
|
||||
}
|
||||
DeviceType::Tap => {
|
||||
delete_tap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod wait;
|
||||
@@ -0,0 +1,44 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
use tokio::sync::watch::{channel, Receiver, Sender};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WaitGroup {
|
||||
count: Arc<AtomicIsize>,
|
||||
receiver: Receiver<usize>,
|
||||
sender: Arc<Sender<usize>>,
|
||||
}
|
||||
|
||||
impl WaitGroup {
|
||||
pub fn new() -> Self {
|
||||
let (sender, receiver) = channel(1);
|
||||
Self {
|
||||
count: Arc::new(Default::default()),
|
||||
receiver,
|
||||
sender: Arc::new(sender),
|
||||
}
|
||||
}
|
||||
pub fn add(&self) {
|
||||
let _ = self.count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
pub fn done(&self) {
|
||||
let i = self.count.fetch_sub(1, Ordering::Relaxed);
|
||||
if i == 1 {
|
||||
let _ = self.sender.send(0);
|
||||
}
|
||||
}
|
||||
pub async fn wait(&mut self) {
|
||||
loop {
|
||||
if 0 == *self.receiver.borrow() {
|
||||
return;
|
||||
}
|
||||
if self.receiver.changed().await.is_ok() {
|
||||
if 0 == *self.receiver.borrow() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "win-tun-tap"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.17"
|
||||
winreg = "0.7"
|
||||
scopeguard = "1.1"
|
||||
libloading = "0.7"
|
||||
widestring = "0.4"
|
||||
once_cell = "1.8"
|
||||
itertools = "0.10.1"
|
||||
rand = "0.8.5"
|
||||
[dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = [
|
||||
"errhandlingapi",
|
||||
"combaseapi",
|
||||
"ioapiset",
|
||||
"winioctl",
|
||||
"setupapi",
|
||||
"synchapi",
|
||||
"netioapi",
|
||||
"fileapi",
|
||||
"winbase",
|
||||
"winerror",
|
||||
"ipexport",
|
||||
"iphlpapi",
|
||||
"handleapi"
|
||||
]
|
||||
@@ -0,0 +1,534 @@
|
||||
// Many things will be used in the future
|
||||
#![allow(unused)]
|
||||
|
||||
//! Module holding safe wrappers over winapi functions
|
||||
|
||||
use winapi::shared::basetsd::*;
|
||||
use winapi::shared::guiddef::GUID;
|
||||
use winapi::shared::ifdef::*;
|
||||
use winapi::shared::minwindef::*;
|
||||
use winapi::shared::netioapi::*;
|
||||
use winapi::shared::winerror::*;
|
||||
|
||||
use winapi::um::combaseapi::*;
|
||||
use winapi::um::errhandlingapi::*;
|
||||
use winapi::um::fileapi::*;
|
||||
use winapi::um::handleapi::*;
|
||||
use winapi::um::ioapiset::*;
|
||||
use winapi::um::setupapi::*;
|
||||
use winapi::um::synchapi::*;
|
||||
use winapi::um::winioctl::*;
|
||||
use winapi::um::winnt::*;
|
||||
use winapi::um::winreg::*;
|
||||
|
||||
use std::{io, mem, ptr};
|
||||
use std::error::Error;
|
||||
use winapi::um::minwinbase::OVERLAPPED_u;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
/// Custom type to handle variable size SP_DRVINFO_DETAIL_DATA_W
|
||||
pub struct SP_DRVINFO_DETAIL_DATA_W2 {
|
||||
pub cbSize: DWORD,
|
||||
pub InfDate: FILETIME,
|
||||
pub CompatIDsOffset: DWORD,
|
||||
pub CompatIDsLength: DWORD,
|
||||
pub Reserved: ULONG_PTR,
|
||||
pub SectionName: [WCHAR; 256],
|
||||
pub InfFileName: [WCHAR; 260],
|
||||
pub DrvDescription: [WCHAR; 256],
|
||||
pub HardwareID: [WCHAR; 512],
|
||||
}
|
||||
|
||||
pub fn string_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
|
||||
// GUID_STRING_CHARACTERS + 1
|
||||
let mut string = vec![0; 39];
|
||||
|
||||
match unsafe {
|
||||
StringFromGUID2(guid, string.as_mut_ptr(), string.len() as _)
|
||||
} {
|
||||
0 => Err(io::Error::new(io::ErrorKind::Other, "Insufficent buffer")),
|
||||
_ => Ok(string),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alias_to_luid(alias: &[WCHAR]) -> io::Result<NET_LUID> {
|
||||
let mut luid = unsafe { mem::zeroed() };
|
||||
|
||||
match unsafe { ConvertInterfaceAliasToLuid(alias.as_ptr(), &mut luid) } {
|
||||
0 => Ok(luid),
|
||||
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn luid_to_index(luid: &NET_LUID) -> io::Result<NET_IFINDEX> {
|
||||
let mut index = 0;
|
||||
|
||||
match unsafe { ConvertInterfaceLuidToIndex(luid, &mut index) } {
|
||||
0 => Ok(index),
|
||||
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn luid_to_guid(luid: &NET_LUID) -> io::Result<GUID> {
|
||||
let mut guid = unsafe { mem::zeroed() };
|
||||
|
||||
match unsafe { ConvertInterfaceLuidToGuid(luid, &mut guid) } {
|
||||
0 => Ok(guid),
|
||||
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn luid_to_alias(luid: &NET_LUID) -> io::Result<Vec<WCHAR>> {
|
||||
// IF_MAX_STRING_SIZE + 1
|
||||
let mut alias = vec![0; 257];
|
||||
|
||||
match unsafe {
|
||||
ConvertInterfaceLuidToAlias(luid, alias.as_mut_ptr(), alias.len())
|
||||
} {
|
||||
0 => {
|
||||
Ok(alias)
|
||||
}
|
||||
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close_handle(handle: HANDLE) -> io::Result<()> {
|
||||
match unsafe { CloseHandle(handle) } {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_file(
|
||||
file_name: &[WCHAR],
|
||||
desired_access: DWORD,
|
||||
share_mode: DWORD,
|
||||
creation_disposition: DWORD,
|
||||
flags_and_attributes: DWORD,
|
||||
) -> io::Result<HANDLE> {
|
||||
match unsafe {
|
||||
CreateFileW(
|
||||
file_name.as_ptr(),
|
||||
desired_access,
|
||||
share_mode,
|
||||
ptr::null_mut(),
|
||||
creation_disposition,
|
||||
flags_and_attributes,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
} {
|
||||
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||
handle => Ok(handle),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_file(handle: HANDLE, buffer: &mut [u8]) -> io::Result<DWORD> {
|
||||
let mut ret = 0;
|
||||
//https://www.cnblogs.com/linyilong3/archive/2012/05/03/2480451.html
|
||||
unsafe {
|
||||
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
|
||||
Internal: 0,
|
||||
InternalHigh: 0,
|
||||
u: Default::default(),
|
||||
hEvent: ptr::null_mut(),
|
||||
};
|
||||
if 0 == ReadFile(
|
||||
handle,
|
||||
buffer.as_mut_ptr() as _,
|
||||
buffer.len() as _,
|
||||
&mut ret,
|
||||
&mut ip_overlapped, ) {
|
||||
let e = io::Error::last_os_error();
|
||||
if e.raw_os_error().unwrap_or(0) == 997 {
|
||||
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
|
||||
return Err(e);
|
||||
}
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_file(handle: HANDLE, buffer: &[u8]) -> io::Result<DWORD> {
|
||||
let mut ret = 0;
|
||||
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
|
||||
Internal: 0,
|
||||
InternalHigh: 0,
|
||||
u: Default::default(),
|
||||
hEvent: ptr::null_mut(),
|
||||
};
|
||||
unsafe {
|
||||
if 0 == WriteFile(
|
||||
handle,
|
||||
buffer.as_ptr() as _,
|
||||
buffer.len() as _,
|
||||
&mut ret,
|
||||
&mut ip_overlapped,
|
||||
) {
|
||||
let e = io::Error::last_os_error();
|
||||
if e.raw_os_error().unwrap_or(0) == 997 {
|
||||
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
|
||||
return Err(e);
|
||||
}
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_device_info_list(guid: &GUID) -> io::Result<HDEVINFO> {
|
||||
match unsafe { SetupDiCreateDeviceInfoList(guid, ptr::null_mut()) } {
|
||||
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||
devinfo => Ok(devinfo),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_class_devs(guid: &GUID, flags: DWORD) -> io::Result<HDEVINFO> {
|
||||
match unsafe {
|
||||
SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), flags)
|
||||
} {
|
||||
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||
devinfo => Ok(devinfo),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy_device_info_list(devinfo: HDEVINFO) -> io::Result<()> {
|
||||
match unsafe { SetupDiDestroyDeviceInfoList(devinfo) } {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn class_name_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
|
||||
let mut class_name = vec![0; 32];
|
||||
|
||||
match unsafe {
|
||||
SetupDiClassNameFromGuidW(
|
||||
guid,
|
||||
class_name.as_mut_ptr(),
|
||||
class_name.len() as _,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(class_name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_device_info(
|
||||
devinfo: HDEVINFO,
|
||||
device_name: &[WCHAR],
|
||||
guid: &GUID,
|
||||
device_description: &[WCHAR],
|
||||
creation_flags: DWORD,
|
||||
) -> io::Result<SP_DEVINFO_DATA> {
|
||||
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
|
||||
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
|
||||
|
||||
match unsafe {
|
||||
SetupDiCreateDeviceInfoW(
|
||||
devinfo,
|
||||
device_name.as_ptr(),
|
||||
guid,
|
||||
device_description.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
creation_flags,
|
||||
&mut devinfo_data,
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(devinfo_data),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_selected_device(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
) -> io::Result<()> {
|
||||
match unsafe {
|
||||
SetupDiSetSelectedDevice(devinfo, devinfo_data as *const _ as _)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_device_registry_property(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
property: DWORD,
|
||||
value: &[WCHAR],
|
||||
) -> io::Result<()> {
|
||||
match unsafe {
|
||||
SetupDiSetDeviceRegistryPropertyW(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
property,
|
||||
value.as_ptr() as _,
|
||||
(value.len() * 2) as _,
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_device_registry_property(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
property: DWORD,
|
||||
) -> io::Result<Vec<WCHAR>> {
|
||||
let mut value = vec![0; 32];
|
||||
|
||||
match unsafe {
|
||||
SetupDiGetDeviceRegistryPropertyW(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
property,
|
||||
ptr::null_mut(),
|
||||
value.as_mut_ptr() as _,
|
||||
(value.len() * 2) as _,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_driver_info_list(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
driver_type: DWORD,
|
||||
) -> io::Result<()> {
|
||||
match unsafe {
|
||||
SetupDiBuildDriverInfoList(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
driver_type,
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy_driver_info_list(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
driver_type: DWORD,
|
||||
) -> io::Result<()> {
|
||||
match unsafe {
|
||||
SetupDiDestroyDriverInfoList(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
driver_type,
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_driver_info_detail(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
drvinfo_data: &SP_DRVINFO_DATA_W,
|
||||
) -> io::Result<SP_DRVINFO_DETAIL_DATA_W2> {
|
||||
let mut drvinfo_detail: SP_DRVINFO_DETAIL_DATA_W2 =
|
||||
unsafe { mem::zeroed() };
|
||||
drvinfo_detail.cbSize = mem::size_of::<SP_DRVINFO_DETAIL_DATA_W>() as _;
|
||||
|
||||
match unsafe {
|
||||
SetupDiGetDriverInfoDetailW(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
drvinfo_data as *const _ as _,
|
||||
&mut drvinfo_detail as *mut _ as _,
|
||||
mem::size_of_val(&drvinfo_detail) as _,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(drvinfo_detail),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_selected_driver(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
drvinfo_data: &SP_DRVINFO_DATA_W,
|
||||
) -> io::Result<()> {
|
||||
match unsafe {
|
||||
SetupDiSetSelectedDriverW(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
drvinfo_data as *const _ as _,
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_class_install_params(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
params: &impl Copy,
|
||||
) -> io::Result<()> {
|
||||
match unsafe {
|
||||
SetupDiSetClassInstallParamsW(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
params as *const _ as _,
|
||||
mem::size_of_val(params) as _,
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_class_installer(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
install_function: DI_FUNCTION,
|
||||
) -> io::Result<()> {
|
||||
match unsafe {
|
||||
SetupDiCallClassInstaller(
|
||||
install_function,
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_dev_reg_key(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
scope: DWORD,
|
||||
hw_profile: DWORD,
|
||||
key_type: DWORD,
|
||||
sam_desired: REGSAM,
|
||||
) -> io::Result<HKEY> {
|
||||
const INVALID_KEY_VALUE: HKEY = INVALID_HANDLE_VALUE as _;
|
||||
|
||||
match unsafe {
|
||||
SetupDiOpenDevRegKey(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
scope,
|
||||
hw_profile,
|
||||
key_type,
|
||||
sam_desired,
|
||||
)
|
||||
} {
|
||||
INVALID_KEY_VALUE => Err(io::Error::last_os_error()),
|
||||
key => Ok(key),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_change_key_value(
|
||||
key: HKEY,
|
||||
watch_subtree: BOOL,
|
||||
notify_filter: DWORD,
|
||||
milliseconds: DWORD,
|
||||
) -> io::Result<()> {
|
||||
let event = match unsafe {
|
||||
CreateEventW(ptr::null_mut(), FALSE, FALSE, ptr::null())
|
||||
} {
|
||||
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||
event => Ok(event),
|
||||
}?;
|
||||
|
||||
match unsafe {
|
||||
RegNotifyChangeKeyValue(key, watch_subtree, notify_filter, event, TRUE)
|
||||
} {
|
||||
0 => Ok(()),
|
||||
err => Err(io::Error::from_raw_os_error(err)),
|
||||
}?;
|
||||
|
||||
match unsafe { WaitForSingleObject(event, milliseconds) } {
|
||||
0 => Ok(()),
|
||||
0x102 => Err(io::Error::new(
|
||||
io::ErrorKind::TimedOut,
|
||||
"Registry timed out",
|
||||
)),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enum_driver_info(
|
||||
devinfo: HDEVINFO,
|
||||
devinfo_data: &SP_DEVINFO_DATA,
|
||||
driver_type: DWORD,
|
||||
member_index: DWORD,
|
||||
) -> Option<io::Result<SP_DRVINFO_DATA_W>> {
|
||||
let mut drvinfo_data: SP_DRVINFO_DATA_W = unsafe { mem::zeroed() };
|
||||
drvinfo_data.cbSize = mem::size_of_val(&drvinfo_data) as _;
|
||||
|
||||
match unsafe {
|
||||
SetupDiEnumDriverInfoW(
|
||||
devinfo,
|
||||
devinfo_data as *const _ as _,
|
||||
driver_type,
|
||||
member_index,
|
||||
&mut drvinfo_data,
|
||||
)
|
||||
} {
|
||||
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
|
||||
0 => Some(Err(io::Error::last_os_error())),
|
||||
_ => Some(Ok(drvinfo_data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enum_device_info(
|
||||
devinfo: HDEVINFO,
|
||||
member_index: DWORD,
|
||||
) -> Option<io::Result<SP_DEVINFO_DATA>> {
|
||||
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
|
||||
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
|
||||
|
||||
match unsafe {
|
||||
SetupDiEnumDeviceInfo(devinfo, member_index, &mut devinfo_data)
|
||||
} {
|
||||
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
|
||||
0 => Some(Err(io::Error::last_os_error())),
|
||||
_ => Some(Ok(devinfo_data)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn device_io_control(
|
||||
handle: HANDLE,
|
||||
io_control_code: DWORD,
|
||||
in_buffer: &impl Copy,
|
||||
out_buffer: &mut impl Copy,
|
||||
) -> io::Result<()> {
|
||||
let mut junk = 0;
|
||||
|
||||
match unsafe {
|
||||
DeviceIoControl(
|
||||
handle,
|
||||
io_control_code,
|
||||
in_buffer as *const _ as _,
|
||||
mem::size_of_val(in_buffer) as _,
|
||||
out_buffer as *mut _ as _,
|
||||
mem::size_of_val(out_buffer) as _,
|
||||
&mut junk,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
} {
|
||||
0 => Err(io::Error::last_os_error()),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#![cfg(windows)]
|
||||
|
||||
mod tap;
|
||||
mod tun;
|
||||
mod ffi;
|
||||
mod netsh;
|
||||
mod route;
|
||||
use std::{io, net};
|
||||
use std::net::Ipv4Addr;
|
||||
pub use tap::TapDevice;
|
||||
pub use tun::*;
|
||||
|
||||
/// Encode a string as a utf16 buffer
|
||||
fn encode_utf16(string: &str) -> Vec<u16> {
|
||||
use std::iter::once;
|
||||
string.encode_utf16().chain(once(0)).collect()
|
||||
}
|
||||
|
||||
/// Decode a string from a utf16 buffer
|
||||
fn decode_utf16(string: &[u16]) -> String {
|
||||
let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
|
||||
String::from_utf16_lossy(&string[..end])
|
||||
}
|
||||
|
||||
pub trait IFace {
|
||||
fn shutdown(&self) -> io::Result<()>;
|
||||
/// 获取接口索引
|
||||
fn get_index(&self) -> io::Result<u32>;
|
||||
/// 获取名称
|
||||
fn get_name(&self) -> io::Result<String>;
|
||||
/// 设置名称
|
||||
fn set_name(&self, new_name: &str) -> io::Result<()>;
|
||||
/// 设置ip
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()>;
|
||||
/// 设置路由
|
||||
fn add_route(&self, dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, metric: u16) -> io::Result<()>;
|
||||
/// 删除路由
|
||||
fn delete_route(&self, dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, ) -> io::Result<()>;
|
||||
/// 设置最大传输单元
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()>;
|
||||
/// 设置跃点
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()>;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
/// 设置网卡名称
|
||||
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
|
||||
let cmd = format!(" netsh interface set interface name={:?} newname={:?}", old_name, new_name);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000) //winapi-0.3.9/src/um/winbase.rs:283
|
||||
.arg("/C")
|
||||
.arg(&cmd)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::warn!("修改网卡名称失败:cmd={:?},out={:?}",cmd,out);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "修改网卡名称失败"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// 设置网卡ip
|
||||
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
|
||||
let set_address = format!(
|
||||
"netsh interface ip set address {} static {:?} {:?} ",
|
||||
index, address, netmask,
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_address)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}",set_address,out);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> {
|
||||
let set_mtu = format!(
|
||||
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
|
||||
index, mtu
|
||||
);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_mtu)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}",set_mtu,out);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置mtu失败: {:?}", out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
|
||||
let set_metric = format!("netsh interface ip set interface {} metric={}", index,metric);
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_metric)
|
||||
.output()?;
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}",set_metric,out);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置metric失败: {:?}", out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
/// 添加路由
|
||||
pub fn add_route(index: u32, dest: Ipv4Addr,
|
||||
netmask: Ipv4Addr,
|
||||
gateway: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
let set_route = format!(
|
||||
"route add {:?} mask {:?} {:?} metric {} if {}",
|
||||
dest, netmask, gateway, metric, index
|
||||
);
|
||||
// 执行添加路由命令
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(&set_route)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
log::error!("cmd={:?},out={:?}",set_route,out);
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 删除路由
|
||||
pub fn delete_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
if index == 0 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("网络接口索引错误: {:?}", index)));
|
||||
}
|
||||
let delete_route = format!(
|
||||
"route delete {:?} mask {:?} {:?} if {}",
|
||||
dest, netmask, gateway, index
|
||||
);
|
||||
// 删除路由
|
||||
let out = std::process::Command::new("cmd")
|
||||
.creation_flags(0x08000000)
|
||||
.arg("/C")
|
||||
.arg(delete_route)
|
||||
.output()
|
||||
.unwrap();
|
||||
if !out.status.success() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("删除路由失败: {:?}", out)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
use winapi::shared::ifdef::NET_LUID;
|
||||
use winapi::shared::minwindef::*;
|
||||
|
||||
use winapi::um::fileapi::*;
|
||||
use winapi::um::setupapi::*;
|
||||
use winapi::um::winnt::*;
|
||||
|
||||
use scopeguard::{guard, ScopeGuard};
|
||||
use winreg::RegKey;
|
||||
|
||||
use std::io;
|
||||
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
||||
|
||||
use crate::{decode_utf16, encode_utf16, ffi};
|
||||
|
||||
/// tap-windows hardware ID
|
||||
const HARDWARE_ID: &str = "tap0901";
|
||||
|
||||
winapi::DEFINE_GUID! {
|
||||
GUID_NETWORK_ADAPTER,
|
||||
0x4d36e972, 0xe325, 0x11ce,
|
||||
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
|
||||
}
|
||||
|
||||
/// Create a new interface and returns its NET_LUID
|
||||
pub fn create_interface() -> io::Result<NET_LUID> {
|
||||
let devinfo = ffi::create_device_info_list(&GUID_NETWORK_ADAPTER)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_device_info_list(devinfo);
|
||||
});
|
||||
|
||||
let class_name = ffi::class_name_from_guid(&GUID_NETWORK_ADAPTER)?;
|
||||
|
||||
let devinfo_data = ffi::create_device_info(
|
||||
devinfo,
|
||||
&class_name,
|
||||
&GUID_NETWORK_ADAPTER,
|
||||
&encode_utf16(""),
|
||||
DICD_GENERATE_ID,
|
||||
)?;
|
||||
|
||||
ffi::set_selected_device(devinfo, &devinfo_data)?;
|
||||
ffi::set_device_registry_property(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
SPDRP_HARDWAREID,
|
||||
&encode_utf16(HARDWARE_ID),
|
||||
)?;
|
||||
|
||||
ffi::build_driver_info_list(devinfo, &devinfo_data, SPDIT_COMPATDRIVER)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_driver_info_list(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
SPDIT_COMPATDRIVER,
|
||||
);
|
||||
});
|
||||
|
||||
let mut driver_version = 0;
|
||||
let mut member_index = 0;
|
||||
|
||||
while let Some(drvinfo_data) = ffi::enum_driver_info(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
SPDIT_COMPATDRIVER,
|
||||
member_index,
|
||||
) {
|
||||
member_index += 1;
|
||||
|
||||
let drvinfo_data = match drvinfo_data {
|
||||
Ok(drvinfo_data) => drvinfo_data,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if drvinfo_data.DriverVersion <= driver_version {
|
||||
continue;
|
||||
}
|
||||
|
||||
let drvinfo_detail = match ffi::get_driver_info_detail(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
&drvinfo_data,
|
||||
) {
|
||||
Ok(drvinfo_detail) => drvinfo_detail,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let is_compatible = drvinfo_detail
|
||||
.HardwareID
|
||||
.split(|b| *b == 0)
|
||||
.map(|id| decode_utf16(id))
|
||||
.any(|id| id.eq_ignore_ascii_case(HARDWARE_ID));
|
||||
|
||||
if !is_compatible {
|
||||
continue;
|
||||
}
|
||||
|
||||
match ffi::set_selected_driver(devinfo, &devinfo_data, &drvinfo_data) {
|
||||
Ok(_) => (),
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
driver_version = drvinfo_data.DriverVersion;
|
||||
}
|
||||
|
||||
if driver_version == 0 {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "No driver found"));
|
||||
}
|
||||
|
||||
let uninstaller = guard((), |_| {
|
||||
let _ = ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
|
||||
});
|
||||
|
||||
ffi::call_class_installer(devinfo, &devinfo_data, DIF_REGISTERDEVICE)?;
|
||||
|
||||
let _ = ffi::call_class_installer(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DIF_REGISTER_COINSTALLERS,
|
||||
);
|
||||
let _ = ffi::call_class_installer(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DIF_INSTALLINTERFACES,
|
||||
);
|
||||
|
||||
ffi::call_class_installer(devinfo, &devinfo_data, DIF_INSTALLDEVICE)?;
|
||||
|
||||
let key = ffi::open_dev_reg_key(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DICS_FLAG_GLOBAL,
|
||||
0,
|
||||
DIREG_DRV,
|
||||
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||
)?;
|
||||
|
||||
let key = RegKey::predef(key);
|
||||
|
||||
while let Err(_) = key.get_value::<DWORD, &str>("*IfType") {
|
||||
ffi::notify_change_key_value(
|
||||
key.raw_handle(),
|
||||
TRUE,
|
||||
REG_NOTIFY_CHANGE_NAME,
|
||||
2000,
|
||||
)?;
|
||||
}
|
||||
|
||||
while let Err(_) = key.get_value::<DWORD, &str>("NetLuidIndex") {
|
||||
ffi::notify_change_key_value(
|
||||
key.raw_handle(),
|
||||
TRUE,
|
||||
REG_NOTIFY_CHANGE_NAME,
|
||||
2000,
|
||||
)?;
|
||||
}
|
||||
|
||||
let if_type: DWORD = key.get_value("*IfType")?;
|
||||
let luid_index: DWORD = key.get_value("NetLuidIndex")?;
|
||||
|
||||
// Defuse the uninstaller
|
||||
ScopeGuard::into_inner(uninstaller);
|
||||
|
||||
let mut luid = NET_LUID { Value: 0 };
|
||||
|
||||
luid.set_IfType(if_type as _);
|
||||
luid.set_NetLuidIndex(luid_index as _);
|
||||
|
||||
Ok(luid)
|
||||
}
|
||||
|
||||
/// Check if the given interface exists and is a valid tap-windows device
|
||||
pub fn check_interface(luid: &NET_LUID) -> io::Result<()> {
|
||||
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_device_info_list(devinfo);
|
||||
});
|
||||
|
||||
let mut member_index = 0;
|
||||
|
||||
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index)
|
||||
{
|
||||
member_index += 1;
|
||||
|
||||
let devinfo_data = match devinfo_data {
|
||||
Ok(devinfo_data) => devinfo_data,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let hardware_id = match ffi::get_device_registry_property(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
SPDRP_HARDWAREID,
|
||||
) {
|
||||
Ok(hardware_id) => hardware_id,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let key = match ffi::open_dev_reg_key(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DICS_FLAG_GLOBAL,
|
||||
0,
|
||||
DIREG_DRV,
|
||||
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||
) {
|
||||
Ok(key) => RegKey::predef(key),
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let if_type: DWORD = match key.get_value("*IfType") {
|
||||
Ok(if_type) => if_type,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
|
||||
Ok(luid_index) => luid_index,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let mut luid2 = NET_LUID { Value: 0 };
|
||||
|
||||
luid2.set_IfType(if_type as _);
|
||||
luid2.set_NetLuidIndex(luid_index as _);
|
||||
|
||||
if luid.Value != luid2.Value {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found it!
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "TAP Device not found"))
|
||||
}
|
||||
|
||||
/// Deletes an existing interface
|
||||
pub fn delete_interface(luid: &NET_LUID) -> io::Result<()> {
|
||||
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
|
||||
|
||||
let _guard = guard((), |_| {
|
||||
let _ = ffi::destroy_device_info_list(devinfo);
|
||||
});
|
||||
|
||||
let mut member_index = 0;
|
||||
|
||||
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index)
|
||||
{
|
||||
member_index += 1;
|
||||
|
||||
let devinfo_data = match devinfo_data {
|
||||
Ok(devinfo_data) => devinfo_data,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let hardware_id = match ffi::get_device_registry_property(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
SPDRP_HARDWAREID,
|
||||
) {
|
||||
Ok(hardware_id) => hardware_id,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let key = match ffi::open_dev_reg_key(
|
||||
devinfo,
|
||||
&devinfo_data,
|
||||
DICS_FLAG_GLOBAL,
|
||||
0,
|
||||
DIREG_DRV,
|
||||
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||
) {
|
||||
Ok(key) => RegKey::predef(key),
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let if_type: DWORD = match key.get_value("*IfType") {
|
||||
Ok(if_type) => if_type,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
|
||||
Ok(luid_index) => luid_index,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let mut luid2 = NET_LUID { Value: 0 };
|
||||
|
||||
luid2.set_IfType(if_type as _);
|
||||
luid2.set_NetLuidIndex(luid_index as _);
|
||||
|
||||
if luid.Value != luid2.Value {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found it!
|
||||
return ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
|
||||
}
|
||||
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "TAP Device not found"))
|
||||
}
|
||||
|
||||
/// Open an handle to an interface
|
||||
pub fn open_interface(luid: &NET_LUID) -> io::Result<HANDLE> {
|
||||
let guid = ffi::luid_to_guid(luid)
|
||||
.and_then(|guid| ffi::string_from_guid(&guid))?;
|
||||
|
||||
let path = format!(r"\\.\Global\{}.tap", &decode_utf16(&guid));
|
||||
|
||||
ffi::create_file(
|
||||
&encode_utf16(&path),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_SYSTEM,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
use std::{io, time};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use winapi::shared::ifdef::NET_LUID;
|
||||
use winapi::um::winioctl::*;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
|
||||
|
||||
mod iface;
|
||||
|
||||
pub struct TapDevice {
|
||||
index: u32,
|
||||
luid: NET_LUID,
|
||||
handle: HANDLE,
|
||||
|
||||
}
|
||||
|
||||
unsafe impl Send for TapDevice {}
|
||||
|
||||
unsafe impl Sync for TapDevice {}
|
||||
|
||||
impl TapDevice {
|
||||
/// Retieve the mac of the interface
|
||||
pub fn get_mac(&self) -> io::Result<[u8; 6]> {
|
||||
let mut mac = [0; 6];
|
||||
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&(),
|
||||
&mut mac,
|
||||
)
|
||||
.map(|_| mac)
|
||||
}
|
||||
|
||||
/// Retrieve the version of the driver
|
||||
pub fn get_version(&self) -> io::Result<[u32; 3]> {
|
||||
let mut version = [0; 3];
|
||||
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&(),
|
||||
&mut version,
|
||||
)
|
||||
.map(|_| version)
|
||||
}
|
||||
|
||||
/// Retieve the mtu of the interface
|
||||
pub fn get_mtu(&self) -> io::Result<u32> {
|
||||
let mut mtu = 0;
|
||||
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&(),
|
||||
&mut mtu,
|
||||
)
|
||||
.map(|_| mtu)
|
||||
}
|
||||
|
||||
|
||||
/// Set the status of the interface, true for connected,
|
||||
/// false for disconnected.
|
||||
pub fn set_status(&self, status: bool) -> io::Result<()> {
|
||||
let status: u32 = if status { 1 } else { 0 };
|
||||
ffi::device_io_control(
|
||||
self.handle,
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
&status,
|
||||
&mut (),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TapDevice {
|
||||
pub fn create() -> io::Result<Self> {
|
||||
let luid = iface::create_interface()?;
|
||||
// Even after retrieving the luid, we might need to wait
|
||||
let start = time::Instant::now();
|
||||
let handle = loop {
|
||||
// If we surpassed 2 seconds just return
|
||||
let now = time::Instant::now();
|
||||
if now - start > time::Duration::from_secs(3) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::TimedOut,
|
||||
"Interface timed out",
|
||||
));
|
||||
}
|
||||
|
||||
match iface::open_interface(&luid) {
|
||||
Err(_) => {
|
||||
std::thread::yield_now();
|
||||
continue;
|
||||
}
|
||||
Ok(handle) => break handle,
|
||||
};
|
||||
};
|
||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||
Ok(Self { index, luid, handle })
|
||||
}
|
||||
|
||||
pub fn open(name: &str) -> io::Result<Self> {
|
||||
let name = encode_utf16(name);
|
||||
|
||||
let luid = ffi::alias_to_luid(&name)?;
|
||||
iface::check_interface(&luid)?;
|
||||
|
||||
let handle = iface::open_interface(&luid)?;
|
||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||
Ok(Self { index, luid, handle })
|
||||
}
|
||||
|
||||
pub fn delete(self) -> io::Result<()> {
|
||||
iface::delete_interface(&self.luid)
|
||||
}
|
||||
}
|
||||
|
||||
impl IFace for TapDevice {
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
self.set_status(false)
|
||||
}
|
||||
|
||||
fn get_index(&self) -> io::Result<u32> {
|
||||
Ok(self.index)
|
||||
}
|
||||
|
||||
fn get_name(&self) -> io::Result<String> {
|
||||
ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
|
||||
}
|
||||
|
||||
fn set_name(&self, new_name: &str) -> io::Result<()> {
|
||||
let name = self.get_name()?;
|
||||
netsh::set_interface_name(&name, new_name)
|
||||
}
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_ip(index, &address, &mask)
|
||||
}
|
||||
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
route::add_route(index, dest, netmask, gateway,metric)
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
route::delete_route(index, dest, netmask, gateway)
|
||||
}
|
||||
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_mtu(index, mtu)
|
||||
}
|
||||
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_metric(index, metric)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl TapDevice {
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
ffi::read_file(self.handle, buf).map(|res| res as _)
|
||||
}
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
ffi::write_file(self.handle, buf).map(|res| res as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TapDevice {
|
||||
fn drop(&mut self) {
|
||||
let _ = ffi::close_handle(self.handle);
|
||||
let _ = iface::delete_interface(&self.luid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use log::*;
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use widestring::U16CStr;
|
||||
use crate::tun::wintun_raw;
|
||||
|
||||
/// Sets the logger wintun will use when logging. Maps to the WintunSetLogger C function
|
||||
pub fn set_logger(win_tun: &wintun_raw::wintun, f: wintun_raw::WINTUN_LOGGER_CALLBACK) {
|
||||
unsafe { win_tun.WintunSetLogger(f) };
|
||||
}
|
||||
|
||||
pub fn reset_logger(win_tun: &wintun_raw::wintun) {
|
||||
set_logger(win_tun, None);
|
||||
}
|
||||
|
||||
static SET_LOGGER: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// The logger that is active by default. Logs messages to the log crate
|
||||
///
|
||||
/// # Safety
|
||||
/// `message` must be a valid pointer that points to an aligned null terminated UTF-16 string
|
||||
pub unsafe extern "C" fn default_logger(
|
||||
level: wintun_raw::WINTUN_LOGGER_LEVEL,
|
||||
_timestamp: wintun_raw::DWORD64,
|
||||
message: *const wintun_raw::WCHAR,
|
||||
) {
|
||||
//Cant wait for RFC 2585
|
||||
#[allow(unused_unsafe)]
|
||||
//Wintun will always give us a valid UTF16 null termineted string
|
||||
let msg = unsafe { U16CStr::from_ptr_str(message) };
|
||||
let utf8_msg = msg.to_string_lossy();
|
||||
match level {
|
||||
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO => info!("WinTun: {}", utf8_msg),
|
||||
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN => warn!("WinTun: {}", utf8_msg),
|
||||
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR => error!("WinTun: {}", utf8_msg),
|
||||
_ => error!("WinTun: {} (with invalid log level {})", utf8_msg, level),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_default_logger_if_unset(win_tun: &wintun_raw::wintun) {
|
||||
if SET_LOGGER
|
||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
set_logger(win_tun, Some(default_logger));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use winapi::um::{handleapi, synchapi, winbase, winnt};
|
||||
|
||||
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
|
||||
use rand::Rng;
|
||||
mod wintun_raw;
|
||||
mod log;
|
||||
pub mod packet;
|
||||
|
||||
/// The maximum size of wintun's internal ring buffer (in bytes)
|
||||
pub const MAX_RING_CAPACITY: u32 = 0x400_0000;
|
||||
|
||||
/// The minimum size of wintun's internal ring buffer (in bytes)
|
||||
pub const MIN_RING_CAPACITY: u32 = 0x2_0000;
|
||||
|
||||
/// Maximum pool name length including zero terminator
|
||||
pub const MAX_POOL: usize = 256;
|
||||
|
||||
|
||||
pub struct TunDevice {
|
||||
pub(crate) luid: u64,
|
||||
pub(crate) index: u32,
|
||||
/// The session handle given to us by WintunStartSession
|
||||
pub(crate) session: wintun_raw::WINTUN_SESSION_HANDLE,
|
||||
|
||||
/// Shared dll for required wintun driver functions
|
||||
pub(crate) win_tun: wintun_raw::wintun,
|
||||
|
||||
/// Windows event handle that is signaled by the wintun driver when data becomes available to
|
||||
/// read
|
||||
pub(crate) read_event: winnt::HANDLE,
|
||||
|
||||
/// Windows event handle that is signaled when [`TunSession::shutdown`] is called force blocking
|
||||
/// readers to exit
|
||||
pub(crate) shutdown_event: winnt::HANDLE,
|
||||
|
||||
/// The adapter that owns this session
|
||||
pub(crate) adapter: wintun_raw::WINTUN_ADAPTER_HANDLE,
|
||||
|
||||
}
|
||||
|
||||
unsafe impl Send for TunDevice {}
|
||||
|
||||
unsafe impl Sync for TunDevice {}
|
||||
|
||||
impl TunDevice {
|
||||
pub unsafe fn create<L>(library: L, pool: &str, name: &str) -> io::Result<Self>
|
||||
where L: Into<libloading::Library>, {
|
||||
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||
Ok(win_tun) => { win_tun }
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("library error {:?} ", e)));
|
||||
}
|
||||
};
|
||||
let pool_utf16 = encode_utf16(pool);
|
||||
if pool_utf16.len() > MAX_POOL {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("长度大于{}:{:?}", MAX_POOL, pool)));
|
||||
}
|
||||
let name_utf16 = encode_utf16(name);
|
||||
if name_utf16.len() > MAX_POOL {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("长度大于{}:{:?}", MAX_POOL, pool)));
|
||||
}
|
||||
let mut guid_bytes: [u8; 16] = [0u8; 16];
|
||||
rand::thread_rng().fill(&mut guid_bytes);
|
||||
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_ptr = &guid_struct as *const wintun_raw::GUID;
|
||||
|
||||
log::set_default_logger_if_unset(&win_tun);
|
||||
|
||||
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
|
||||
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
|
||||
//applies for all Wintun* functions below
|
||||
let adapter = win_tun.WintunCreateAdapter(pool_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
|
||||
if adapter.is_null() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Failed to crate adapter"));
|
||||
}
|
||||
Self::init(win_tun, adapter)
|
||||
}
|
||||
pub unsafe fn init(win_tun: wintun_raw::wintun, adapter: wintun_raw::WINTUN_ADAPTER_HANDLE) -> io::Result<Self> {
|
||||
// 开启session
|
||||
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
||||
if session.is_null() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "WintunStartSession failed"));
|
||||
}
|
||||
//SAFETY: We follow the contract required by CreateEventA. See MSDN
|
||||
//(the pointers are allowed to be null, and 0 is okay for the others)
|
||||
let shutdown_event = synchapi::CreateEventA(std::ptr::null_mut(),
|
||||
0, 0, std::ptr::null_mut());
|
||||
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
|
||||
let mut luid: wintun_raw::NET_LUID = std::mem::zeroed();
|
||||
win_tun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID);
|
||||
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
|
||||
Ok(TunDevice {
|
||||
luid: std::mem::transmute(luid),
|
||||
index,
|
||||
session,
|
||||
win_tun,
|
||||
read_event,
|
||||
shutdown_event,
|
||||
adapter,
|
||||
})
|
||||
}
|
||||
pub unsafe fn delete_for_name<L>(library: L, name: &str) -> io::Result<()>
|
||||
where L: Into<libloading::Library>, {
|
||||
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||
Ok(win_tun) => win_tun,
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("library error {:?} ", e)));
|
||||
}
|
||||
};
|
||||
log::set_default_logger_if_unset(&win_tun);
|
||||
let name_utf16 = encode_utf16(name);
|
||||
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
|
||||
if adapter.is_null() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Failed to open adapter"));
|
||||
}
|
||||
win_tun.WintunCloseAdapter(adapter);
|
||||
win_tun.WintunDeleteDriver();
|
||||
Ok(())
|
||||
}
|
||||
pub fn delete(self) -> io::Result<()> {
|
||||
drop(self);
|
||||
Ok(())
|
||||
}
|
||||
pub fn version(&self) -> io::Result<Version> {
|
||||
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
|
||||
if version == 0 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "WintunGetRunningDriverVersion"));
|
||||
} else {
|
||||
Ok(Version {
|
||||
major: ((version >> 16) & 0xFF) as u16,
|
||||
minor: (version & 0xFF) as u16,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Version {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
}
|
||||
|
||||
// impl TunDevice {
|
||||
// fn get_adapter_luid(&self) -> u64 {
|
||||
// let mut luid: wintun_raw::NET_LUID = unsafe { std::mem::zeroed() };
|
||||
// unsafe { self.win_tun.WintunGetAdapterLUID(self.adapter, &mut luid as *mut wintun_raw::NET_LUID) };
|
||||
// unsafe { std::mem::transmute(luid) }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
impl IFace for TunDevice {
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
let _ = unsafe { synchapi::SetEvent(self.shutdown_event) };
|
||||
let _ = unsafe { handleapi::CloseHandle(self.shutdown_event) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_index(&self) -> io::Result<u32> {
|
||||
Ok(self.index)
|
||||
}
|
||||
|
||||
fn get_name(&self) -> io::Result<String> {
|
||||
let luid = self.luid;
|
||||
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| {
|
||||
decode_utf16(&name)
|
||||
})
|
||||
}
|
||||
|
||||
fn set_name(&self, new_name: &str) -> io::Result<()> {
|
||||
let name = self.get_name()?;
|
||||
netsh::set_interface_name(&name, new_name)
|
||||
}
|
||||
|
||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()>{
|
||||
netsh::set_interface_ip(self.get_index()?, &address, &mask)
|
||||
}
|
||||
|
||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr, metric: u16) -> io::Result<()> {
|
||||
route::add_route(self.get_index()?, dest, netmask, gateway, metric)
|
||||
}
|
||||
|
||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||
route::delete_route(self.get_index()?, dest, netmask, gateway)
|
||||
}
|
||||
|
||||
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||
netsh::set_interface_mtu(self.get_index()?, mtu)
|
||||
}
|
||||
|
||||
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||
let index = self.get_index()?;
|
||||
netsh::set_interface_metric(index, metric)
|
||||
}
|
||||
}
|
||||
|
||||
impl TunDevice {
|
||||
pub fn try_receive(&self) -> io::Result<Option<packet::TunPacket>> {
|
||||
let mut size = 0u32;
|
||||
|
||||
let bytes_ptr = unsafe {
|
||||
self.win_tun
|
||||
.WintunReceivePacket(self.session, &mut size as *mut u32)
|
||||
};
|
||||
|
||||
debug_assert!(size <= u16::MAX as u32);
|
||||
if bytes_ptr.is_null() {
|
||||
//Wintun returns ERROR_NO_MORE_ITEMS instead of blocking if packets are not available
|
||||
let last_error = unsafe { winapi::um::errhandlingapi::GetLastError() };
|
||||
if last_error == winapi::shared::winerror::ERROR_NO_MORE_ITEMS {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "try_receive failed"))
|
||||
}
|
||||
} else {
|
||||
Ok(Some(packet::TunPacket {
|
||||
kind: packet::Kind::ReceivePacket,
|
||||
size: size as usize,
|
||||
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
|
||||
//must be less than isize::MAX because bytes is a u16
|
||||
bytes_ptr,
|
||||
tun_device: Some(&self),
|
||||
}))
|
||||
}
|
||||
}
|
||||
pub fn receive_blocking(&self) -> io::Result<packet::TunPacket> {
|
||||
loop {
|
||||
//Try 5 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 _ in 0..5 {
|
||||
match self.try_receive()? {
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
Some(packet) => {
|
||||
return Ok(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Wait on both the read handle and the shutdown handle so that we stop when requested
|
||||
let handles = [self.read_event, self.shutdown_event];
|
||||
let result = unsafe {
|
||||
//SAFETY: We abide by the requirements of WaitForMultipleObjects, handles is a
|
||||
//pointer to valid, aligned, stack memory
|
||||
synchapi::WaitForMultipleObjects(
|
||||
2,
|
||||
&handles as *const winnt::HANDLE,
|
||||
0,
|
||||
winbase::INFINITE,
|
||||
)
|
||||
};
|
||||
match result {
|
||||
winbase::WAIT_FAILED => return Err(io::Error::new(io::ErrorKind::Other, "WAIT_FAILED")),
|
||||
_ => {
|
||||
if result == winbase::WAIT_OBJECT_0 {
|
||||
//We have data!
|
||||
continue;
|
||||
} else if result == winbase::WAIT_OBJECT_0 + 1 {
|
||||
//Shutdown event triggered
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Shutdown event triggered"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TunDevice {
|
||||
pub fn allocate_send_packet(&self, size: u16) -> io::Result<packet::TunPacket> {
|
||||
let bytes_ptr = unsafe {
|
||||
self.win_tun.WintunAllocateSendPacket(self.session, size as u32)
|
||||
};
|
||||
if bytes_ptr.is_null() {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "allocate_send_packet failed"))
|
||||
} else {
|
||||
Ok(packet::TunPacket {
|
||||
kind: packet::Kind::SendPacketPending,
|
||||
size: size as usize,
|
||||
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
|
||||
//must be less than isize::MAX because bytes is a u16
|
||||
bytes_ptr,
|
||||
tun_device: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
pub fn send_packet(&self, mut packet: packet::TunPacket) {
|
||||
assert!(matches!(packet.kind, packet::Kind::SendPacketPending));
|
||||
|
||||
unsafe {
|
||||
self.win_tun
|
||||
.WintunSendPacket(self.session, packet.bytes_ptr)
|
||||
};
|
||||
//Mark the packet at sent
|
||||
packet.kind = packet::Kind::SendPacketSent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Drop for TunDevice {
|
||||
fn drop(&mut self) {
|
||||
//Close adapter on drop
|
||||
//This is why we need an Arc of wintun
|
||||
unsafe {
|
||||
self.win_tun.WintunCloseAdapter(self.adapter);
|
||||
self.win_tun.WintunDeleteDriver()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
use crate::TunDevice;
|
||||
|
||||
pub(crate) enum Kind {
|
||||
SendPacketPending,
|
||||
//Send packet type, but not sent yet
|
||||
SendPacketSent,
|
||||
//Send packet type - sent
|
||||
ReceivePacket,
|
||||
}
|
||||
|
||||
/// Represents a wintun packet
|
||||
pub struct TunPacket<'a> {
|
||||
pub(crate) kind: Kind,
|
||||
pub(crate) size:usize,
|
||||
pub(crate) bytes_ptr: *const u8,
|
||||
|
||||
//Share ownership of session to prevent the session from being dropped before packets that
|
||||
//belong to it
|
||||
pub(crate) tun_device: Option<&'a TunDevice>,
|
||||
}
|
||||
|
||||
impl <'a>TunPacket<'a> {
|
||||
/// Returns the bytes this packet holds as &mut.
|
||||
/// The lifetime of the bytes is tied to the lifetime of this packet.
|
||||
pub fn bytes_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { std::slice::from_raw_parts_mut(self.bytes_ptr as *mut u8, self.size) }
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the bytes this packet holds.
|
||||
/// The lifetime of the bytes is tied to the lifetime of this packet.
|
||||
pub fn bytes(&self) -> &[u8] {
|
||||
unsafe { std::slice::from_raw_parts(self.bytes_ptr,self.size) }
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a>Drop for TunPacket<'a> {
|
||||
fn drop(&mut self) {
|
||||
match self.kind {
|
||||
Kind::ReceivePacket => {
|
||||
unsafe {
|
||||
//SAFETY:
|
||||
//
|
||||
// 1. We share ownership of the session therefore it hasn't been dropped yet
|
||||
// 2. Bytes is valid because each packet holds exclusive access to a region of the
|
||||
// ring buffer that the wintun session owns. We return that region of
|
||||
// memory back to wintun here
|
||||
let tun_device = self.tun_device.unwrap();
|
||||
tun_device.win_tun
|
||||
.WintunReleaseReceivePacket(tun_device.session, self.bytes_ptr)
|
||||
};
|
||||
}
|
||||
Kind::SendPacketPending => {
|
||||
//If someone allocates a packet with session.allocate_send_packet() and then it is
|
||||
//dropped without being sent, this will hold up the send queue because wintun expects
|
||||
//that every allocated packet is sent
|
||||
panic!("Packet was never sent!");
|
||||
}
|
||||
Kind::SendPacketSent => {
|
||||
//Nop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
/* automatically generated by rust-bindgen 0.59.1 */
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct __BindgenBitfieldUnit<Storage> {
|
||||
storage: Storage,
|
||||
}
|
||||
impl<Storage> __BindgenBitfieldUnit<Storage> {
|
||||
#[inline]
|
||||
pub const fn new(storage: Storage) -> Self {
|
||||
Self { storage }
|
||||
}
|
||||
}
|
||||
impl<Storage> __BindgenBitfieldUnit<Storage>
|
||||
where
|
||||
Storage: AsRef<[u8]> + AsMut<[u8]>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn get_bit(&self, index: usize) -> bool {
|
||||
debug_assert!(index / 8 < self.storage.as_ref().len());
|
||||
let byte_index = index / 8;
|
||||
let byte = self.storage.as_ref()[byte_index];
|
||||
let bit_index = if cfg!(target_endian = "big") {
|
||||
7 - (index % 8)
|
||||
} else {
|
||||
index % 8
|
||||
};
|
||||
let mask = 1 << bit_index;
|
||||
byte & mask == mask
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_bit(&mut self, index: usize, val: bool) {
|
||||
debug_assert!(index / 8 < self.storage.as_ref().len());
|
||||
let byte_index = index / 8;
|
||||
let byte = &mut self.storage.as_mut()[byte_index];
|
||||
let bit_index = if cfg!(target_endian = "big") {
|
||||
7 - (index % 8)
|
||||
} else {
|
||||
index % 8
|
||||
};
|
||||
let mask = 1 << bit_index;
|
||||
if val {
|
||||
*byte |= mask;
|
||||
} else {
|
||||
*byte &= !mask;
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
|
||||
debug_assert!(bit_width <= 64);
|
||||
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
|
||||
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
|
||||
let mut val = 0;
|
||||
for i in 0..(bit_width as usize) {
|
||||
if self.get_bit(i + bit_offset) {
|
||||
let index = if cfg!(target_endian = "big") {
|
||||
bit_width as usize - 1 - i
|
||||
} else {
|
||||
i
|
||||
};
|
||||
val |= 1 << index;
|
||||
}
|
||||
}
|
||||
val
|
||||
}
|
||||
#[inline]
|
||||
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
|
||||
debug_assert!(bit_width <= 64);
|
||||
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
|
||||
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
|
||||
for i in 0..(bit_width as usize) {
|
||||
let mask = 1 << i;
|
||||
let val_bit_is_set = val & mask == mask;
|
||||
let index = if cfg!(target_endian = "big") {
|
||||
bit_width as usize - 1 - i
|
||||
} else {
|
||||
i
|
||||
};
|
||||
self.set_bit(index + bit_offset, val_bit_is_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type wchar_t = ::std::os::raw::c_ushort;
|
||||
pub type DWORD = ::std::os::raw::c_ulong;
|
||||
pub type BOOL = ::std::os::raw::c_int;
|
||||
pub type BYTE = ::std::os::raw::c_uchar;
|
||||
pub type ULONG64 = ::std::os::raw::c_ulonglong;
|
||||
pub type DWORD64 = ::std::os::raw::c_ulonglong;
|
||||
pub type WCHAR = wchar_t;
|
||||
pub type LPCWSTR = *const WCHAR;
|
||||
pub type HANDLE = *mut ::std::os::raw::c_void;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _GUID {
|
||||
pub Data1: ::std::os::raw::c_ulong,
|
||||
pub Data2: ::std::os::raw::c_ushort,
|
||||
pub Data3: ::std::os::raw::c_ushort,
|
||||
pub Data4: [::std::os::raw::c_uchar; 8usize],
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout__GUID() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<_GUID>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(_GUID))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<_GUID>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(_GUID))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<_GUID>())).Data1 as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(_GUID),
|
||||
"::",
|
||||
stringify!(Data1)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<_GUID>())).Data2 as *const _ as usize },
|
||||
4usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(_GUID),
|
||||
"::",
|
||||
stringify!(Data2)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<_GUID>())).Data3 as *const _ as usize },
|
||||
6usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(_GUID),
|
||||
"::",
|
||||
stringify!(Data3)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<_GUID>())).Data4 as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(_GUID),
|
||||
"::",
|
||||
stringify!(Data4)
|
||||
)
|
||||
);
|
||||
}
|
||||
pub type GUID = _GUID;
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union _NET_LUID_LH {
|
||||
pub Value: ULONG64,
|
||||
pub Info: _NET_LUID_LH__bindgen_ty_1,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[repr(align(8))]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _NET_LUID_LH__bindgen_ty_1 {
|
||||
pub _bitfield_align_1: [u32; 0],
|
||||
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout__NET_LUID_LH__bindgen_ty_1() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<_NET_LUID_LH__bindgen_ty_1>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(_NET_LUID_LH__bindgen_ty_1))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<_NET_LUID_LH__bindgen_ty_1>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(_NET_LUID_LH__bindgen_ty_1))
|
||||
);
|
||||
}
|
||||
impl _NET_LUID_LH__bindgen_ty_1 {
|
||||
#[inline]
|
||||
pub fn Reserved(&self) -> ULONG64 {
|
||||
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 24u8) as u64) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_Reserved(&mut self, val: ULONG64) {
|
||||
unsafe {
|
||||
let val: u64 = ::std::mem::transmute(val);
|
||||
self._bitfield_1.set(0usize, 24u8, val as u64)
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn NetLuidIndex(&self) -> ULONG64 {
|
||||
unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 24u8) as u64) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_NetLuidIndex(&mut self, val: ULONG64) {
|
||||
unsafe {
|
||||
let val: u64 = ::std::mem::transmute(val);
|
||||
self._bitfield_1.set(24usize, 24u8, val as u64)
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn IfType(&self) -> ULONG64 {
|
||||
unsafe { ::std::mem::transmute(self._bitfield_1.get(48usize, 16u8) as u64) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_IfType(&mut self, val: ULONG64) {
|
||||
unsafe {
|
||||
let val: u64 = ::std::mem::transmute(val);
|
||||
self._bitfield_1.set(48usize, 16u8, val as u64)
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn new_bitfield_1(
|
||||
Reserved: ULONG64,
|
||||
NetLuidIndex: ULONG64,
|
||||
IfType: ULONG64,
|
||||
) -> __BindgenBitfieldUnit<[u8; 8usize]> {
|
||||
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 8usize]> = Default::default();
|
||||
__bindgen_bitfield_unit.set(0usize, 24u8, {
|
||||
let Reserved: u64 = unsafe { ::std::mem::transmute(Reserved) };
|
||||
Reserved as u64
|
||||
});
|
||||
__bindgen_bitfield_unit.set(24usize, 24u8, {
|
||||
let NetLuidIndex: u64 = unsafe { ::std::mem::transmute(NetLuidIndex) };
|
||||
NetLuidIndex as u64
|
||||
});
|
||||
__bindgen_bitfield_unit.set(48usize, 16u8, {
|
||||
let IfType: u64 = unsafe { ::std::mem::transmute(IfType) };
|
||||
IfType as u64
|
||||
});
|
||||
__bindgen_bitfield_unit
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout__NET_LUID_LH() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<_NET_LUID_LH>(),
|
||||
8usize,
|
||||
concat!("Size of: ", stringify!(_NET_LUID_LH))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<_NET_LUID_LH>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(_NET_LUID_LH))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Value as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(_NET_LUID_LH),
|
||||
"::",
|
||||
stringify!(Value)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Info as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(_NET_LUID_LH),
|
||||
"::",
|
||||
stringify!(Info)
|
||||
)
|
||||
);
|
||||
}
|
||||
pub type NET_LUID_LH = _NET_LUID_LH;
|
||||
pub type NET_LUID = NET_LUID_LH;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _WINTUN_ADAPTER {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
#[doc = " A handle representing Wintun adapter"]
|
||||
pub type WINTUN_ADAPTER_HANDLE = *mut _WINTUN_ADAPTER;
|
||||
#[doc = "< Informational"]
|
||||
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO: WINTUN_LOGGER_LEVEL = 0;
|
||||
#[doc = "< Warning"]
|
||||
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN: WINTUN_LOGGER_LEVEL = 1;
|
||||
#[doc = "< Error"]
|
||||
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR: WINTUN_LOGGER_LEVEL = 2;
|
||||
#[doc = " Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK."]
|
||||
pub type WINTUN_LOGGER_LEVEL = ::std::os::raw::c_int;
|
||||
#[doc = " Called by internal logger to report diagnostic messages"]
|
||||
#[doc = ""]
|
||||
#[doc = " @param Level Message level."]
|
||||
#[doc = ""]
|
||||
#[doc = " @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC."]
|
||||
#[doc = ""]
|
||||
#[doc = " @param Message Message text."]
|
||||
pub type WINTUN_LOGGER_CALLBACK = ::std::option::Option<
|
||||
unsafe extern "C" fn(Level: WINTUN_LOGGER_LEVEL, Timestamp: DWORD64, Message: LPCWSTR),
|
||||
>;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct _TUN_SESSION {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
#[doc = " A handle representing Wintun session"]
|
||||
pub type WINTUN_SESSION_HANDLE = *mut _TUN_SESSION;
|
||||
extern crate libloading;
|
||||
pub struct wintun {
|
||||
__library: ::libloading::Library,
|
||||
pub WintunCreateAdapter: unsafe extern "C" fn(
|
||||
arg1: LPCWSTR,
|
||||
arg2: LPCWSTR,
|
||||
arg3: *const GUID,
|
||||
) -> WINTUN_ADAPTER_HANDLE,
|
||||
pub WintunCloseAdapter: unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE),
|
||||
pub WintunOpenAdapter: unsafe extern "C" fn(arg1: LPCWSTR) -> WINTUN_ADAPTER_HANDLE,
|
||||
pub WintunGetAdapterLUID:
|
||||
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: *mut NET_LUID),
|
||||
pub WintunGetRunningDriverVersion: unsafe extern "C" fn() -> DWORD,
|
||||
pub WintunDeleteDriver: unsafe extern "C" fn() -> BOOL,
|
||||
pub WintunSetLogger: unsafe extern "C" fn(arg1: WINTUN_LOGGER_CALLBACK),
|
||||
pub WintunStartSession:
|
||||
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: DWORD) -> WINTUN_SESSION_HANDLE,
|
||||
pub WintunEndSession: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE),
|
||||
pub WintunGetReadWaitEvent: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE) -> HANDLE,
|
||||
pub WintunReceivePacket:
|
||||
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *mut DWORD) -> *mut BYTE,
|
||||
pub WintunReleaseReceivePacket:
|
||||
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
|
||||
pub WintunAllocateSendPacket:
|
||||
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: DWORD) -> *mut BYTE,
|
||||
pub WintunSendPacket: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
|
||||
}
|
||||
impl wintun {
|
||||
pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
|
||||
where
|
||||
P: AsRef<::std::ffi::OsStr>,
|
||||
{
|
||||
let library = ::libloading::Library::new(path)?;
|
||||
Self::from_library(library)
|
||||
}
|
||||
pub unsafe fn from_library<L>(library: L) -> Result<Self, ::libloading::Error>
|
||||
where
|
||||
L: Into<::libloading::Library>,
|
||||
{
|
||||
let __library = library.into();
|
||||
let WintunCreateAdapter = __library.get(b"WintunCreateAdapter\0").map(|sym| *sym)?;
|
||||
let WintunCloseAdapter = __library.get(b"WintunCloseAdapter\0").map(|sym| *sym)?;
|
||||
let WintunOpenAdapter = __library.get(b"WintunOpenAdapter\0").map(|sym| *sym)?;
|
||||
let WintunGetAdapterLUID = __library.get(b"WintunGetAdapterLUID\0").map(|sym| *sym)?;
|
||||
let WintunGetRunningDriverVersion = __library
|
||||
.get(b"WintunGetRunningDriverVersion\0")
|
||||
.map(|sym| *sym)?;
|
||||
let WintunDeleteDriver = __library.get(b"WintunDeleteDriver\0").map(|sym| *sym)?;
|
||||
let WintunSetLogger = __library.get(b"WintunSetLogger\0").map(|sym| *sym)?;
|
||||
let WintunStartSession = __library.get(b"WintunStartSession\0").map(|sym| *sym)?;
|
||||
let WintunEndSession = __library.get(b"WintunEndSession\0").map(|sym| *sym)?;
|
||||
let WintunGetReadWaitEvent = __library.get(b"WintunGetReadWaitEvent\0").map(|sym| *sym)?;
|
||||
let WintunReceivePacket = __library.get(b"WintunReceivePacket\0").map(|sym| *sym)?;
|
||||
let WintunReleaseReceivePacket = __library
|
||||
.get(b"WintunReleaseReceivePacket\0")
|
||||
.map(|sym| *sym)?;
|
||||
let WintunAllocateSendPacket = __library
|
||||
.get(b"WintunAllocateSendPacket\0")
|
||||
.map(|sym| *sym)?;
|
||||
let WintunSendPacket = __library.get(b"WintunSendPacket\0").map(|sym| *sym)?;
|
||||
Ok(wintun {
|
||||
__library,
|
||||
WintunCreateAdapter,
|
||||
WintunCloseAdapter,
|
||||
WintunOpenAdapter,
|
||||
WintunGetAdapterLUID,
|
||||
WintunGetRunningDriverVersion,
|
||||
WintunDeleteDriver,
|
||||
WintunSetLogger,
|
||||
WintunStartSession,
|
||||
WintunEndSession,
|
||||
WintunGetReadWaitEvent,
|
||||
WintunReceivePacket,
|
||||
WintunReleaseReceivePacket,
|
||||
WintunAllocateSendPacket,
|
||||
WintunSendPacket,
|
||||
})
|
||||
}
|
||||
pub unsafe fn WintunCreateAdapter(
|
||||
&self,
|
||||
arg1: LPCWSTR,
|
||||
arg2: LPCWSTR,
|
||||
arg3: *const GUID,
|
||||
) -> WINTUN_ADAPTER_HANDLE {
|
||||
(self.WintunCreateAdapter)(arg1, arg2, arg3)
|
||||
}
|
||||
pub unsafe fn WintunCloseAdapter(&self, arg1: WINTUN_ADAPTER_HANDLE) -> () {
|
||||
(self.WintunCloseAdapter)(arg1)
|
||||
}
|
||||
pub unsafe fn WintunOpenAdapter(&self, arg1: LPCWSTR) -> WINTUN_ADAPTER_HANDLE {
|
||||
(self.WintunOpenAdapter)(arg1)
|
||||
}
|
||||
pub unsafe fn WintunGetAdapterLUID(
|
||||
&self,
|
||||
arg1: WINTUN_ADAPTER_HANDLE,
|
||||
arg2: *mut NET_LUID,
|
||||
) -> () {
|
||||
(self.WintunGetAdapterLUID)(arg1, arg2)
|
||||
}
|
||||
pub unsafe fn WintunGetRunningDriverVersion(&self) -> DWORD {
|
||||
(self.WintunGetRunningDriverVersion)()
|
||||
}
|
||||
pub unsafe fn WintunDeleteDriver(&self) -> BOOL {
|
||||
(self.WintunDeleteDriver)()
|
||||
}
|
||||
pub unsafe fn WintunSetLogger(&self, arg1: WINTUN_LOGGER_CALLBACK) -> () {
|
||||
(self.WintunSetLogger)(arg1)
|
||||
}
|
||||
pub unsafe fn WintunStartSession(
|
||||
&self,
|
||||
arg1: WINTUN_ADAPTER_HANDLE,
|
||||
arg2: DWORD,
|
||||
) -> WINTUN_SESSION_HANDLE {
|
||||
(self.WintunStartSession)(arg1, arg2)
|
||||
}
|
||||
pub unsafe fn WintunEndSession(&self, arg1: WINTUN_SESSION_HANDLE) -> () {
|
||||
(self.WintunEndSession)(arg1)
|
||||
}
|
||||
pub unsafe fn WintunGetReadWaitEvent(&self, arg1: WINTUN_SESSION_HANDLE) -> HANDLE {
|
||||
(self.WintunGetReadWaitEvent)(arg1)
|
||||
}
|
||||
pub unsafe fn WintunReceivePacket(
|
||||
&self,
|
||||
arg1: WINTUN_SESSION_HANDLE,
|
||||
arg2: *mut DWORD,
|
||||
) -> *mut BYTE {
|
||||
(self.WintunReceivePacket)(arg1, arg2)
|
||||
}
|
||||
pub unsafe fn WintunReleaseReceivePacket(
|
||||
&self,
|
||||
arg1: WINTUN_SESSION_HANDLE,
|
||||
arg2: *const BYTE,
|
||||
) -> () {
|
||||
(self.WintunReleaseReceivePacket)(arg1, arg2)
|
||||
}
|
||||
pub unsafe fn WintunAllocateSendPacket(
|
||||
&self,
|
||||
arg1: WINTUN_SESSION_HANDLE,
|
||||
arg2: DWORD,
|
||||
) -> *mut BYTE {
|
||||
(self.WintunAllocateSendPacket)(arg1, arg2)
|
||||
}
|
||||
pub unsafe fn WintunSendPacket(&self, arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE) -> () {
|
||||
(self.WintunSendPacket)(arg1, arg2)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user