Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71da72da34 | ||
|
|
c6ef2031fa | ||
|
|
a82933a7a8 | ||
|
|
76444ef17d | ||
|
|
fde33380be | ||
|
|
eedb6684a5 | ||
|
|
a335a5bcdf | ||
|
|
4a347d853e | ||
|
|
79f55fe7fd | ||
|
|
affe8fb719 | ||
|
|
22eee048d0 | ||
|
|
2b2a550a98 | ||
|
|
14427ce437 | ||
|
|
39c170892e | ||
|
|
b82276e6fa | ||
|
|
154e8ef09a | ||
|
|
97a2f7c306 | ||
|
|
8d39d6045a | ||
|
|
04b60773b9 | ||
|
|
774a80dc46 | ||
|
|
1cba257531 | ||
|
|
16cc2abe7a | ||
|
|
595a49ee3f | ||
|
|
f894f62eb2 | ||
|
|
a98d6a7594 | ||
|
|
9674dfa5dc | ||
|
|
00068cdcfd | ||
|
|
846f128689 | ||
|
|
2225edeb2e | ||
|
|
ef48007922 | ||
|
|
1d5257363c | ||
|
|
0238d1ab7e | ||
|
|
ffbb85dfff | ||
|
|
563aca39aa | ||
|
|
274f4df43a | ||
|
|
1fae7c9979 | ||
|
|
46b37c0753 | ||
|
|
f737f591b6 | ||
|
|
ebf8337ad7 | ||
|
|
e2d8a462a2 | ||
|
|
b09cd690f0 | ||
|
|
76bd79d97a | ||
|
|
c0d8645833 | ||
|
|
501a9e8198 | ||
|
|
8aa4736b01 | ||
|
|
d5e10a8210 | ||
|
|
1165ee52c7 | ||
|
|
8a66bbe1af | ||
|
|
c91d8a2734 | ||
|
|
09a315a0f1 | ||
|
|
2979f2ef6f | ||
|
|
8225cb7877 | ||
|
|
129ca1ec85 | ||
|
|
96b67c6162 | ||
|
|
ce02b30b2b | ||
|
|
2fbdfe920e | ||
|
|
7901407d69 | ||
|
|
e6cfdec9c6 | ||
|
|
7e0de2c4e6 | ||
|
|
803af55246 | ||
|
|
8e1a8fa7f0 | ||
|
|
fc6bf407c4 | ||
|
|
dc4e472f20 | ||
|
|
afff49e61a | ||
|
|
0f9ac2ac87 | ||
|
|
cce23b9661 | ||
|
|
4347ed68c3 | ||
|
|
64d68c8a84 | ||
|
|
210b7c959e | ||
|
|
e8322adbcc | ||
|
|
e523b02b58 | ||
|
|
13df028cd9 | ||
|
|
4550bea063 | ||
|
|
be8d4cbb8b | ||
|
|
ace0268a8c | ||
|
|
56fd0d7a4f | ||
|
|
91ee751b07 | ||
|
|
fa9903ace1 | ||
|
|
c2854352df | ||
|
|
b3472fb5b3 | ||
|
|
e373c9ee16 | ||
|
|
13b7b1761d | ||
|
|
352f322f61 | ||
|
|
be966c4f83 | ||
|
|
b8cbf2cdac | ||
|
|
05cf0e1a6f | ||
|
|
f90ef96a5d | ||
|
|
81c6c8c1fc | ||
|
|
7ebdffcdd3 | ||
|
|
1abe33cb16 | ||
|
|
965cbfbb7e | ||
|
|
aa332b4f4d | ||
|
|
14ee9c4632 | ||
|
|
ddfa89167d | ||
|
|
1f9ed7b314 | ||
|
|
dc45602661 | ||
|
|
27c0f389ee | ||
|
|
59d6bfd957 | ||
|
|
31b8661b7d | ||
|
|
8ae20497c6 | ||
|
|
a70b4f30b5 | ||
|
|
df4795c9c4 | ||
|
|
c21a73f950 | ||
|
|
29cd111a49 | ||
|
|
367a56d346 | ||
|
|
d81ac6368e | ||
|
|
a228b62d23 | ||
|
|
995ff9b059 | ||
|
|
7dc78cc170 | ||
|
|
7e218355f2 | ||
|
|
98c394c993 | ||
|
|
31b06cd713 | ||
|
|
d7266926d8 | ||
|
|
1df5a1cfb1 | ||
|
|
8658bd3601 | ||
|
|
17d1ad3716 | ||
|
|
728598ba8e | ||
|
|
218483f431 | ||
|
|
1f80e06d9d | ||
|
|
5e56064ec6 | ||
|
|
31f0213fc5 | ||
|
|
54b1fef164 | ||
|
|
7c18df0a6f | ||
|
|
916fd8254b | ||
|
|
9e249862dc | ||
|
|
3773c09f57 | ||
|
|
6798c652f9 | ||
|
|
382d5b61ba | ||
|
|
ac162eba66 | ||
|
|
05a60b3cb7 | ||
|
|
7f210e9319 | ||
|
|
481c00629a | ||
|
|
bf55ec9512 | ||
|
|
073fa6ac6b | ||
|
|
51315efb52 | ||
|
|
30cbf39e7f | ||
|
|
2973d88df3 | ||
|
|
8b2d7293fe | ||
|
|
215d9aa362 | ||
|
|
c3f27e8727 | ||
|
|
755339189d | ||
|
|
71cf0aa66d | ||
|
|
d695efd787 | ||
|
|
66129c2a24 | ||
|
|
0bc7115102 | ||
|
|
dca33a3ec1 | ||
|
|
9acbae2554 | ||
|
|
ccfff7b1f6 | ||
|
|
39ae4c5dd6 | ||
|
|
350357076d | ||
|
|
1e5e15f1f5 | ||
|
|
1a385a777e | ||
|
|
16278dae62 | ||
|
|
8294e46003 | ||
|
|
dedc66875b | ||
|
|
3045e239ff | ||
|
|
5363558118 | ||
|
|
13ba7cf0b8 | ||
|
|
a5a43e762d | ||
|
|
cb6101a835 | ||
|
|
255f84c969 | ||
|
|
7617d6c409 | ||
|
|
f75691b483 | ||
|
|
c5dbb79ed2 | ||
|
|
60ba3c64b2 | ||
|
|
080e58eeb7 | ||
|
|
5d228b9c27 | ||
|
|
e36e45054c | ||
|
|
ba87a2780d | ||
|
|
fccc3478c8 | ||
|
|
a76280c53b | ||
|
|
90ff03e27c | ||
|
|
5eed05989f | ||
|
|
ac939746bd | ||
|
|
b7532e89c2 | ||
|
|
74f44d6961 | ||
|
|
86fc27c233 | ||
|
|
4b6bb0e5f7 | ||
|
|
39170b74ca | ||
|
|
0e3f06429b | ||
|
|
ee7c597bd8 | ||
|
|
7f500d72c7 | ||
|
|
4dca4c4f22 |
+160
-130
@@ -7,155 +7,157 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
# necessary for windows
|
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
jobs:
|
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:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
# a list of all the targets
|
|
||||||
# 选择使用openssl或者ring,并不是所有平台都支持
|
|
||||||
include:
|
include:
|
||||||
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
|
- TARGET: i686-unknown-linux-musl
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: default
|
FEATURES: ring-cipher,openssl-vendored,wss
|
||||||
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
- TARGET: x86_64-unknown-linux-musl
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
|
- TARGET: aarch64-unknown-linux-musl
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
- TARGET: armv7-unknown-linux-musleabihf
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested
|
- TARGET: armv7-unknown-linux-musleabi
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
- TARGET: arm-unknown-linux-musleabihf
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested
|
- TARGET: arm-unknown-linux-musleabi
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
- TARGET: x86_64-apple-darwin
|
||||||
OS: macos-latest
|
OS: macos-latest
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
- TARGET: aarch64-apple-darwin
|
||||||
OS: macos-latest
|
OS: macos-latest
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: i686-pc-windows-msvc # tested on a windows machine
|
- TARGET: i686-pc-windows-msvc
|
||||||
OS: windows-2019
|
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
|
||||||
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
|
|
||||||
OS: windows-latest
|
OS: windows-latest
|
||||||
FEATURES: ring-cipher,openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: mipsel-unknown-linux-musl # openwrt
|
- TARGET: x86_64-pc-windows-msvc
|
||||||
|
OS: windows-latest
|
||||||
|
FEATURES: ring-cipher,wss
|
||||||
|
- TARGET: mipsel-unknown-linux-musl
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: openssl-vendored,ring-cipher
|
FEATURES: ring-cipher,wss
|
||||||
- TARGET: mips-unknown-linux-musl # openwrt
|
- TARGET: mips-unknown-linux-musl
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: openssl-vendored
|
FEATURES: ring-cipher,wss
|
||||||
# needs: test
|
|
||||||
runs-on: ${{ matrix.OS }}
|
runs-on: ${{ matrix.OS }}
|
||||||
env:
|
env:
|
||||||
NAME: vnt-cli # change with the name of your project
|
NAME: vnt-cli
|
||||||
TARGET: ${{ matrix.TARGET }}
|
TARGET: ${{ matrix.TARGET }}
|
||||||
OS: ${{ matrix.OS }}
|
OS: ${{ matrix.OS }}
|
||||||
FEATURES: ${{ matrix.FEATURES }}
|
FEATURES: ${{ matrix.FEATURES }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Init submodules
|
- name: Init submodules
|
||||||
uses: snickerbockers/submodules-init@v4
|
run: git submodule update --init --recursive --remote && git submodule status
|
||||||
|
|
||||||
- name: Cargo cache
|
- name: Cargo cache
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
./target
|
./target
|
||||||
key: build-cargo-registry-${{matrix.TARGET}}
|
key: build-cargo-registry-${{matrix.TARGET}}
|
||||||
|
|
||||||
- name: Use strawberry perl
|
- name: Use strawberry perl
|
||||||
if: startsWith(matrix.os, 'windows')
|
if: startsWith(matrix.OS, 'windows')
|
||||||
run: echo OPENSSL_SRC_PERL=C:/Strawberry/perl/bin/perl >> $GITHUB_ENV
|
run: echo OPENSSL_SRC_PERL=C:/Strawberry/perl/bin/perl >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: List
|
- name: List
|
||||||
run: find ./
|
run: find ./
|
||||||
- name: Install and configure dependencies
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly
|
||||||
|
profile: minimal
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: Verify Rust version
|
||||||
run: |
|
run: |
|
||||||
# dependencies are only needed on ubuntu as that's the only place where
|
rustc --version
|
||||||
# we make cross-compilation
|
cargo --version
|
||||||
rustup set auto-self-update disable
|
|
||||||
|
- name: Install dependencies on Ubuntu
|
||||||
if [[ $OS =~ ^ubuntu.*$ ]]; then
|
if: startsWith(matrix.OS, 'ubuntu')
|
||||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools
|
run: |
|
||||||
# curl -s musl.cc | grep mipsel
|
sudo apt-get update && sudo apt-get install -y clang llvm libc6-dev-i386 \
|
||||||
case $TARGET in
|
crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools libboost-all-dev libc6-dev wget tar
|
||||||
mipsel-unknown-linux-musl)
|
|
||||||
MUSL_URI=mipsel-linux-musl-cross
|
# Install musl cross toolchains if needed
|
||||||
;;
|
case $TARGET in
|
||||||
aarch64-unknown-linux-musl)
|
mipsel-unknown-linux-musl)
|
||||||
MUSL_URI=aarch64-linux-musl-cross
|
MUSL_URI=mipsel-linux-muslsf-cross
|
||||||
;;
|
URL=mipsel-linux-muslsf
|
||||||
armv7-unknown-linux-musleabihf)
|
;;
|
||||||
MUSL_URI=armv7l-linux-musleabihf-cross
|
aarch64-unknown-linux-musl)
|
||||||
;;
|
MUSL_URI=aarch64-linux-musl-cross
|
||||||
armv7-unknown-linux-musleabi)
|
;;
|
||||||
MUSL_URI=armv7m-linux-musleabi-cross
|
armv7-unknown-linux-musleabihf)
|
||||||
;;
|
MUSL_URI=armv7l-linux-musleabihf-cross
|
||||||
arm-unknown-linux-musleabihf)
|
;;
|
||||||
MUSL_URI=arm-linux-musleabihf-cross
|
armv7-unknown-linux-musleabi)
|
||||||
;;
|
MUSL_URI=armv7m-linux-musleabi-cross
|
||||||
arm-unknown-linux-musleabi)
|
;;
|
||||||
MUSL_URI=arm-linux-musleabi-cross
|
arm-unknown-linux-musleabihf)
|
||||||
;;
|
MUSL_URI=arm-linux-musleabihf-cross
|
||||||
mips-unknown-linux-musl)
|
;;
|
||||||
MUSL_URI=mips-linux-musl-cross
|
arm-unknown-linux-musleabi)
|
||||||
;;
|
MUSL_URI=arm-linux-musleabi-cross
|
||||||
esac
|
;;
|
||||||
|
mips-unknown-linux-musl)
|
||||||
if [[ $TARGET =~ ^mips.*$ ]]; then
|
MUSL_URI=mips-linux-muslsf-cross
|
||||||
# mips平台使用1.71.1版本
|
URL=mips-linux-muslsf
|
||||||
rustup install 1.71.1
|
;;
|
||||||
rustup default 1.71.1
|
i686-unknown-linux-musl)
|
||||||
else
|
MUSL_URI=i686-linux-musl-cross
|
||||||
rustup install 1.77
|
;;
|
||||||
rustup default 1.77
|
esac
|
||||||
fi
|
|
||||||
|
if [ -n "$MUSL_URI" ]; then
|
||||||
if [ -n "$MUSL_URI" ]; then
|
mkdir -p /opt/musl_gcc
|
||||||
mkdir -p ./musl_gcc
|
wget -c https://github.com/rustp2p/musl-cross/releases/download/0.0.1/$MUSL_URI.tgz -P /opt/musl_gcc/
|
||||||
wget -c https://musl.cc/$MUSL_URI.tgz -P ./musl_gcc/
|
tar zxf /opt/musl_gcc/$MUSL_URI.tgz -C /opt/musl_gcc/
|
||||||
tar zxf ./musl_gcc/$MUSL_URI.tgz -C ./musl_gcc/
|
sudo ln -s /opt/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
|
||||||
sudo ln -s $(pwd)/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
rustup install 1.77
|
|
||||||
rustup default 1.77
|
|
||||||
fi
|
fi
|
||||||
rustup -V
|
|
||||||
|
if [[ $TARGET =~ ^mips.*$ ]]; then
|
||||||
# some additional configuration for cross-compilation on linux
|
cd /opt/musl_gcc/${URL}-cross/lib/gcc/${URL}/11.2.1
|
||||||
|
cp libgcc_eh.a libunwind.a
|
||||||
|
rustup toolchain install nightly-x86_64-unknown-linux-gnu
|
||||||
|
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
||||||
|
RUST_LIB_SRC=$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/
|
||||||
|
if [[ -f $RUST_LIB_SRC/library/Cargo.lock && ! -f $RUST_LIB_SRC/Cargo.lock ]]; then
|
||||||
|
cp -f $RUST_LIB_SRC/library/Cargo.lock $RUST_LIB_SRC/Cargo.lock
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rustup -V
|
||||||
|
|
||||||
|
|
||||||
|
- name: Configure cargo for cross-compilation
|
||||||
|
run: |
|
||||||
cat >>~/.cargo/config <<EOF
|
cat >>~/.cargo/config <<EOF
|
||||||
[target.x86_64-unknown-linux-musl]
|
[target.x86_64-unknown-linux-musl]
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
||||||
@@ -175,11 +177,17 @@ jobs:
|
|||||||
linker = "arm-linux-musleabi-gcc"
|
linker = "arm-linux-musleabi-gcc"
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
||||||
[target.mipsel-unknown-linux-musl]
|
[target.mipsel-unknown-linux-musl]
|
||||||
linker = "mipsel-linux-musl-gcc"
|
linker = "mipsel-linux-muslsf-gcc"
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols","-C", "link-arg=-static",
|
||||||
|
"-C", "relocation-model=static","-C", "link-arg=-no-pie","--cfg", "compiler_builtins_no_debug",
|
||||||
|
"-L", "/opt/musl_gcc/mipsel-linux-muslsf-cross/mipsel-linux-muslsf/lib",
|
||||||
|
"-L", "/opt/musl_gcc/mipsel-linux-muslsf-cross/lib/gcc/mipsel-linux-muslsf/11.2.1"]
|
||||||
[target.mips-unknown-linux-musl]
|
[target.mips-unknown-linux-musl]
|
||||||
linker = "mips-linux-musl-gcc"
|
linker = "mips-linux-muslsf-gcc"
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols","-C", "link-arg=-static",
|
||||||
|
"-C", "relocation-model=static","-C", "link-arg=-no-pie","--cfg", "compiler_builtins_no_debug",
|
||||||
|
"-L", "/opt/musl_gcc/mips-linux-muslsf-cross/mips-linux-muslsf/lib",
|
||||||
|
"-L", "/opt/musl_gcc/mips-linux-muslsf-cross/lib/gcc/mips-linux-muslsf/11.2.1"]
|
||||||
[target.x86_64-pc-windows-msvc]
|
[target.x86_64-pc-windows-msvc]
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
||||||
[target.i686-pc-windows-msvc]
|
[target.i686-pc-windows-msvc]
|
||||||
@@ -189,54 +197,76 @@ jobs:
|
|||||||
[target.aarch64-apple-darwin]
|
[target.aarch64-apple-darwin]
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
||||||
[target.i686-unknown-linux-musl]
|
[target.i686-unknown-linux-musl]
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
linker = "i686-linux-musl-gcc"
|
||||||
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
- name: Install rust target
|
- name: Install rust target
|
||||||
|
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') && ! startsWith(matrix.TARGET, 'mips') }}
|
||||||
run: rustup target add $TARGET
|
run: rustup target add $TARGET
|
||||||
- name: Run build
|
|
||||||
run: cargo build --package vnt-cli --release --verbose --target $TARGET --features $FEATURES
|
- name: Run build vn-link-cli
|
||||||
|
run: |
|
||||||
|
if [[ $TARGET =~ ^mips.*$ ]]; then
|
||||||
|
cargo +nightly build --package vn-link-cli --release --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
|
||||||
|
else
|
||||||
|
cargo build --package vn-link-cli --release --target $TARGET --features $FEATURES
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run build vnt-cli
|
||||||
|
run: |
|
||||||
|
if [[ $TARGET =~ ^mips.*$ ]]; then
|
||||||
|
cargo +nightly build --package vnt-cli --release --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
|
||||||
|
else
|
||||||
|
cargo build --package vnt-cli --release --target $TARGET --features $FEATURES
|
||||||
|
fi
|
||||||
- name: List target
|
- name: List target
|
||||||
run: find ./target
|
run: find ./target
|
||||||
- name: Compress
|
- name: Compress
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ./artifacts
|
mkdir -p ./artifacts
|
||||||
# windows is the only OS using a different convention for executable file name
|
|
||||||
if [[ $OS =~ ^windows.*$ ]]; then
|
if [[ $OS =~ ^windows.*$ ]]; then
|
||||||
EXEC=$NAME.exe
|
EXEC_VNT_CLI=vnt-cli.exe
|
||||||
|
EXEC_VN_LINK_CLI=vn-link-cli.exe
|
||||||
else
|
else
|
||||||
EXEC=$NAME
|
EXEC_VNT_CLI=vnt-cli
|
||||||
|
EXEC_VN_LINK_CLI=vn-link-cli
|
||||||
fi
|
fi
|
||||||
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
|
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
|
||||||
TAG=$GITHUB_REF_NAME
|
TAG=$GITHUB_REF_NAME
|
||||||
else
|
else
|
||||||
TAG=$GITHUB_SHA
|
TAG=$GITHUB_SHA
|
||||||
fi
|
fi
|
||||||
mv ./target/$TARGET/release/$EXEC ./artifacts/$EXEC
|
mv ./target/$TARGET/release/$EXEC_VNT_CLI ./artifacts/$EXEC_VNT_CLI
|
||||||
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz -C ./artifacts $EXEC
|
mv ./target/$TARGET/release/$EXEC_VN_LINK_CLI ./artifacts/$EXEC_VN_LINK_CLI
|
||||||
|
mv ./README ./artifacts/README.txt
|
||||||
|
cd ./artifacts
|
||||||
|
tar -czf vnt-$TARGET-$TAG.tar.gz *
|
||||||
|
mkdir upload_file
|
||||||
|
mv vnt-$TARGET-$TAG.tar.gz ./upload_file/
|
||||||
|
|
||||||
- name: Archive artifact
|
- name: Archive artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: vnt-cli
|
name: vnt-cli-${{ matrix.TARGET }}
|
||||||
path: |
|
path: ./artifacts/upload_file
|
||||||
./artifacts
|
|
||||||
# deploys to github releases on tag
|
|
||||||
deploy:
|
deploy:
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: vnt-cli
|
|
||||||
path: ./artifacts
|
path: ./artifacts
|
||||||
- name: List
|
- name: List
|
||||||
run: find ./artifacts
|
run: find ./artifacts
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.YOURTOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: ./artifacts/*.tar.gz
|
file: ./artifacts/**/*.tar.gz
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
|||||||
+4
-1
@@ -1,3 +1,6 @@
|
|||||||
target/*
|
target/*
|
||||||
vnt/src/proto/*
|
vnt/src/proto/*
|
||||||
vnt-cli/src/generated_serial_number.rs
|
common/src/generated_serial_number.rs
|
||||||
|
|
||||||
|
# RustRover
|
||||||
|
.idea
|
||||||
Generated
-2054
@@ -1,2054 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "addr2line"
|
|
||||||
version = "0.21.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
|
||||||
dependencies = [
|
|
||||||
"gimli",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aead"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aes"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cipher",
|
|
||||||
"cpufeatures",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aes-gcm"
|
|
||||||
version = "0.10.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
|
|
||||||
dependencies = [
|
|
||||||
"aead",
|
|
||||||
"aes",
|
|
||||||
"cipher",
|
|
||||||
"ctr",
|
|
||||||
"ghash",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "1.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android-tzdata"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_log-sys"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_logger"
|
|
||||||
version = "0.13.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f"
|
|
||||||
dependencies = [
|
|
||||||
"android_log-sys",
|
|
||||||
"env_logger",
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_system_properties"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.82"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arc-swap"
|
|
||||||
version = "1.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace"
|
|
||||||
version = "0.3.71"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
|
||||||
dependencies = [
|
|
||||||
"addr2line",
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide",
|
|
||||||
"object",
|
|
||||||
"rustc-demangle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64ct"
|
|
||||||
version = "1.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "block-buffer"
|
|
||||||
version = "0.10.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "block-padding"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bumpalo"
|
|
||||||
version = "3.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "byteorder"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytes"
|
|
||||||
version = "1.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cbc"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
|
|
||||||
dependencies = [
|
|
||||||
"cipher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.94"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
|
|
||||||
dependencies = [
|
|
||||||
"jobserver",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cesu8"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono"
|
|
||||||
version = "0.4.38"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
|
||||||
dependencies = [
|
|
||||||
"android-tzdata",
|
|
||||||
"iana-time-zone",
|
|
||||||
"js-sys",
|
|
||||||
"num-traits",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-targets 0.52.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cipher"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"inout",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "combine"
|
|
||||||
version = "4.6.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "common"
|
|
||||||
version = "1.2.10"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "console"
|
|
||||||
version = "0.15.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
|
||||||
dependencies = [
|
|
||||||
"encode_unicode",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"unicode-width",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "const-oid"
|
|
||||||
version = "0.9.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation-sys"
|
|
||||||
version = "0.8.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cpufeatures"
|
|
||||||
version = "0.2.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-queue"
|
|
||||||
version = "0.3.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crypto-common"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array",
|
|
||||||
"rand_core",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ctr"
|
|
||||||
version = "0.9.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
|
||||||
dependencies = [
|
|
||||||
"cipher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "der"
|
|
||||||
version = "0.7.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
|
|
||||||
dependencies = [
|
|
||||||
"const-oid",
|
|
||||||
"pem-rfc7468",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derivative"
|
|
||||||
version = "2.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "destructure_traitobject"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "digest"
|
|
||||||
version = "0.10.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
|
||||||
dependencies = [
|
|
||||||
"block-buffer",
|
|
||||||
"const-oid",
|
|
||||||
"crypto-common",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dns-parser"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"quick-error",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ecb"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7"
|
|
||||||
dependencies = [
|
|
||||||
"cipher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "embed-manifest"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "41cd446c890d6bed1d8b53acef5f240069ebef91d6fae7c5f52efe61fe8b5eae"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "encode_unicode"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_logger"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "equivalent"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.3.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastrand"
|
|
||||||
version = "2.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fnv"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "generic-array"
|
|
||||||
version = "0.14.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
|
||||||
dependencies = [
|
|
||||||
"typenum",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getopts"
|
|
||||||
version = "0.2.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"js-sys",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ghash"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
|
|
||||||
dependencies = [
|
|
||||||
"opaque-debug",
|
|
||||||
"polyval",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gimli"
|
|
||||||
version = "0.28.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.14.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "home"
|
|
||||||
version = "0.5.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humantime"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone"
|
|
||||||
version = "0.1.60"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
|
||||||
dependencies = [
|
|
||||||
"android_system_properties",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"iana-time-zone-haiku",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone-haiku"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "1.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"hashbrown 0.12.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "2.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
|
||||||
dependencies = [
|
|
||||||
"equivalent",
|
|
||||||
"hashbrown 0.14.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inout"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
|
||||||
dependencies = [
|
|
||||||
"block-padding",
|
|
||||||
"generic-array",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ioctl-sys"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jni"
|
|
||||||
version = "0.21.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
|
||||||
dependencies = [
|
|
||||||
"cesu8",
|
|
||||||
"cfg-if",
|
|
||||||
"combine",
|
|
||||||
"jni-sys",
|
|
||||||
"log",
|
|
||||||
"thiserror",
|
|
||||||
"walkdir",
|
|
||||||
"windows-sys 0.45.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jni-sys"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jobserver"
|
|
||||||
version = "0.1.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "js-sys"
|
|
||||||
version = "0.3.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
|
||||||
dependencies = [
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
dependencies = [
|
|
||||||
"spin 0.5.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.153"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"windows-targets 0.52.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libm"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libsm"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "git+https://github.com/lbl8603/libsm#f9e1b8cf20d0829efb4934a940d0ba4f3ee0ac14"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"getrandom",
|
|
||||||
"lazy_static",
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"rand",
|
|
||||||
"yasna",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.4.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lock_api"
|
|
||||||
version = "0.4.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log-mdc"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log4rs"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"arc-swap",
|
|
||||||
"chrono",
|
|
||||||
"derivative",
|
|
||||||
"fnv",
|
|
||||||
"humantime",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"log-mdc",
|
|
||||||
"once_cell",
|
|
||||||
"parking_lot",
|
|
||||||
"rand",
|
|
||||||
"serde",
|
|
||||||
"serde-value",
|
|
||||||
"serde_json",
|
|
||||||
"serde_yaml",
|
|
||||||
"thiserror",
|
|
||||||
"thread-id",
|
|
||||||
"typemap-ors",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lz4_flex"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mio"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"wasi",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint-dig"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
"lazy_static",
|
|
||||||
"libm",
|
|
||||||
"num-integer",
|
|
||||||
"num-iter",
|
|
||||||
"num-traits",
|
|
||||||
"rand",
|
|
||||||
"smallvec",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.46"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-iter"
|
|
||||||
version = "0.1.44"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"libm",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "object"
|
|
||||||
version = "0.32.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "opaque-debug"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-src"
|
|
||||||
version = "300.1.3+3.1.2"
|
|
||||||
source = "git+https://github.com/lbl8603/openssl-src-rs#871c5d6cfe8a7cb1c5725638d7563c0d96ca4c04"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-sys"
|
|
||||||
version = "0.9.93"
|
|
||||||
source = "git+https://github.com/lbl8603/rust-openssl#e8b3d2c02d2d07a0e4a82ff4e4bef210f4bc71c8"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"openssl-src",
|
|
||||||
"pkg-config",
|
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ordered-float"
|
|
||||||
version = "2.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_info"
|
|
||||||
version = "3.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"serde",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "packet"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
|
||||||
dependencies = [
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.9.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"smallvec",
|
|
||||||
"windows-targets 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pem-rfc7468"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
|
||||||
dependencies = [
|
|
||||||
"base64ct",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkcs1"
|
|
||||||
version = "0.7.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
|
|
||||||
dependencies = [
|
|
||||||
"der",
|
|
||||||
"pkcs8",
|
|
||||||
"spki",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkcs8"
|
|
||||||
version = "0.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
|
||||||
dependencies = [
|
|
||||||
"der",
|
|
||||||
"spki",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkg-config"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "polyval"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cpufeatures",
|
|
||||||
"opaque-debug",
|
|
||||||
"universal-hash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.81"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protobuf"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "58678a64de2fced2bdec6bca052a6716a0efe692d6e3f53d1bda6a1def64cfc0"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"protobuf-support",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protobuf-codegen"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "32777b0b3f6538d9d2e012b3fad85c7e4b9244b5958d04a6415f4333782b7a77"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"once_cell",
|
|
||||||
"protobuf",
|
|
||||||
"protobuf-parse",
|
|
||||||
"regex",
|
|
||||||
"tempfile",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protobuf-parse"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96cb37955261126624a25b5e6bda40ae34cf3989d52a783087ca6091b29b5642"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"indexmap 1.9.3",
|
|
||||||
"log",
|
|
||||||
"protobuf",
|
|
||||||
"protobuf-support",
|
|
||||||
"tempfile",
|
|
||||||
"thiserror",
|
|
||||||
"which",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protobuf-support"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1ed294a835b0f30810e13616b1cd34943c6d1e84a8f3b0dcfe466d256c3e7e7"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protoc-bin-vendored"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "005ca8623e5633e298ad1f917d8be0a44bcf406bf3cde3b80e63003e49a3f27d"
|
|
||||||
dependencies = [
|
|
||||||
"protoc-bin-vendored-linux-aarch_64",
|
|
||||||
"protoc-bin-vendored-linux-ppcle_64",
|
|
||||||
"protoc-bin-vendored-linux-x86_32",
|
|
||||||
"protoc-bin-vendored-linux-x86_64",
|
|
||||||
"protoc-bin-vendored-macos-x86_64",
|
|
||||||
"protoc-bin-vendored-win32",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protoc-bin-vendored-linux-aarch_64"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fb9fc9cce84c8694b6ea01cc6296617b288b703719b725b8c9c65f7c5874435"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protoc-bin-vendored-linux-ppcle_64"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02d2a07dcf7173a04d49974930ccbfb7fd4d74df30ecfc8762cf2f895a094516"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protoc-bin-vendored-linux-x86_32"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d54fef0b04fcacba64d1d80eed74a20356d96847da8497a59b0a0a436c9165b0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protoc-bin-vendored-linux-x86_64"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b8782f2ce7d43a9a5c74ea4936f001e9e8442205c244f7a3d4286bd4c37bc924"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protoc-bin-vendored-macos-x86_64"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b5de656c7ee83f08e0ae5b81792ccfdc1d04e7876b1d9a38e6876a9e09e02537"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protoc-bin-vendored-win32"
|
|
||||||
version = "3.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9653c3ed92974e34c5a6e0a510864dab979760481714c172e0a34e437cb98804"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-error"
|
|
||||||
version = "1.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.36"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "r-ex"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "42776a943a4f890410259860d4c308d32792ecbeaca4932a2b94b04f6d27bb9a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.10.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ring"
|
|
||||||
version = "0.17.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"getrandom",
|
|
||||||
"libc",
|
|
||||||
"spin 0.9.8",
|
|
||||||
"untrusted",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rsa"
|
|
||||||
version = "0.9.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc"
|
|
||||||
dependencies = [
|
|
||||||
"const-oid",
|
|
||||||
"digest",
|
|
||||||
"num-bigint-dig",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"pkcs1",
|
|
||||||
"pkcs8",
|
|
||||||
"rand_core",
|
|
||||||
"signature",
|
|
||||||
"spki",
|
|
||||||
"subtle",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-demangle"
|
|
||||||
version = "0.1.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.38.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.5.0",
|
|
||||||
"errno",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "1.0.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "same-file"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.198"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
|
|
||||||
dependencies = [
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde-value"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
|
||||||
dependencies = [
|
|
||||||
"ordered-float",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.198"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.60",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.116"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
|
||||||
dependencies = [
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_yaml"
|
|
||||||
version = "0.9.34+deprecated"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap 2.2.6",
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
"unsafe-libyaml",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha2"
|
|
||||||
version = "0.10.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cpufeatures",
|
|
||||||
"digest",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "signal-hook-registry"
|
|
||||||
version = "1.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "signature"
|
|
||||||
version = "2.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
|
||||||
dependencies = [
|
|
||||||
"digest",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.13.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "socket2"
|
|
||||||
version = "0.5.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spin"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spin"
|
|
||||||
version = "0.9.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spki"
|
|
||||||
version = "0.7.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
|
||||||
dependencies = [
|
|
||||||
"base64ct",
|
|
||||||
"der",
|
|
||||||
"sha2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stun-bytes"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3bebd666814c8af1e06e4d489f9c3d03a4aef20bae651550c52e6e95e09f3f12"
|
|
||||||
dependencies = [
|
|
||||||
"r-ex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stun-format"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c6ad3c54fde6dfd6fe5048a71515b392d22c29730533663b5300e1b511d78df5"
|
|
||||||
dependencies = [
|
|
||||||
"r-ex",
|
|
||||||
"stun-bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "subtle"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sudo"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "88bd84d4c082e18e37fef52c0088e4407dabcef19d23a607fb4b5ee03b7d5b83"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.109"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.60"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tempfile"
|
|
||||||
version = "3.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"fastrand",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "1.0.58"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "1.0.58"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.60",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread-id"
|
|
||||||
version = "4.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio"
|
|
||||||
version = "1.37.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
"bytes",
|
|
||||||
"libc",
|
|
||||||
"mio",
|
|
||||||
"num_cpus",
|
|
||||||
"parking_lot",
|
|
||||||
"pin-project-lite",
|
|
||||||
"signal-hook-registry",
|
|
||||||
"socket2",
|
|
||||||
"tokio-macros",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-macros"
|
|
||||||
version = "2.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.60",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tun"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"ioctl-sys",
|
|
||||||
"libc",
|
|
||||||
"libloading",
|
|
||||||
"log",
|
|
||||||
"rand",
|
|
||||||
"widestring",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typemap-ors"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867"
|
|
||||||
dependencies = [
|
|
||||||
"unsafe-any-ors",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "universal-hash"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unsafe-any-ors"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad"
|
|
||||||
dependencies = [
|
|
||||||
"destructure_traitobject",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unsafe-libyaml"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "untrusted"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "uuid"
|
|
||||||
version = "1.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vcpkg"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vnt"
|
|
||||||
version = "1.2.10"
|
|
||||||
dependencies = [
|
|
||||||
"aes",
|
|
||||||
"aes-gcm",
|
|
||||||
"anyhow",
|
|
||||||
"bytes",
|
|
||||||
"cbc",
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-queue",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"dns-parser",
|
|
||||||
"ecb",
|
|
||||||
"libc",
|
|
||||||
"libloading",
|
|
||||||
"libsm",
|
|
||||||
"log",
|
|
||||||
"lz4_flex",
|
|
||||||
"mio",
|
|
||||||
"openssl-sys",
|
|
||||||
"packet",
|
|
||||||
"parking_lot",
|
|
||||||
"protobuf",
|
|
||||||
"protobuf-codegen",
|
|
||||||
"protoc-bin-vendored",
|
|
||||||
"rand",
|
|
||||||
"ring",
|
|
||||||
"rsa",
|
|
||||||
"sha2",
|
|
||||||
"socket2",
|
|
||||||
"spki",
|
|
||||||
"stun-format",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"tun",
|
|
||||||
"zstd",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vnt-cli"
|
|
||||||
version = "1.2.10"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"chrono",
|
|
||||||
"common",
|
|
||||||
"console",
|
|
||||||
"embed-manifest",
|
|
||||||
"getopts",
|
|
||||||
"log",
|
|
||||||
"log4rs",
|
|
||||||
"os_info",
|
|
||||||
"rand",
|
|
||||||
"serde",
|
|
||||||
"serde_yaml",
|
|
||||||
"sudo",
|
|
||||||
"uuid",
|
|
||||||
"vnt",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vnt-jni"
|
|
||||||
version = "1.2.10"
|
|
||||||
dependencies = [
|
|
||||||
"android_logger",
|
|
||||||
"common",
|
|
||||||
"jni",
|
|
||||||
"log",
|
|
||||||
"parking_lot",
|
|
||||||
"spki",
|
|
||||||
"vnt",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "walkdir"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
|
||||||
dependencies = [
|
|
||||||
"same-file",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen"
|
|
||||||
version = "0.2.92"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"wasm-bindgen-macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-backend"
|
|
||||||
version = "0.2.92"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
|
||||||
dependencies = [
|
|
||||||
"bumpalo",
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.60",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro"
|
|
||||||
version = "0.2.92"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"wasm-bindgen-macro-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro-support"
|
|
||||||
version = "0.2.92"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.60",
|
|
||||||
"wasm-bindgen-backend",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-shared"
|
|
||||||
version = "0.2.92"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "which"
|
|
||||||
version = "4.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"home",
|
|
||||||
"once_cell",
|
|
||||||
"rustix",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "widestring"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.45.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.42.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.42.2",
|
|
||||||
"windows_aarch64_msvc 0.42.2",
|
|
||||||
"windows_i686_gnu 0.42.2",
|
|
||||||
"windows_i686_msvc 0.42.2",
|
|
||||||
"windows_x86_64_gnu 0.42.2",
|
|
||||||
"windows_x86_64_gnullvm 0.42.2",
|
|
||||||
"windows_x86_64_msvc 0.42.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.48.5",
|
|
||||||
"windows_aarch64_msvc 0.48.5",
|
|
||||||
"windows_i686_gnu 0.48.5",
|
|
||||||
"windows_i686_msvc 0.48.5",
|
|
||||||
"windows_x86_64_gnu 0.48.5",
|
|
||||||
"windows_x86_64_gnullvm 0.48.5",
|
|
||||||
"windows_x86_64_msvc 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.52.5",
|
|
||||||
"windows_aarch64_msvc 0.52.5",
|
|
||||||
"windows_i686_gnu 0.52.5",
|
|
||||||
"windows_i686_gnullvm",
|
|
||||||
"windows_i686_msvc 0.52.5",
|
|
||||||
"windows_x86_64_gnu 0.52.5",
|
|
||||||
"windows_x86_64_gnullvm 0.52.5",
|
|
||||||
"windows_x86_64_msvc 0.52.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnullvm"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.52.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yasna"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zeroize"
|
|
||||||
version = "1.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zstd"
|
|
||||||
version = "0.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
|
|
||||||
dependencies = [
|
|
||||||
"zstd-safe",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zstd-safe"
|
|
||||||
version = "7.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
|
|
||||||
dependencies = [
|
|
||||||
"zstd-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zstd-sys"
|
|
||||||
version = "2.0.10+zstd.1.5.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["vnt","common","vnt-cli","vnt-jni"]
|
members = ["vnt", "common", "vnt-cli", "vn-link", "vn-link-cli"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 'z'
|
opt-level = 'z'
|
||||||
debug = 0
|
debug = 0
|
||||||
debug-assertions = false
|
debug-assertions = false
|
||||||
strip= "debuginfo"
|
strip = "debuginfo"
|
||||||
lto = true
|
lto = true
|
||||||
panic = 'abort'
|
panic = 'abort'
|
||||||
incremental = false
|
incremental = false
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
一、程序说明
|
||||||
|
1. vnt-cli vnt的命令行程序
|
||||||
|
2. vn-link-cli 功能和vnt-cli基本一致,但是不依赖tun、不改变本地路由、不需要管理员/root权限
|
||||||
|
|
||||||
|
二、使用说明
|
||||||
|
使用-k参数构建虚拟网络
|
||||||
|
|
||||||
|
|
||||||
|
1. Program Description
|
||||||
|
a. vnt-cli: Command-line program for VNT.
|
||||||
|
b. vn-link-cli: Functions similarly to vnt-cli, but does not depend on TUN, does not change local routing, and does not require administrator/root permissions.
|
||||||
|
|
||||||
|
2. Instructions for Use
|
||||||
|
Use the -k parameter to create a virtual network.
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
# Vnt
|
# VNT
|
||||||
|
|
||||||
A virtual network tool (VPN)
|
🚀An efficient VPN
|
||||||
|
|
||||||
将不同网络下的多个设备虚拟到一个局域网下
|
🚀一个简单、高效、能快速组建虚拟局域网的工具
|
||||||
|
|
||||||
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
|
### vnt-cli参数详解 [参数说明](https://github.com/vnt-dev/vnt/blob/main/vnt-cli/README.md)
|
||||||
|
|
||||||
### 快速使用:
|
### 快速开始:
|
||||||
|
|
||||||
1. 指定一个token,在多台设备上运行该程序,例如:
|
1. 指定一个token,在多台设备上运行该程序,例如:
|
||||||
```shell
|
```shell
|
||||||
@@ -39,27 +39,26 @@ A virtual network tool (VPN)
|
|||||||
```
|
```
|
||||||
4. 最后可以用虚拟ip实现设备间相互访问
|
4. 最后可以用虚拟ip实现设备间相互访问
|
||||||
|
|
||||||
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/vnt/main/documents/img/ssh.jpg">
|
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/vnt-dev/vnt/main/documents/img/ssh.jpg">
|
||||||
5. 帮助,使用-h命令查看
|
5. 帮助,使用-h命令查看
|
||||||
|
|
||||||
### 更多玩法
|
|
||||||
|
|
||||||
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
|
|
||||||
2. 安装samba服务,共享磁盘
|
|
||||||
3. 搭配公网服务器nginx反向代理,在公网访问内网文件或服务
|
|
||||||
4. 点对网,访问内网其他机器、IP代理(结合启动参数'-i'和'-o')
|
|
||||||
|
|
||||||
### 使用须知
|
### 使用须知
|
||||||
|
|
||||||
- token的作用是标识一个虚拟局域网,当使用公共服务器时,建议使用一个唯一值当token(比如uuid),否则有可能连接到其他人创建的虚拟局域网中
|
- token的作用是标识一个虚拟局域网,当使用公共服务器时,建议使用一个唯一值当token(比如uuid),否则有可能连接到其他人创建的虚拟局域网中
|
||||||
- 默认使用公共服务器做注册和中继,目前的配置是2核4G 4Mbps,有需要再扩展~
|
- 默认使用公共服务器做注册和中继,目前的配置是2核4G 4Mbps,有需要再扩展~
|
||||||
- 需要root/管理员权限
|
|
||||||
- vnt-cli需要使用命令行运行
|
- vnt-cli需要使用命令行运行
|
||||||
- Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli)
|
- Mac和Linux下需要加可执行权限(例如:chmod +x ./vnt-cli)
|
||||||
- 可以自己搭注册和中继服务器([server](https://github.com/lbl8603/vnts))
|
- 可以自己搭中继服务器([server](https://github.com/vnt-dev/vnts))
|
||||||
- vnt使用stun服务器探测网络NAT类型,默认使用谷歌和腾讯的stun服务器,也可自己搭建(-e参数指定)
|
|
||||||
|
|
||||||
### 编译
|
### 直接使用
|
||||||
|
|
||||||
|
[**下载release文件**](https://github.com/vnt-dev/vnt/releases)
|
||||||
|
|
||||||
|
[**帮助文档**](https://rustvnt.com)
|
||||||
|
|
||||||
|
### 自行编译
|
||||||
|
|
||||||
|
<details> <summary>点击展开</summary>
|
||||||
|
|
||||||
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
|
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
|
||||||
|
|
||||||
@@ -73,99 +72,27 @@ cargo build -p vnt-cli --no-default-features
|
|||||||
|
|
||||||
features说明
|
features说明
|
||||||
|
|
||||||
| feature | 说明 | 是否默认 |
|
| feature | 说明 | 是否默认 |
|
||||||
|------------------|----------------------|------|
|
|-------------------|--------------------------------|------|
|
||||||
| openssl | 使用openssl中的aes_ecb算法 | 否 |
|
| openssl | 使用openssl中的加密算法 | 否 |
|
||||||
| openssl-vendored | 从源码编译openssl | 否 |
|
| openssl-vendored | 从源码编译openssl | 否 |
|
||||||
| ring-cipher | 使用ring中的aes_gcm算法 | 否 |
|
| ring-cipher | 使用ring中的加密算法 | 否 |
|
||||||
| aes_cbc | 支持aes_cbc加密 | 是 |
|
| aes_cbc | 支持aes_cbc加密 | 是 |
|
||||||
| aes_ecb | 支持aes_ecb加密 | 是 |
|
| aes_ecb | 支持aes_ecb加密 | 是 |
|
||||||
| aes_gcm | 支持aes_gcm加密 | 是 |
|
| aes_gcm | 支持aes_gcm加密 | 是 |
|
||||||
| sm4_cbc | 支持sm4_cbc加密 | 是 |
|
| sm4_cbc | 支持sm4_cbc加密 | 是 |
|
||||||
| server_encrypt | 支持服务端加密 | 是 |
|
| chacha20_poly1305 | 支持chacha20和chacha20_poly1305加密 | 是 |
|
||||||
| ip_proxy | 内置ip代理 | 是 |
|
| server_encrypt | 支持服务端加密 | 是 |
|
||||||
| port_mapping | 端口映射 | 是 |
|
| ip_proxy | 内置ip代理 | 是 |
|
||||||
| log | 日志 | 是 |
|
| port_mapping | 端口映射 | 是 |
|
||||||
| command | list、route等命令 | 是 |
|
| log | 日志 | 是 |
|
||||||
| file_config | yaml配置文件 | 是 |
|
| command | list、route等命令 | 是 |
|
||||||
| lz4 | lz4压缩 | 是 |
|
| file_config | yaml配置文件 | 是 |
|
||||||
| zstd | zstd压缩 | 否 |
|
| lz4 | lz4压缩 | 是 |
|
||||||
|
| zstd | zstd压缩 | 否 |
|
||||||
### ip转发/代理
|
| upnp | upnp协议 | 否 |
|
||||||
|
| ws | ws协议 | 是 |
|
||||||
如果编译时去除了内置的ip代理(或使用--no-proxy关闭了代理),则可以使用网卡NAT转发来实现点对网,
|
| wss | wss协议 | 是 |
|
||||||
一般来说使用网卡NAT转发会比内置的ip代理性能更好
|
|
||||||
<details> <summary>NAT配置可参考如下示例,点击展开</summary>
|
|
||||||
|
|
||||||
### 在出口一端做如下配置
|
|
||||||
|
|
||||||
注意原有的-i(入口)和-o(出口)的参数不能少
|
|
||||||
|
|
||||||
### windows
|
|
||||||
|
|
||||||
参考 https://learn.microsoft.com/zh-cn/virtualization/hyper-v-on-windows/user-guide/setup-nat-network
|
|
||||||
|
|
||||||
```shell
|
|
||||||
#设置nat,名字可以自己取,网段是vnt的网段
|
|
||||||
New-NetNat -Name vntnat -InternalIPInterfaceAddressPrefix 10.26.0.0/24
|
|
||||||
#查看设置
|
|
||||||
Get-NetNat
|
|
||||||
```
|
|
||||||
|
|
||||||
### linux
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 开启ip转发
|
|
||||||
sudo sysctl -w net.ipv4.ip_forward=1
|
|
||||||
# 开启nat转发 表示来源10.26.0.0/24的数据通过nat映射后再从vnt-tun以外的其他网卡发出去
|
|
||||||
sudo iptables -t nat -A POSTROUTING ! -o vnt-tun -s 10.26.0.0/24 -j MASQUERADE
|
|
||||||
# 或者这样 表示来源10.26.0.0/24的数据通过nat映射后再从eth0网卡发出去
|
|
||||||
sudo iptables -t nat -A POSTROUTING -o eth0 -s 10.26.0.0/24 -j MASQUERADE
|
|
||||||
# 查看设置
|
|
||||||
iptables -vnL -t nat
|
|
||||||
```
|
|
||||||
|
|
||||||
### Arch Linux
|
|
||||||
|
|
||||||
[](https://repology.org/project/vnt/versions)
|
|
||||||
|
|
||||||
- 通过 AUR 安装 [vnt-git](https://aur.archlinux.org/packages/vnt-git)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yay -Syu vnt
|
|
||||||
```
|
|
||||||
|
|
||||||
- 通过 `systemd` 设置开机自启及配置
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo systemctl enable --now vnt-cli@
|
|
||||||
sudo systemctl status vnt-cli@
|
|
||||||
```
|
|
||||||
|
|
||||||
- 启用内置 `IPv4` 转发规则
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo sysctl --system
|
|
||||||
```
|
|
||||||
|
|
||||||
- 通过内置防火墙文件配置防火墙转发规则
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo cat /etc/vnt/iptables-vnt.rules >> /etc/iptables/iptables.rules
|
|
||||||
sudo iptables-restore iptables.rules
|
|
||||||
```
|
|
||||||
|
|
||||||
### macos
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# 开启ip转发
|
|
||||||
sudo sysctl -w net.ipv4.ip_forward=1
|
|
||||||
# 配置NAT转发规则
|
|
||||||
# 在/etc/pf.conf文件中添加以下规则,en0是出口网卡,10.26.0.0/24是来源网段
|
|
||||||
nat on en0 from 10.26.0.0/24 to any -> (en0)
|
|
||||||
# 加载规则
|
|
||||||
sudo pfctl -f /etc/pf.conf -e
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@@ -173,60 +100,40 @@ sudo pfctl -f /etc/pf.conf -e
|
|||||||
|
|
||||||
- Mac
|
- Mac
|
||||||
- Linux
|
- Linux
|
||||||
- Arch Linux `yay -Syu vnt`
|
|
||||||
- Windows
|
- Windows
|
||||||
- 默认使用tun网卡 依赖wintun.dll([win-tun](https://www.wintun.net/))(将dll放到同目录下,建议使用版本0.14.1)
|
- 默认使用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)
|
- 可选择使用tap网卡 依赖tap-windows([win-tap](https://build.openvpn.net/downloads/releases/))(建议使用版本9.24.7)
|
||||||
- Android
|
- Android
|
||||||
- [VntApp](https://github.com/lbl8603/VntApp)
|
|
||||||
|
### GUI
|
||||||
|
|
||||||
|
支持安卓和Windows [下载](https://github.com/vnt-dev/VntApp/releases/)
|
||||||
|
|
||||||
### 特性
|
### 特性
|
||||||
|
|
||||||
- IP层数据转发
|
- IP层数据转发
|
||||||
- tun虚拟网卡
|
|
||||||
- tap虚拟网卡
|
|
||||||
- NAT穿透
|
- NAT穿透
|
||||||
- 点对点穿透
|
- 点对点穿透
|
||||||
- 服务端中继转发
|
- 服务端中继转发
|
||||||
- 客户端中继转发
|
- 客户端中继转发
|
||||||
- IP代理
|
- IP代理(点对点、点对网)
|
||||||
- p2p组播/广播
|
- p2p组播/广播
|
||||||
- 客户端数据加密
|
- 客户端数据加密(`aes-gcm`、`chacha20-poly1305`等多种加密算法)
|
||||||
- 服务端数据加密
|
- 服务端数据加密(`rsa` + `aes-gcm`)
|
||||||
|
- 多通道UDP应对QOS
|
||||||
|
- 支持TCP、UDP、WebSocket等多种协议
|
||||||
|
- 支持数据压缩
|
||||||
|
|
||||||
### 结构
|
### 更多玩法
|
||||||
|
|
||||||
<details> <summary>展开</summary>
|
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
|
||||||
|
2. 安装samba服务,共享磁盘
|
||||||
<pre>
|
3. 点对网,访问内网其他机器、IP代理(结合启动参数'-i'和'-o')
|
||||||
|
|
||||||
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
|
### Todo
|
||||||
|
|
||||||
- 桌面UI(测试中)
|
- ~~桌面UI(已支持)~~
|
||||||
|
- 使用FEC、ARQ等方式提升弱网环境的稳定性
|
||||||
|
|
||||||
### 常见问题
|
### 常见问题
|
||||||
|
|
||||||
@@ -282,16 +189,29 @@ vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
|
|||||||
|
|
||||||
### 交流群
|
### 交流群
|
||||||
|
|
||||||
QQ: 1034868233
|
对VNT有任何问题均可以加群联系作者
|
||||||
|
|
||||||
|
QQ群1: 1034868233(满人)
|
||||||
|
|
||||||
|
QQ群2: 950473757
|
||||||
|
|
||||||
|
QQ群3: 1060550456
|
||||||
|
|
||||||
|
### 赞助
|
||||||
|
|
||||||
|
如果VNT对你有帮助,欢迎打赏作者
|
||||||
|
|
||||||
|
<img width="300" alt="" src="https://github.com/vnt-dev/vnt/assets/49143209/0d3a7311-43fc-4ed7-9507-863b5d69b6b2">
|
||||||
|
|
||||||
### 其他
|
### 其他
|
||||||
|
|
||||||
可使用社区小伙伴搭建的中继服务器
|
可使用社区小伙伴搭建的中继服务器
|
||||||
|
|
||||||
1. -s vnt.8443.eu.org:29871
|
1. -s vnt.8443.eu.org:29871
|
||||||
|
2. -s vnt.wherewego.top:29872
|
||||||
|
|
||||||
### 参与贡献
|
### 参与贡献
|
||||||
|
|
||||||
<a href="https://github.com/lbl8603/vnt/graphs/contributors">
|
<a href="https://github.com/vnt-dev/vnt/graphs/contributors">
|
||||||
<img src="https://contrib.rocks/image?repo=lbl8603/vnt" />
|
<img src="https://contrib.rocks/image?repo=vnt-dev/vnt" />
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
+39
-1
@@ -1,8 +1,46 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "1.2.10"
|
version = "1.2.16"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
||||||
|
anyhow = "1.0.82"
|
||||||
|
console = "0.15.2"
|
||||||
|
log = "0.4.17"
|
||||||
|
log4rs = { version = "1.3.0", optional = true }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_yaml = "0.9.32"
|
||||||
|
getopts = "0.2.21"
|
||||||
|
gethostname = "0.4.3"
|
||||||
|
uuid = { version = "1.8.0", features = ["v4"] }
|
||||||
|
sys-locale = "0.3.1"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
openssl = ["vnt/openssl"]
|
||||||
|
openssl-vendored = ["vnt/openssl-vendored"]
|
||||||
|
ring-cipher = ["vnt/ring-cipher"]
|
||||||
|
aes_cbc = ["vnt/aes_cbc"]
|
||||||
|
aes_ecb = ["vnt/aes_ecb"]
|
||||||
|
sm4_cbc = ["vnt/sm4_cbc"]
|
||||||
|
aes_gcm = ["vnt/aes_gcm"]
|
||||||
|
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
|
||||||
|
server_encrypt = ["vnt/server_encrypt"]
|
||||||
|
ip_proxy = ["vnt/ip_proxy"]
|
||||||
|
port_mapping = ["vnt/port_mapping"]
|
||||||
|
lz4 = ["vnt/lz4_compress"]
|
||||||
|
zstd = ["vnt/zstd_compress"]
|
||||||
|
upnp = ["vnt/upnp"]
|
||||||
|
ws = ["vnt/ws"]
|
||||||
|
wss = ["vnt/wss"]
|
||||||
|
command = []
|
||||||
|
file_config = []
|
||||||
|
log = ["log4rs"]
|
||||||
|
integrated_tun = ["vnt/integrated_tun"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
rand = "0.8.5"
|
||||||
|
chrono = "0.4.23"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
use rand::Rng;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let now_time = chrono::Local::now();
|
||||||
|
let serial_number = format!(
|
||||||
|
"{}-{}",
|
||||||
|
&now_time.format("%y%m%d%H%M").to_string(),
|
||||||
|
rand::thread_rng().gen_range(100..1000)
|
||||||
|
);
|
||||||
|
let generated_code = format!(r#"pub const SERIAL_NUMBER: &str = "{}";"#, serial_number);
|
||||||
|
let dest_path = "src/generated_serial_number.rs";
|
||||||
|
let mut file = File::create(&dest_path).unwrap();
|
||||||
|
file.write_all(generated_code.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use console::style;
|
use console::style;
|
||||||
|
use vnt::{ConnectInfo, ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo, VntCallback};
|
||||||
use vnt::handle::callback::{ConnectInfo, ErrorType};
|
|
||||||
use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct VntHandler {}
|
pub struct VntHandler {}
|
||||||
@@ -12,7 +10,8 @@ impl VntCallback for VntHandler {
|
|||||||
fn success(&self) {
|
fn success(&self) {
|
||||||
println!(" {} ", style("====== Connect Successfully ======").green())
|
println!(" {} ", style("====== Connect Successfully ======").green())
|
||||||
}
|
}
|
||||||
fn create_tun(&self, info: DeviceInfo) {
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
fn create_tun(&self, info: vnt::DeviceInfo) {
|
||||||
println!("create_tun {}", info)
|
println!("create_tun {}", info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +37,8 @@ impl VntCallback for VntHandler {
|
|||||||
| ErrorType::AddressExhausted
|
| ErrorType::AddressExhausted
|
||||||
| ErrorType::IpAlreadyExists
|
| ErrorType::IpAlreadyExists
|
||||||
| ErrorType::InvalidIp
|
| ErrorType::InvalidIp
|
||||||
| ErrorType::LocalIpExists => {
|
| ErrorType::LocalIpExists
|
||||||
|
| ErrorType::FailedToCrateDevice => {
|
||||||
self.stop();
|
self.stop();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -0,0 +1,620 @@
|
|||||||
|
use crate::args_parse::{ips_parse, out_ips_parse};
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
use crate::command;
|
||||||
|
use crate::{config, generated_serial_number};
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use console::style;
|
||||||
|
use getopts::Options;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use sys_locale::get_locale;
|
||||||
|
use vnt::channel::punch::PunchModel;
|
||||||
|
use vnt::channel::UseChannelType;
|
||||||
|
use vnt::cipher::CipherModel;
|
||||||
|
use vnt::compression::Compressor;
|
||||||
|
use vnt::core::Config;
|
||||||
|
|
||||||
|
pub fn app_home() -> io::Result<PathBuf> {
|
||||||
|
let root_path = match std::env::current_exe() {
|
||||||
|
Ok(path) => {
|
||||||
|
if let Some(v) = path.as_path().parent() {
|
||||||
|
v.to_path_buf()
|
||||||
|
} else {
|
||||||
|
log::warn!("current_exe parent none:{:?}", path);
|
||||||
|
PathBuf::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("current_exe err:{:?}", e);
|
||||||
|
PathBuf::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let path = root_path.join("env");
|
||||||
|
if !path.exists() {
|
||||||
|
std::fs::create_dir_all(&path)?;
|
||||||
|
}
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>> {
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
let _ = log4rs::init_file("log4rs.yaml", Default::default());
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
let program = args[0].clone();
|
||||||
|
let mut opts = Options::new();
|
||||||
|
opts.optopt("k", "", "组网标识", "<token>");
|
||||||
|
opts.optopt("n", "", "设备名称", "<name>");
|
||||||
|
opts.optopt("d", "", "设备标识", "<id>");
|
||||||
|
opts.optflag("c", "", "关闭交互式命令");
|
||||||
|
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
|
||||||
|
opts.optmulti("e", "", "stun服务器", "<stun-server>");
|
||||||
|
opts.optflag("a", "", "使用tap模式");
|
||||||
|
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
|
||||||
|
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
|
||||||
|
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
|
||||||
|
opts.optopt("w", "", "客户端加密", "<password>");
|
||||||
|
opts.optflag("W", "", "服务端加密");
|
||||||
|
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
||||||
|
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
|
||||||
|
opts.optflag("", "relay", "仅使用服务器转发");
|
||||||
|
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
|
||||||
|
opts.optopt("", "model", "加密模式", "<model>");
|
||||||
|
opts.optflag("", "finger", "指纹校验");
|
||||||
|
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
|
||||||
|
opts.optopt("", "ports", "监听的端口", "<port,port>");
|
||||||
|
opts.optflag("", "cmd", "开启窗口输入");
|
||||||
|
opts.optflag("", "no-proxy", "关闭内置代理");
|
||||||
|
opts.optflag("", "first-latency", "优先延迟");
|
||||||
|
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
|
||||||
|
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
|
||||||
|
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
|
||||||
|
opts.optmulti("", "dns", "dns", "<dns>");
|
||||||
|
opts.optmulti("", "mapping", "mapping", "<mapping>");
|
||||||
|
opts.optmulti("", "vnt-mapping", "vnt-mapping", "<mapping>");
|
||||||
|
opts.optopt("f", "", "配置文件", "<conf>");
|
||||||
|
opts.optopt("", "compressor", "压缩算法", "<lz4>");
|
||||||
|
opts.optopt("", "local-dev", "指定本地ipv4网卡名称", "<NAME>");
|
||||||
|
opts.optflag("", "disable-stats", "关闭流量统计");
|
||||||
|
opts.optflag("", "allow-wg", "允许接入WireGuard");
|
||||||
|
//"后台运行时,查看其他设备列表"
|
||||||
|
opts.optflag("", "add", "后台运行时,添加地址");
|
||||||
|
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
||||||
|
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
|
||||||
|
opts.optflag("", "info", "后台运行时,查看当前设备信息");
|
||||||
|
opts.optflag("", "route", "后台运行时,查看数据转发路径");
|
||||||
|
opts.optflag("", "chart_a", "后台运行时,查看流量统计");
|
||||||
|
opts.optopt("", "chart_b", "后台运行时,查看流量统计", "<IP>");
|
||||||
|
opts.optflag("", "stop", "停止后台运行");
|
||||||
|
opts.optflag("h", "help", "帮助");
|
||||||
|
let matches = match opts.parse(&args[1..]) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(f) => {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
return Err(anyhow::anyhow!("{}", f.to_string()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if matches.opt_present("h") || args.len() == 1 {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
if matches.opt_present("list") {
|
||||||
|
command::command(command::CommandEnum::List);
|
||||||
|
return Ok(None);
|
||||||
|
} else if matches.opt_present("info") {
|
||||||
|
command::command(command::CommandEnum::Info);
|
||||||
|
return Ok(None);
|
||||||
|
} else if matches.opt_present("stop") {
|
||||||
|
command::command(command::CommandEnum::Stop);
|
||||||
|
return Ok(None);
|
||||||
|
} else if matches.opt_present("route") {
|
||||||
|
command::command(command::CommandEnum::Route);
|
||||||
|
return Ok(None);
|
||||||
|
} else if matches.opt_present("all") {
|
||||||
|
command::command(command::CommandEnum::All);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
if matches.opt_present("chart_a") {
|
||||||
|
command::command(command::CommandEnum::ChartA);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
if let Some(v) = matches.opt_str("chart_b") {
|
||||||
|
command::command(command::CommandEnum::ChartB(v));
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let conf = matches.opt_str("f");
|
||||||
|
let (config, vnt_link_config, cmd) = if conf.is_some() {
|
||||||
|
match config::read_config(&conf.unwrap()) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(anyhow::anyhow!("conf err {}", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !matches.opt_present("k") {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
return Err(anyhow::anyhow!("parameter -k not found ."));
|
||||||
|
}
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
let device_name = matches.opt_str("nic");
|
||||||
|
let token: String = matches.opt_get("k").unwrap().unwrap();
|
||||||
|
let device_id = matches.opt_get_default("d", String::new()).unwrap();
|
||||||
|
let device_id = if device_id.is_empty() {
|
||||||
|
config::get_device_id()
|
||||||
|
} else {
|
||||||
|
device_id
|
||||||
|
};
|
||||||
|
if device_id.is_empty() {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
return Err(anyhow::anyhow!("parameter -d not found ."));
|
||||||
|
}
|
||||||
|
let name = matches
|
||||||
|
.opt_get_default(
|
||||||
|
"n",
|
||||||
|
gethostname::gethostname()
|
||||||
|
.to_str()
|
||||||
|
.unwrap_or("UnknownName")
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let server_address_str = matches
|
||||||
|
.opt_get_default("s", "vnt.wherewego.top:29872".to_string())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut stun_server = matches.opt_strs("e");
|
||||||
|
if stun_server.is_empty() {
|
||||||
|
for x in config::PUB_STUN {
|
||||||
|
stun_server.push(x.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dns = matches.opt_strs("dns");
|
||||||
|
let in_ip = matches.opt_strs("i");
|
||||||
|
let in_ip = match ips_parse(&in_ip) {
|
||||||
|
Ok(in_ip) => in_ip,
|
||||||
|
Err(e) => {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
println!();
|
||||||
|
println!("-i: {:?} {}", in_ip, e);
|
||||||
|
return Err(anyhow::anyhow!("example: -i 192.168.0.0/24,10.26.0.3"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let out_ip = matches.opt_strs("o");
|
||||||
|
let out_ip = match out_ips_parse(&out_ip) {
|
||||||
|
Ok(out_ip) => out_ip,
|
||||||
|
Err(e) => {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
println!();
|
||||||
|
println!("-o: {:?} {}", out_ip, e);
|
||||||
|
return Err(anyhow::anyhow!("example: -o 0.0.0.0/0"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let password: Option<String> = matches.opt_get("w").unwrap();
|
||||||
|
let server_encrypt = matches.opt_present("W");
|
||||||
|
#[cfg(not(feature = "server_encrypt"))]
|
||||||
|
{
|
||||||
|
if server_encrypt {
|
||||||
|
println!("Server encryption not supported");
|
||||||
|
return Err(anyhow::anyhow!("Server encryption not supported"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mtu: Option<String> = matches.opt_get("u").unwrap();
|
||||||
|
let mtu = if let Some(mtu) = mtu {
|
||||||
|
match u32::from_str(&mtu) {
|
||||||
|
Ok(mtu) => Some(mtu),
|
||||||
|
Err(e) => {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
println!();
|
||||||
|
println!("'-u {}' {}", mtu, e);
|
||||||
|
return Err(anyhow::anyhow!("'-u {}' {}", mtu, e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
|
||||||
|
let virtual_ip =
|
||||||
|
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
|
||||||
|
if let Some(virtual_ip) = virtual_ip {
|
||||||
|
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
|
||||||
|
{
|
||||||
|
return Err(anyhow::anyhow!("'--ip {}' invalid", virtual_ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let relay = matches.opt_present("relay");
|
||||||
|
|
||||||
|
let cipher_model = match matches.opt_get::<CipherModel>("model") {
|
||||||
|
Ok(model) => {
|
||||||
|
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
||||||
|
{
|
||||||
|
if password.is_some() && model.is_none() {
|
||||||
|
return Err(anyhow::anyhow!("'--model ' undefined"));
|
||||||
|
}
|
||||||
|
model.unwrap_or(CipherModel::None)
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
|
model.unwrap_or(CipherModel::AesGcm)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(anyhow::anyhow!("'--model ' invalid,{}", e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let finger = matches.opt_present("finger");
|
||||||
|
let punch_model = matches
|
||||||
|
.opt_get::<PunchModel>("punch")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap_or(PunchModel::All);
|
||||||
|
let use_channel_type = matches
|
||||||
|
.opt_get::<UseChannelType>("use-channel")
|
||||||
|
.unwrap()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
if relay {
|
||||||
|
UseChannelType::Relay
|
||||||
|
} else {
|
||||||
|
UseChannelType::All
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let ports = matches
|
||||||
|
.opt_get::<String>("ports")
|
||||||
|
.unwrap_or(None)
|
||||||
|
.map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect());
|
||||||
|
|
||||||
|
let cmd = matches.opt_present("cmd");
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
let no_proxy = matches.opt_present("no-proxy");
|
||||||
|
let first_latency = matches.opt_present("first-latency");
|
||||||
|
let packet_loss = matches
|
||||||
|
.opt_get::<f64>("packet-loss")
|
||||||
|
.expect("--packet-loss");
|
||||||
|
let packet_delay = matches
|
||||||
|
.opt_get::<u32>("packet-delay")
|
||||||
|
.expect("--packet-delay")
|
||||||
|
.unwrap_or(0);
|
||||||
|
#[cfg(feature = "port_mapping")]
|
||||||
|
let port_mapping_list = matches.opt_strs("mapping");
|
||||||
|
let vnt_mapping_list = matches.opt_strs("vnt-mapping");
|
||||||
|
let local_dev: Option<String> = matches.opt_get("local-dev").unwrap();
|
||||||
|
|
||||||
|
let disable_stats = matches.opt_present("disable-stats");
|
||||||
|
let allow_wire_guard = matches.opt_present("allow-wg");
|
||||||
|
let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() {
|
||||||
|
Compressor::from_str(compressor)
|
||||||
|
.map_err(|e| anyhow!("{}", e))
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
Compressor::None
|
||||||
|
};
|
||||||
|
let config = Config::new(
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
false,
|
||||||
|
token,
|
||||||
|
device_id,
|
||||||
|
name,
|
||||||
|
server_address_str,
|
||||||
|
dns,
|
||||||
|
stun_server,
|
||||||
|
in_ip,
|
||||||
|
out_ip,
|
||||||
|
password,
|
||||||
|
mtu,
|
||||||
|
virtual_ip,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
no_proxy,
|
||||||
|
server_encrypt,
|
||||||
|
cipher_model,
|
||||||
|
finger,
|
||||||
|
punch_model,
|
||||||
|
ports,
|
||||||
|
first_latency,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
device_name,
|
||||||
|
use_channel_type,
|
||||||
|
packet_loss,
|
||||||
|
packet_delay,
|
||||||
|
#[cfg(feature = "port_mapping")]
|
||||||
|
port_mapping_list,
|
||||||
|
compressor,
|
||||||
|
!disable_stats,
|
||||||
|
allow_wire_guard,
|
||||||
|
local_dev,
|
||||||
|
)?;
|
||||||
|
(config, vnt_mapping_list, cmd)
|
||||||
|
};
|
||||||
|
println!("version {}", vnt::VNT_VERSION);
|
||||||
|
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
||||||
|
log::info!(
|
||||||
|
"version:{},Serial:{}",
|
||||||
|
vnt::VNT_VERSION,
|
||||||
|
generated_serial_number::SERIAL_NUMBER
|
||||||
|
);
|
||||||
|
Ok(Some((config, vnt_link_config, cmd)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_description(key: &str, language: &str) -> String {
|
||||||
|
// 设置一个全局的映射来存储中英文对照
|
||||||
|
let descriptions: HashMap<&str, (&str, &str)> = [
|
||||||
|
("-k <token>", ("使用相同的token,就能组建一个局域网络", "Use the same token to form a local network")),
|
||||||
|
("-n <name>", ("给设备一个名字,便于区分不同设备,默认使用系统版本", "Give the device a name to distinguish it, defaults to system version")),
|
||||||
|
("-d <id>", ("设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复", "Device unique identifier, used by the server to allocate virtual IP when --ip parameter is not used, must be unique")),
|
||||||
|
("-s <server>", ("注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://", "Registration and relay server address, protocols support using tcp://, ws://, and wss://, default is udp://")),
|
||||||
|
("-e <stun-server>", ("stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com", "STUN server for detecting NAT type, can specify multiple addresses, e.g., -e stun.miwifi.com -e turn.cloudflare.com")),
|
||||||
|
("-i <in-ip>", ("配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3,可指定多个网段", "Used when configuring point-to-point network (IP proxy), -i 192.168.0.0/24,10.26.0.3 allows receiving data from subnet 192.168.0.0/24 and forwarding to 10.26.0.3, specify multiple subnets")),
|
||||||
|
("-o <out-ip>", ("配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段", "Used when configuring point-to-point network, -o 192.168.0.0/24 allows forwarding data to 192.168.0.0/24, specify multiple subnets")),
|
||||||
|
("-w <password>", ("使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "Encrypt client data with keys generated by this password, server cannot decrypt, clients must use the same password to communicate")),
|
||||||
|
("-W", ("加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确", "Encrypt the data currently being communicated between the client and server, please pay attention to whether the server fingerprint is correct")),
|
||||||
|
("-u <mtu>", ("自定义mtu(默认为1420)", "Customize MTU (default is 1420)")),
|
||||||
|
("-f <conf_file>", ("读取配置文件中的配置", "Read configuration from file")),
|
||||||
|
("--ip <ip>", ("指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配", "Specify virtual IP, must be unique and valid within server subnet, by default allocated by server")),
|
||||||
|
("--model <model>", ("加密模式(默认aes_gcm),可选值", "Encryption mode (default aes_gcm), options ")),
|
||||||
|
("--finger", ("增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启", "Add data fingerprint verification for increased security, client must enable if server does")),
|
||||||
|
("--punch <punch>", ("取值ipv4/ipv6/ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-udp/all,ipv4表示仅使用ipv4打洞", "Values ipv4/ipv6/ipv4-tcp/ipv4-udp/ipv6-tcp/ipv6-udp/all, ipv4 for IPv4 hole punching only")),
|
||||||
|
("--ports <port,port>", ("取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担", "Values 0~65535, specify a group of local listening ports, defaults to two random ports, using many ports increases network load")),
|
||||||
|
("--cmd", ("开启交互式命令,使用此参数开启控制台输入", "Enable interactive command mode, use this parameter to enable console input")),
|
||||||
|
("--no-proxy", ("关闭内置代理,如需点对网则需要配置网卡NAT转发", "Disable built-in proxy, configure network card NAT forwarding for point-to-point networking")),
|
||||||
|
("--first-latency", ("优先低延迟的通道,默认情况优先使用p2p通道", "Prioritize low-latency channels, defaults to prioritizing p2p channel")),
|
||||||
|
("--use-channel <p2p>", ("使用通道 relay/p2p/all,默认两者都使用", "Use channel relay/p2p/all, defaults to using both")),
|
||||||
|
("--nic <tun0>", ("指定虚拟网卡名称", "Specify virtual network card name")),
|
||||||
|
("--packet-loss <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate packet loss, value between 0 and 1, program actively drops packets based on set probability, useful for simulating weak networks")),
|
||||||
|
("--packet-delay <0>", ("模拟延迟,正整数,单位毫秒,程序将根据设定值延迟发送数据包,可用于模拟弱网", "Simulate latency, integer, in milliseconds (ms). The program will delay sending packets according to the set value and can be used to simulate weak networks")),
|
||||||
|
("--dns <host:port>", ("DNS服务器地址,可使用多个dns,不指定时使用系统解析", "DNS server address, can specify multiple DNS servers, defaults to system resolution if not specified")),
|
||||||
|
("--mapping <mapping>", ("端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备", "Port mapping, e.g., --mapping udp:0.0.0.0:80-domain:80 maps to a device accessible by local routing")),
|
||||||
|
("--compressor-all <lz4>", ("启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10", "Enable compression, options lz4/zstd<,level>, level is compression level, e.g., --compressor lz4 or --compressor zstd,10")),
|
||||||
|
("--compressor-lz4 <lz4>", ("启用压缩,可选值lz4,例如 --compressor lz4", "Enable compression, option lz4, e.g., --compressor lz4")),
|
||||||
|
("--compressor-zstd <zstd>", ("启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10", "Enable compression, options zstd<,level>, level is compression level, e.g., --compressor zstd,10")),
|
||||||
|
("--vnt-mapping <x>", ("vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备", "VNT address mapping, e.g., --vnt-mapping tcp:80-10.26.0.10:80 maps to a device in VNT network or its subnet")),
|
||||||
|
("--local-dev", ("本地出口网卡的名称", "name of local export network card")),
|
||||||
|
("--disable-stats", ("关闭流量统计", "Disable traffic statistics")),
|
||||||
|
("--allow-wg", ("允许接入WireGuard客户端", "Allow access to WireGuard client")),
|
||||||
|
("--list", ("后台运行时,查看其他设备列表", "View list of other devices when running in background")),
|
||||||
|
("--all", ("后台运行时,查看其他设备完整信息", "View complete information of other devices when running in background")),
|
||||||
|
("--info", ("后台运行时,查看当前设备信息", "View information of current device when running in background")),
|
||||||
|
("--route", ("后台运行时,查看数据转发路径", "View data forwarding path when running in background")),
|
||||||
|
("--chart_a", ("后台运行时,查看所有IP的流量统计", "View traffic statistics of all IPs when running in background")),
|
||||||
|
("--chart_b <IP>", ("后台运行时,查看单个IP的历史流量", "View historical traffic of a single IP when running in background")),
|
||||||
|
("--stop", ("停止后台运行", "Stop running in background"))
|
||||||
|
// ... 其他选项
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if let Some(&(zh, en)) = descriptions.get(key) {
|
||||||
|
if language.starts_with("zh") {
|
||||||
|
return zh.to_string(); // 返回 String 类型
|
||||||
|
}
|
||||||
|
// 默认返回英文
|
||||||
|
return en.to_string(); // 返回 String 类型
|
||||||
|
}
|
||||||
|
// 如果没有找到对应的键,则返回空字符串
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_usage(program: &str, _opts: Options) {
|
||||||
|
// 获取系统语言 Locale::user_default().unwrap_or_else(|_| Locale::default());
|
||||||
|
let language = get_locale().unwrap_or_else(|| String::from("en-US"));
|
||||||
|
println!("Usage: {} [options]", program);
|
||||||
|
println!("version:{}", vnt::VNT_VERSION);
|
||||||
|
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
||||||
|
println!("Options:");
|
||||||
|
println!(
|
||||||
|
" -k <token> {}",
|
||||||
|
green(get_description("-k <token>", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" -n <name> {}",
|
||||||
|
get_description("-n <name>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" -d <id> {}",
|
||||||
|
get_description("-d <id>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" -s <server> {}",
|
||||||
|
get_description("-s <server>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" -e <stun-server> {}",
|
||||||
|
get_description("-e <stun-server>", &language)
|
||||||
|
);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
" -i <in-ip> {}",
|
||||||
|
get_description("-i <in-ip>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" -o <out-ip> {}",
|
||||||
|
get_description("-o <out-ip>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" -w <password> {}",
|
||||||
|
get_description("-w <password>", &language)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "server_encrypt")]
|
||||||
|
println!(" -W {}", get_description("-W", &language));
|
||||||
|
println!(
|
||||||
|
" -u <mtu> {}",
|
||||||
|
get_description("-u <mtu>", &language)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "file_config")]
|
||||||
|
println!(
|
||||||
|
" -f <conf_file> {}",
|
||||||
|
get_description("-f <conf_file>", &language)
|
||||||
|
);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
" --ip <ip> {}",
|
||||||
|
get_description("--ip <ip>", &language)
|
||||||
|
);
|
||||||
|
let mut enums = String::new();
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
|
enums.push_str("/aes_gcm");
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
enums.push_str("/chacha20_poly1305/chacha20");
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
|
enums.push_str("/aes_cbc");
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
|
enums.push_str("/aes_ecb");
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
enums.push_str("/sm4_cbc");
|
||||||
|
enums.push_str("/xor");
|
||||||
|
println!(
|
||||||
|
" --model <model> {}{}",
|
||||||
|
get_description("--model <model>", &language),
|
||||||
|
&enums[1..]
|
||||||
|
);
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "aes_gcm",
|
||||||
|
feature = "chacha20_poly1305",
|
||||||
|
feature = "server_encrypt",
|
||||||
|
feature = "aes_cbc",
|
||||||
|
feature = "aes_ecb",
|
||||||
|
feature = "sm4_cbc"
|
||||||
|
))]
|
||||||
|
println!(
|
||||||
|
" --finger {}",
|
||||||
|
get_description("--finger", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --punch <punch> {}",
|
||||||
|
get_description("--punch <punch>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --ports <port,port> {}",
|
||||||
|
get_description("--ports <port,port>", &language)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
println!(
|
||||||
|
" --cmd {}",
|
||||||
|
get_description("--cmd", &language)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
println!(
|
||||||
|
" --no-proxy {}",
|
||||||
|
get_description("--no-proxy", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --first-latency {}",
|
||||||
|
get_description("--first-latency", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --use-channel <p2p> {}",
|
||||||
|
get_description("--use-channel <p2p>", &language)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
println!(
|
||||||
|
" --nic <tun0> {}",
|
||||||
|
get_description("--nic <tun0>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --packet-loss <0> {}",
|
||||||
|
get_description("--packet-loss <0>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --packet-delay <0> {}",
|
||||||
|
get_description("--packet-delay <0>", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --dns <host:port> {}",
|
||||||
|
get_description("--dns <host:port>", &language)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "port_mapping")]
|
||||||
|
println!(
|
||||||
|
" --mapping <mapping> {}",
|
||||||
|
get_description("--mapping <mapping>", &language)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(all(feature = "lz4", feature = "zstd"))]
|
||||||
|
println!(
|
||||||
|
" --compressor <lz4> {}",
|
||||||
|
get_description("--compressor-all <lz4>", &language)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "lz4")]
|
||||||
|
#[cfg(not(feature = "zstd"))]
|
||||||
|
println!(
|
||||||
|
" --compressor <lz4> {}",
|
||||||
|
get_description("--compressor-lz4 <lz4>", &language)
|
||||||
|
);
|
||||||
|
#[cfg(feature = "zstd")]
|
||||||
|
#[cfg(not(feature = "lz4"))]
|
||||||
|
println!(
|
||||||
|
" --compressor <zstd> {}",
|
||||||
|
get_description("--compressor-zstd <zstd>", &language)
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "integrated_tun"))]
|
||||||
|
println!(
|
||||||
|
" --vnt-mapping <x> {}",
|
||||||
|
green(get_description("--vnt-mapping <x>", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --local-dev <NAME> {}",
|
||||||
|
get_description("--local-dev", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --disable-stats {}",
|
||||||
|
get_description("--disable-stats", &language)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --allow-wg {}",
|
||||||
|
get_description("--allow-wg", &language)
|
||||||
|
);
|
||||||
|
println!();
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
{
|
||||||
|
// #[cfg(not(feature = "integrated_tun"))]
|
||||||
|
// println!(
|
||||||
|
// " --add {}",
|
||||||
|
// yellow("后台运行时,添加VNT地址映射 用法同'--vnt-mapping'".to_string())
|
||||||
|
// );
|
||||||
|
println!(
|
||||||
|
" --list {}",
|
||||||
|
yellow(get_description("--list", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --all {}",
|
||||||
|
yellow(get_description("--all", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --info {}",
|
||||||
|
yellow(get_description("--info", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --route {}",
|
||||||
|
yellow(get_description("--route", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --chart_a {}",
|
||||||
|
yellow(get_description("--chart_a", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --chart_b <IP> {}",
|
||||||
|
yellow(get_description("--chart_b <IP>", &language).to_string())
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" --stop {}",
|
||||||
|
yellow(get_description("--stop", &language).to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!(" -h, --help display help information(显示帮助信息)");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn green(str: String) -> impl std::fmt::Display {
|
||||||
|
style(str).green()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
fn yellow(str: String) -> impl std::fmt::Display {
|
||||||
|
style(str).yellow()
|
||||||
|
}
|
||||||
@@ -4,10 +4,10 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::command::entity::{DeviceItem, Info, RouteItem};
|
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
|
||||||
|
|
||||||
pub struct CommandClient {
|
pub struct CommandClient {
|
||||||
buf: [u8; 10240],
|
buf: Vec<u8>,
|
||||||
udp: UdpSocket,
|
udp: UdpSocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,12 +25,12 @@ impl CommandClient {
|
|||||||
)))?;
|
)))?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
udp,
|
udp,
|
||||||
buf: [0; 10240],
|
buf: vec![0; 65536 * 8],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn read_command_port() -> io::Result<u16> {
|
fn read_command_port() -> io::Result<u16> {
|
||||||
let path_buf = crate::app_home()?.join("command-port");
|
let path_buf = crate::cli::app_home()?.join("command-port");
|
||||||
let port = std::fs::read_to_string(path_buf)?;
|
let port = std::fs::read_to_string(path_buf)?;
|
||||||
match u16::from_str(&port) {
|
match u16::from_str(&port) {
|
||||||
Ok(port) => Ok(port),
|
Ok(port) => Ok(port),
|
||||||
@@ -53,14 +53,33 @@ impl CommandClient {
|
|||||||
pub fn info(&mut self) -> io::Result<Info> {
|
pub fn info(&mut self) -> io::Result<Info> {
|
||||||
self.send_cmd(b"info")
|
self.send_cmd(b"info")
|
||||||
}
|
}
|
||||||
|
pub fn chart_a(&mut self) -> io::Result<ChartA> {
|
||||||
|
self.send_cmd(b"chart_a")
|
||||||
|
}
|
||||||
|
pub fn chart_b(&mut self, input: &str) -> io::Result<ChartB> {
|
||||||
|
let cmd = if input.is_empty() {
|
||||||
|
"chart_b".to_string()
|
||||||
|
} else {
|
||||||
|
format!("chart_b:{}", input)
|
||||||
|
};
|
||||||
|
self.send_cmd(cmd.as_bytes())
|
||||||
|
}
|
||||||
fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result<V> {
|
fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result<V> {
|
||||||
self.udp.send(cmd)?;
|
self.udp.send(cmd)?;
|
||||||
let len = self.udp.recv(&mut self.buf)?;
|
let len = self.udp.recv(&mut self.buf)?;
|
||||||
match serde_yaml::from_slice::<V>(&self.buf[..len]) {
|
match serde_yaml::from_slice::<V>(&self.buf[..len]) {
|
||||||
Ok(val) => Ok(val),
|
Ok(val) => Ok(val),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{:?},{:?}", &self.buf[..len], e);
|
log::error!(
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "data error"))
|
"send_cmd {:?} {:?},{:?}",
|
||||||
|
std::str::from_utf8(cmd),
|
||||||
|
std::str::from_utf8(&self.buf[..len]),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("data error {:?} buf_len={}", e, len),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -12,11 +14,11 @@ pub struct Info {
|
|||||||
pub public_ips: String,
|
pub public_ips: String,
|
||||||
pub local_addr: String,
|
pub local_addr: String,
|
||||||
pub ipv6_addr: String,
|
pub ipv6_addr: String,
|
||||||
pub up: u64,
|
|
||||||
pub down: u64,
|
|
||||||
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
|
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
|
||||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
pub out_ips: Vec<(u32, u32)>,
|
pub out_ips: Vec<(u32, u32)>,
|
||||||
|
pub udp_listen_addr: Vec<String>,
|
||||||
|
pub tcp_listen_addr: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@@ -43,4 +45,24 @@ pub struct DeviceItem {
|
|||||||
pub client_secret_hash: Vec<u8>,
|
pub client_secret_hash: Vec<u8>,
|
||||||
pub current_client_secret: bool,
|
pub current_client_secret: bool,
|
||||||
pub current_client_secret_hash: Vec<u8>,
|
pub current_client_secret_hash: Vec<u8>,
|
||||||
|
pub wire_guard: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
pub struct ChartA {
|
||||||
|
pub disable_stats: bool,
|
||||||
|
pub up_total: u64,
|
||||||
|
pub down_total: u64,
|
||||||
|
pub up_map: HashMap<Ipv4Addr, u64>,
|
||||||
|
pub down_map: HashMap<Ipv4Addr, u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
pub struct ChartB {
|
||||||
|
pub disable_stats: bool,
|
||||||
|
pub ip: Option<Ipv4Addr>,
|
||||||
|
pub up_total: u64,
|
||||||
|
pub up_list: Vec<usize>,
|
||||||
|
pub down_total: u64,
|
||||||
|
pub down_list: Vec<usize>,
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use vnt::channel::ConnectProtocol;
|
||||||
use vnt::core::Vnt;
|
use vnt::core::Vnt;
|
||||||
|
|
||||||
use crate::command::entity::{DeviceItem, Info, RouteItem};
|
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
|
||||||
use crate::console_out;
|
use crate::console_out;
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
@@ -13,9 +16,56 @@ pub enum CommandEnum {
|
|||||||
List,
|
List,
|
||||||
All,
|
All,
|
||||||
Info,
|
Info,
|
||||||
|
ChartA,
|
||||||
|
ChartB(String),
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn command_str(cmd: &str, vnt: &Vnt) -> bool {
|
||||||
|
if cmd.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let cmd = cmd.to_lowercase();
|
||||||
|
let cmd = cmd.trim();
|
||||||
|
match cmd {
|
||||||
|
"list" => {
|
||||||
|
let list = command_list(&vnt);
|
||||||
|
console_out::console_device_list(list);
|
||||||
|
}
|
||||||
|
"info" => {
|
||||||
|
let info = command_info(&vnt);
|
||||||
|
console_out::console_info(info);
|
||||||
|
}
|
||||||
|
"route" => {
|
||||||
|
let route = command_route(&vnt);
|
||||||
|
console_out::console_route_table(route);
|
||||||
|
}
|
||||||
|
"all" => {
|
||||||
|
let list = command_list(&vnt);
|
||||||
|
console_out::console_device_list_all(list);
|
||||||
|
}
|
||||||
|
"chart_a" => {
|
||||||
|
let chart = command_chart_a(&vnt);
|
||||||
|
console_out::console_chart_a(chart);
|
||||||
|
}
|
||||||
|
"stop" => {
|
||||||
|
let _ = vnt.stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
if let Some(ip) = cmd.strip_prefix("chart_b") {
|
||||||
|
let chart = if ip.is_empty() {
|
||||||
|
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
|
||||||
|
} else {
|
||||||
|
command_chart_b(&vnt, &ip[1..])
|
||||||
|
};
|
||||||
|
console_out::console_chart_b(chart);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn command(cmd: CommandEnum) {
|
pub fn command(cmd: CommandEnum) {
|
||||||
if let Err(e) = command_(cmd) {
|
if let Err(e) = command_(cmd) {
|
||||||
println!("cmd: {:?}", e);
|
println!("cmd: {:?}", e);
|
||||||
@@ -41,6 +91,14 @@ fn command_(cmd: CommandEnum) -> io::Result<()> {
|
|||||||
let info = command_client.info()?;
|
let info = command_client.info()?;
|
||||||
console_out::console_info(info);
|
console_out::console_info(info);
|
||||||
}
|
}
|
||||||
|
CommandEnum::ChartA => {
|
||||||
|
let chart = command_client.chart_a()?;
|
||||||
|
console_out::console_chart_a(chart);
|
||||||
|
}
|
||||||
|
CommandEnum::ChartB(input) => {
|
||||||
|
let chart = command_client.chart_b(&input)?;
|
||||||
|
console_out::console_chart_b(chart);
|
||||||
|
}
|
||||||
CommandEnum::Stop => {
|
CommandEnum::Stop => {
|
||||||
command_client.stop()?;
|
command_client.stop()?;
|
||||||
}
|
}
|
||||||
@@ -50,6 +108,7 @@ fn command_(cmd: CommandEnum) -> io::Result<()> {
|
|||||||
|
|
||||||
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
|
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
|
||||||
let route_table = vnt.route_table();
|
let route_table = vnt.route_table();
|
||||||
|
let server_addr = vnt.config().server_address_str.clone();
|
||||||
let mut route_list = Vec::with_capacity(route_table.len());
|
let mut route_list = Vec::with_capacity(route_table.len());
|
||||||
for (destination, routes) in route_table {
|
for (destination, routes) in route_table {
|
||||||
for route in routes {
|
for route in routes {
|
||||||
@@ -62,11 +121,14 @@ pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
|
|||||||
} else {
|
} else {
|
||||||
route.rt.to_string()
|
route.rt.to_string()
|
||||||
};
|
};
|
||||||
let interface = if route.is_tcp {
|
let interface = match route.protocol {
|
||||||
format!("tcp@{}", route.addr)
|
ConnectProtocol::UDP => route.addr.to_string(),
|
||||||
} else {
|
ConnectProtocol::TCP => {
|
||||||
route.addr.to_string()
|
format!("tcp@{}", route.addr)
|
||||||
|
}
|
||||||
|
ConnectProtocol::WS | ConnectProtocol::WSS => server_addr.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let item = RouteItem {
|
let item = RouteItem {
|
||||||
destination: destination.to_string(),
|
destination: destination.to_string(),
|
||||||
next_hop,
|
next_hop,
|
||||||
@@ -114,7 +176,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
|||||||
};
|
};
|
||||||
let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
||||||
let nat_traversal_type = if route.metric == 1 {
|
let nat_traversal_type = if route.metric == 1 {
|
||||||
if route.is_tcp {
|
if route.protocol.is_base_tcp() {
|
||||||
"tcp-p2p"
|
"tcp-p2p"
|
||||||
} else {
|
} else {
|
||||||
"p2p"
|
"p2p"
|
||||||
@@ -157,6 +219,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
|||||||
client_secret_hash: peer.client_secret_hash,
|
client_secret_hash: peer.client_secret_hash,
|
||||||
current_client_secret,
|
current_client_secret,
|
||||||
current_client_secret_hash: client_encrypt_hash.to_vec(),
|
current_client_secret_hash: client_encrypt_hash.to_vec(),
|
||||||
|
wire_guard: peer.wireguard,
|
||||||
};
|
};
|
||||||
list.push(item);
|
list.push(item);
|
||||||
}
|
}
|
||||||
@@ -164,6 +227,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn command_info(vnt: &Vnt) -> Info {
|
pub fn command_info(vnt: &Vnt) -> Info {
|
||||||
|
let config = vnt.config();
|
||||||
let current_device = vnt.current_device();
|
let current_device = vnt.current_device();
|
||||||
let nat_info = vnt.nat_info();
|
let nat_info = vnt.nat_info();
|
||||||
let name = vnt.name().to_string();
|
let name = vnt.name().to_string();
|
||||||
@@ -171,7 +235,11 @@ pub fn command_info(vnt: &Vnt) -> Info {
|
|||||||
let virtual_gateway = current_device.virtual_gateway().to_string();
|
let virtual_gateway = current_device.virtual_gateway().to_string();
|
||||||
let virtual_netmask = current_device.virtual_netmask.to_string();
|
let virtual_netmask = current_device.virtual_netmask.to_string();
|
||||||
let connect_status = format!("{:?}", vnt.connection_status());
|
let connect_status = format!("{:?}", vnt.connection_status());
|
||||||
let relay_server = current_device.connect_server.to_string();
|
let relay_server = if current_device.connect_server.port() == 0 {
|
||||||
|
config.server_address_str.clone()
|
||||||
|
} else {
|
||||||
|
current_device.connect_server.to_string()
|
||||||
|
};
|
||||||
let nat_type = format!("{:?}", nat_info.nat_type);
|
let 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: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
|
||||||
let public_ips = public_ips.join(",");
|
let public_ips = public_ips.join(",");
|
||||||
@@ -183,14 +251,18 @@ pub fn command_info(vnt: &Vnt) -> Info {
|
|||||||
.ipv6()
|
.ipv6()
|
||||||
.map(|v| v.to_string())
|
.map(|v| v.to_string())
|
||||||
.unwrap_or("None".to_string());
|
.unwrap_or("None".to_string());
|
||||||
let up = vnt.up_stream();
|
|
||||||
let down = vnt.down_stream();
|
|
||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
let port_mapping_list = vnt.config().port_mapping_list.clone();
|
let port_mapping_list = vnt.config().port_mapping_list.clone();
|
||||||
#[cfg(not(feature = "port_mapping"))]
|
#[cfg(not(feature = "port_mapping"))]
|
||||||
let port_mapping_list = vec![];
|
let port_mapping_list = vec![];
|
||||||
let in_ips = vnt.config().in_ips.clone();
|
let in_ips = vnt.config().in_ips.clone();
|
||||||
let out_ips = vnt.config().out_ips.clone();
|
let out_ips = vnt.config().out_ips.clone();
|
||||||
|
let udp_listen_addr = nat_info
|
||||||
|
.udp_ports
|
||||||
|
.iter()
|
||||||
|
.map(|port| format!("0.0.0.0:{}", port))
|
||||||
|
.collect();
|
||||||
|
let tcp_listen_addr = format!("0.0.0.0:{}", nat_info.tcp_port);
|
||||||
Info {
|
Info {
|
||||||
name,
|
name,
|
||||||
virtual_ip,
|
virtual_ip,
|
||||||
@@ -202,10 +274,80 @@ pub fn command_info(vnt: &Vnt) -> Info {
|
|||||||
public_ips,
|
public_ips,
|
||||||
local_addr,
|
local_addr,
|
||||||
ipv6_addr,
|
ipv6_addr,
|
||||||
up,
|
|
||||||
down,
|
|
||||||
port_mapping_list,
|
port_mapping_list,
|
||||||
in_ips,
|
in_ips,
|
||||||
out_ips,
|
out_ips,
|
||||||
|
udp_listen_addr,
|
||||||
|
tcp_listen_addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn command_chart_a(vnt: &Vnt) -> ChartA {
|
||||||
|
let disable_stats = !vnt.config().enable_traffic;
|
||||||
|
if disable_stats {
|
||||||
|
let mut chart = ChartA::default();
|
||||||
|
chart.disable_stats = true;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
let (up_total, up_map) = vnt.up_stream_all().unwrap_or_default();
|
||||||
|
let (down_total, down_map) = vnt.down_stream_all().unwrap_or_default();
|
||||||
|
ChartA {
|
||||||
|
disable_stats,
|
||||||
|
up_total,
|
||||||
|
down_total,
|
||||||
|
up_map,
|
||||||
|
down_map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn command_chart_b(vnt: &Vnt, input_str: &str) -> ChartB {
|
||||||
|
let disable_stats = !vnt.config().enable_traffic;
|
||||||
|
if disable_stats {
|
||||||
|
let mut chart = ChartB::default();
|
||||||
|
chart.disable_stats = true;
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
let (_, up_map) = vnt.up_stream_history().unwrap_or_default();
|
||||||
|
let (_, down_map) = vnt.down_stream_history().unwrap_or_default();
|
||||||
|
let up_keys: HashSet<_> = up_map.keys().cloned().collect();
|
||||||
|
let down_keys: HashSet<_> = down_map.keys().cloned().collect();
|
||||||
|
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
|
||||||
|
keys.sort();
|
||||||
|
if let Some(ip) = find_matching_ipv4_address(input_str, &keys) {
|
||||||
|
let (up_total, up_list) = up_map.get(&ip).cloned().unwrap_or_default();
|
||||||
|
let (down_total, down_list) = down_map.get(&ip).cloned().unwrap_or_default();
|
||||||
|
ChartB {
|
||||||
|
disable_stats,
|
||||||
|
ip: Some(ip),
|
||||||
|
up_total,
|
||||||
|
up_list,
|
||||||
|
down_total,
|
||||||
|
down_list,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ChartB::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_from_end(input_str: &str, ip: &str) -> bool {
|
||||||
|
let mut input_chars = input_str.chars().rev();
|
||||||
|
let mut ip_chars = ip.chars().rev();
|
||||||
|
|
||||||
|
while let (Some(ic), Some(pc)) = (input_chars.next(), ip_chars.next()) {
|
||||||
|
if ic != pc {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input_chars.next().is_none() // Ensure all input characters matched
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_matching_ipv4_address(input_str: &str, ip_addresses: &[Ipv4Addr]) -> Option<Ipv4Addr> {
|
||||||
|
for &ip in ip_addresses {
|
||||||
|
let ip_str = ip.to_string();
|
||||||
|
if match_from_end(input_str, &ip_str) {
|
||||||
|
return Some(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
use crate::command::command_chart_b;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
|
|
||||||
use vnt::core::Vnt;
|
use vnt::core::Vnt;
|
||||||
|
|
||||||
pub struct CommandServer {}
|
pub struct CommandServer {}
|
||||||
@@ -48,7 +48,7 @@ impl CommandServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn save_port(port: u16) -> io::Result<()> {
|
fn save_port(port: u16) -> io::Result<()> {
|
||||||
let path_buf = crate::app_home()?.join("command-port");
|
let path_buf = crate::cli::app_home()?.join("command-port");
|
||||||
let mut file = std::fs::File::create(path_buf)?;
|
let mut file = std::fs::File::create(path_buf)?;
|
||||||
file.write_all(port.to_string().as_bytes())?;
|
file.write_all(port.to_string().as_bytes())?;
|
||||||
file.sync_all()
|
file.sync_all()
|
||||||
@@ -63,15 +63,26 @@ fn command(cmd: &str, vnt: &Vnt) -> io::Result<String> {
|
|||||||
.unwrap_or_else(|e| format!("error {:?}", e)),
|
.unwrap_or_else(|e| format!("error {:?}", e)),
|
||||||
"info" => serde_yaml::to_string(&crate::command::command_info(vnt))
|
"info" => serde_yaml::to_string(&crate::command::command_info(vnt))
|
||||||
.unwrap_or_else(|e| format!("error {:?}", e)),
|
.unwrap_or_else(|e| format!("error {:?}", e)),
|
||||||
|
"chart_a" => serde_yaml::to_string(&crate::command::command_chart_a(vnt))
|
||||||
|
.unwrap_or_else(|e| format!("error {:?}", e)),
|
||||||
"stop" => {
|
"stop" => {
|
||||||
vnt.stop();
|
vnt.stop();
|
||||||
"stopped".to_string()
|
"stopped".to_string()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
format!(
|
if let Some(ip) = cmd.strip_prefix("chart_b") {
|
||||||
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
|
let chart = if ip.is_empty() {
|
||||||
cmd
|
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
|
||||||
)
|
} else {
|
||||||
|
command_chart_b(&vnt, &ip[1..])
|
||||||
|
};
|
||||||
|
serde_yaml::to_string(&chart).unwrap_or_else(|e| format!("error {:?}", e))
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
|
||||||
|
cmd
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(out_str)
|
Ok(out_str)
|
||||||
@@ -2,9 +2,9 @@ use anyhow::anyhow;
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::config::get_device_id;
|
use crate::config::get_device_id;
|
||||||
|
use crate::{args_parse, config};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use vnt::channel::punch::PunchModel;
|
use vnt::channel::punch::PunchModel;
|
||||||
use vnt::channel::UseChannelType;
|
use vnt::channel::UseChannelType;
|
||||||
use vnt::cipher::CipherModel;
|
use vnt::cipher::CipherModel;
|
||||||
@@ -32,7 +32,6 @@ pub struct FileConfig {
|
|||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
pub no_proxy: bool,
|
pub no_proxy: bool,
|
||||||
pub server_encrypt: bool,
|
pub server_encrypt: bool,
|
||||||
pub parallel: usize,
|
|
||||||
pub cipher_model: Option<String>,
|
pub cipher_model: Option<String>,
|
||||||
pub finger: bool,
|
pub finger: bool,
|
||||||
pub punch_model: String,
|
pub punch_model: String,
|
||||||
@@ -45,22 +44,30 @@ pub struct FileConfig {
|
|||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
pub mapping: Vec<String>,
|
pub mapping: Vec<String>,
|
||||||
pub compressor: Option<String>,
|
pub compressor: Option<String>,
|
||||||
|
pub vnt_mapping: Vec<String>,
|
||||||
|
pub disable_stats: bool,
|
||||||
|
// 允许传递wg流量
|
||||||
|
pub allow_wire_guard: bool,
|
||||||
|
pub local_dev: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FileConfig {
|
impl Default for FileConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut stun_server = Vec::new();
|
||||||
|
for x in config::PUB_STUN {
|
||||||
|
stun_server.push(x.to_string());
|
||||||
|
}
|
||||||
Self {
|
Self {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
tap: false,
|
tap: false,
|
||||||
token: "".to_string(),
|
token: "".to_string(),
|
||||||
device_id: get_device_id(),
|
device_id: get_device_id(),
|
||||||
name: os_info::get().to_string(),
|
name: gethostname::gethostname()
|
||||||
|
.to_str()
|
||||||
|
.unwrap_or("UnknownName")
|
||||||
|
.to_string(),
|
||||||
server_address: "nat1.wherewego.top:29872".to_string(),
|
server_address: "nat1.wherewego.top:29872".to_string(),
|
||||||
stun_server: vec![
|
stun_server,
|
||||||
"stun1.l.google.com:19302".to_string(),
|
|
||||||
"stun2.l.google.com:19302".to_string(),
|
|
||||||
"stun.miwifi.com:3478".to_string(),
|
|
||||||
],
|
|
||||||
dns: vec![],
|
dns: vec![],
|
||||||
in_ips: vec![],
|
in_ips: vec![],
|
||||||
out_ips: vec![],
|
out_ips: vec![],
|
||||||
@@ -72,7 +79,6 @@ impl Default for FileConfig {
|
|||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
no_proxy: false,
|
no_proxy: false,
|
||||||
server_encrypt: false,
|
server_encrypt: false,
|
||||||
parallel: 1,
|
|
||||||
cipher_model: None,
|
cipher_model: None,
|
||||||
finger: false,
|
finger: false,
|
||||||
punch_model: "all".to_string(),
|
punch_model: "all".to_string(),
|
||||||
@@ -85,30 +91,34 @@ impl Default for FileConfig {
|
|||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
mapping: vec![],
|
mapping: vec![],
|
||||||
compressor: None,
|
compressor: None,
|
||||||
|
vnt_mapping: vec![],
|
||||||
|
disable_stats: false,
|
||||||
|
allow_wire_guard: false,
|
||||||
|
local_dev: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
pub fn read_config(file_path: &str) -> anyhow::Result<(Config, Vec<String>, bool)> {
|
||||||
let conf = std::fs::read_to_string(file_path)?;
|
let conf = std::fs::read_to_string(file_path)?;
|
||||||
let file_conf = match serde_yaml::from_str::<FileConfig>(&conf) {
|
let file_conf = match serde_yaml::from_str::<FileConfig>(&conf) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{:?}", e);
|
log::error!("serde_yaml::from_str {:?}", e);
|
||||||
return Err(anyhow!("{}", e));
|
return Err(anyhow!("serde_yaml::from_str {:?}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if file_conf.token.is_empty() {
|
if file_conf.token.is_empty() {
|
||||||
return Err(anyhow!("token is_empty"));
|
return Err(anyhow!("token is_empty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
|
let in_ips = match args_parse::ips_parse(&file_conf.in_ips) {
|
||||||
Ok(in_ips) => in_ips,
|
Ok(in_ips) => in_ips,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(anyhow!("in_ips {:?} error:{}", &file_conf.in_ips, e));
|
return Err(anyhow!("in_ips {:?} error:{}", &file_conf.in_ips, e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let out_ips = match common::args_parse::out_ips_parse(&file_conf.out_ips) {
|
let out_ips = match args_parse::out_ips_parse(&file_conf.out_ips) {
|
||||||
Ok(out_ips) => out_ips,
|
Ok(out_ips) => out_ips,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(anyhow!("out_ips {:?} error:{}", &file_conf.out_ips, e));
|
return Err(anyhow!("out_ips {:?} error:{}", &file_conf.out_ips, e));
|
||||||
@@ -118,19 +128,13 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
|||||||
None => None,
|
None => None,
|
||||||
Some(r) => Some(r.map_err(|e| anyhow!("ip {:?} error:{}", &file_conf.ip, e))?),
|
Some(r) => Some(r.map_err(|e| anyhow!("ip {:?} error:{}", &file_conf.ip, e))?),
|
||||||
};
|
};
|
||||||
let cipher_model = {
|
let cipher_model = if let Some(v) = file_conf.cipher_model {
|
||||||
|
CipherModel::from_str(&v).map_err(|e| anyhow!("{}", e))?
|
||||||
|
} else {
|
||||||
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
||||||
if file_conf.password.is_some() && file_conf.cipher_model.is_none() {
|
if file_conf.password.is_some() {
|
||||||
Err(anyhow!("cipher_model undefined"))?
|
Err(anyhow!("cipher_model undefined"))?
|
||||||
}
|
} else {
|
||||||
#[cfg(not(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
{
|
|
||||||
CipherModel::None
|
CipherModel::None
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
@@ -147,6 +151,7 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
|||||||
};
|
};
|
||||||
let config = Config::new(
|
let config = Config::new(
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
file_conf.tap,
|
file_conf.tap,
|
||||||
file_conf.token,
|
file_conf.token,
|
||||||
file_conf.device_id,
|
file_conf.device_id,
|
||||||
@@ -158,17 +163,17 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
|||||||
out_ips,
|
out_ips,
|
||||||
file_conf.password,
|
file_conf.password,
|
||||||
file_conf.mtu,
|
file_conf.mtu,
|
||||||
file_conf.tcp,
|
|
||||||
virtual_ip,
|
virtual_ip,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
file_conf.no_proxy,
|
file_conf.no_proxy,
|
||||||
file_conf.server_encrypt,
|
file_conf.server_encrypt,
|
||||||
file_conf.parallel,
|
|
||||||
cipher_model,
|
cipher_model,
|
||||||
file_conf.finger,
|
file_conf.finger,
|
||||||
punch_model,
|
punch_model,
|
||||||
file_conf.ports,
|
file_conf.ports,
|
||||||
file_conf.first_latency,
|
file_conf.first_latency,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
file_conf.device_name,
|
file_conf.device_name,
|
||||||
use_channel_type,
|
use_channel_type,
|
||||||
file_conf.packet_loss,
|
file_conf.packet_loss,
|
||||||
@@ -176,6 +181,10 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
|||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
file_conf.mapping,
|
file_conf.mapping,
|
||||||
compressor,
|
compressor,
|
||||||
|
!file_conf.disable_stats,
|
||||||
|
file_conf.allow_wire_guard,
|
||||||
|
file_conf.local_dev,
|
||||||
)?;
|
)?;
|
||||||
Ok((config, file_conf.cmd))
|
|
||||||
|
Ok((config, file_conf.vnt_mapping, file_conf.cmd))
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,26 @@
|
|||||||
|
pub const PUB_STUN: [&'static str; 4] = [
|
||||||
|
"stun.miwifi.com",
|
||||||
|
"stun.chat.bilibili.com",
|
||||||
|
"stun.hitv.com",
|
||||||
|
"stun.cdnbye.com",
|
||||||
|
];
|
||||||
#[cfg(feature = "file_config")]
|
#[cfg(feature = "file_config")]
|
||||||
mod file_config;
|
mod file_config;
|
||||||
|
|
||||||
|
use crate::identifier;
|
||||||
#[cfg(feature = "file_config")]
|
#[cfg(feature = "file_config")]
|
||||||
pub use file_config::read_config;
|
pub use file_config::read_config;
|
||||||
|
|
||||||
#[cfg(not(feature = "file_config"))]
|
#[cfg(not(feature = "file_config"))]
|
||||||
pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, bool)> {
|
pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, Vec<String>, bool)> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_device_id() -> String {
|
pub fn get_device_id() -> String {
|
||||||
if let Some(id) = common::identifier::get_unique_identifier() {
|
if let Some(id) = identifier::get_unique_identifier() {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
let path_buf = match crate::app_home() {
|
let path_buf = match crate::cli::app_home() {
|
||||||
Ok(path_buf) => path_buf.join("device-id"),
|
Ok(path_buf) => path_buf.join("device-id"),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("{:?}", e);
|
log::warn!("{:?}", e);
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
use console::{style, Style};
|
use console::{style, Style};
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
use crate::command::entity::{DeviceItem, Info, RouteItem};
|
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
|
||||||
|
|
||||||
pub mod table;
|
pub mod table;
|
||||||
|
|
||||||
@@ -21,11 +22,14 @@ pub fn console_info(status: Info) {
|
|||||||
|
|
||||||
println!("NAT type: {}", style(status.nat_type).green());
|
println!("NAT type: {}", style(status.nat_type).green());
|
||||||
println!("Relay server: {}", style(status.relay_server).green());
|
println!("Relay server: {}", style(status.relay_server).green());
|
||||||
|
println!(
|
||||||
|
"Udp listen: {}",
|
||||||
|
style(status.udp_listen_addr.join(", ")).green()
|
||||||
|
);
|
||||||
|
println!("Tcp listen: {}", style(status.tcp_listen_addr).green());
|
||||||
println!("Public ips: {}", style(status.public_ips).green());
|
println!("Public ips: {}", style(status.public_ips).green());
|
||||||
println!("Local addr: {}", style(status.local_addr).green());
|
println!("Local addr: {}", style(status.local_addr).green());
|
||||||
println!("IPv6: {}", style(status.ipv6_addr).green());
|
println!("IPv6: {}", style(status.ipv6_addr).green());
|
||||||
println!("Up: {}", style(convert(status.up)).green());
|
|
||||||
println!("Down: {}", style(convert(status.down)).green());
|
|
||||||
|
|
||||||
if !status.port_mapping_list.is_empty() {
|
if !status.port_mapping_list.is_empty() {
|
||||||
println!("------------------------------------------");
|
println!("------------------------------------------");
|
||||||
@@ -128,15 +132,21 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
|
|||||||
("Rt".to_string(), Style::new()),
|
("Rt".to_string(), Style::new()),
|
||||||
]);
|
]);
|
||||||
for item in list {
|
for item in list {
|
||||||
|
let name = if item.wire_guard {
|
||||||
|
format!("{}(wg)", item.name)
|
||||||
|
} else {
|
||||||
|
item.name
|
||||||
|
};
|
||||||
if &item.status == "Online" {
|
if &item.status == "Online" {
|
||||||
if item.client_secret != item.current_client_secret
|
if !item.wire_guard
|
||||||
|| (!item.current_client_secret_hash.is_empty()
|
&& (item.client_secret != item.current_client_secret
|
||||||
&& !item.client_secret_hash.is_empty()
|
|| (!item.current_client_secret_hash.is_empty()
|
||||||
&& item.current_client_secret_hash != item.client_secret_hash)
|
&& !item.client_secret_hash.is_empty()
|
||||||
|
&& item.current_client_secret_hash != item.client_secret_hash))
|
||||||
{
|
{
|
||||||
//加密状态不一致,无法通信的
|
//加密状态不一致,无法通信的
|
||||||
out_list.push(vec![
|
out_list.push(vec![
|
||||||
(item.name, Style::new().red()),
|
(name, Style::new().red()),
|
||||||
(item.virtual_ip, Style::new().red()),
|
(item.virtual_ip, Style::new().red()),
|
||||||
(item.status, Style::new().red()),
|
(item.status, Style::new().red()),
|
||||||
("Mismatch".to_string(), Style::new().red()),
|
("Mismatch".to_string(), Style::new().red()),
|
||||||
@@ -145,7 +155,7 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
|
|||||||
} else {
|
} else {
|
||||||
if item.nat_traversal_type.contains("p2p") {
|
if item.nat_traversal_type.contains("p2p") {
|
||||||
out_list.push(vec![
|
out_list.push(vec![
|
||||||
(item.name, Style::new().green()),
|
(name, Style::new().green()),
|
||||||
(item.virtual_ip, Style::new().green()),
|
(item.virtual_ip, Style::new().green()),
|
||||||
(item.status, Style::new().green()),
|
(item.status, Style::new().green()),
|
||||||
(item.nat_traversal_type, Style::new().green()),
|
(item.nat_traversal_type, Style::new().green()),
|
||||||
@@ -153,7 +163,7 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
|
|||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
out_list.push(vec![
|
out_list.push(vec![
|
||||||
(item.name, Style::new().yellow()),
|
(name, Style::new().yellow()),
|
||||||
(item.virtual_ip, Style::new().yellow()),
|
(item.virtual_ip, Style::new().yellow()),
|
||||||
(item.status, Style::new().yellow()),
|
(item.status, Style::new().yellow()),
|
||||||
(item.nat_traversal_type, Style::new().yellow()),
|
(item.nat_traversal_type, Style::new().yellow()),
|
||||||
@@ -163,7 +173,7 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out_list.push(vec![
|
out_list.push(vec![
|
||||||
(item.name, Style::new().color256(102)),
|
(name, Style::new().color256(102)),
|
||||||
(item.virtual_ip, Style::new().color256(102)),
|
(item.virtual_ip, Style::new().color256(102)),
|
||||||
(item.status, Style::new().color256(102)),
|
(item.status, Style::new().color256(102)),
|
||||||
("".to_string(), Style::new().color256(102)),
|
("".to_string(), Style::new().color256(102)),
|
||||||
@@ -237,3 +247,120 @@ pub fn console_device_list_all(mut list: Vec<DeviceItem>) {
|
|||||||
}
|
}
|
||||||
table::println_table(out_list)
|
table::println_table(out_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn console_chart_a(chart_a: ChartA) {
|
||||||
|
if chart_a.disable_stats {
|
||||||
|
println!("Traffic statistics not enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
println!("-----------------------------------------------------------------");
|
||||||
|
println!(
|
||||||
|
"Upload total = {}",
|
||||||
|
style(convert(chart_a.up_total)).green()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"Download total = {}",
|
||||||
|
style(convert(chart_a.down_total)).green()
|
||||||
|
);
|
||||||
|
println!("-----------------------------------------------------------------");
|
||||||
|
let up_keys: HashSet<_> = chart_a.up_map.keys().cloned().collect();
|
||||||
|
let down_keys: HashSet<_> = chart_a.down_map.keys().cloned().collect();
|
||||||
|
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
|
||||||
|
// 排序
|
||||||
|
keys.sort();
|
||||||
|
|
||||||
|
// 找到最大的值,用于缩放条形图长度
|
||||||
|
let up_max_value = *chart_a.up_map.values().max().unwrap_or(&0);
|
||||||
|
let down_max_value = *chart_a.down_map.values().max().unwrap_or(&0);
|
||||||
|
let max_value = up_max_value.max(down_max_value);
|
||||||
|
let max_value = max_value.max(1);
|
||||||
|
let max_height = 50;
|
||||||
|
// 打印条形图
|
||||||
|
for key in &keys {
|
||||||
|
if let Some(&value) = chart_a.up_map.get(key) {
|
||||||
|
let bar = "█".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
|
||||||
|
println!(
|
||||||
|
"{:<10} | {} upload {}",
|
||||||
|
key,
|
||||||
|
bar,
|
||||||
|
style(convert(value)).green()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(&value) = chart_a.down_map.get(key) {
|
||||||
|
let bar = "█".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
|
||||||
|
println!(
|
||||||
|
"{:<10} | {} download {}",
|
||||||
|
key,
|
||||||
|
bar,
|
||||||
|
style(convert(value)).green()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn console_chart_b(chart_b: ChartB) {
|
||||||
|
if chart_b.disable_stats {
|
||||||
|
println!("Traffic statistics not enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ip = if let Some(ip) = chart_b.ip {
|
||||||
|
ip
|
||||||
|
} else {
|
||||||
|
println!("Ip: None");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
println!("---------------------------- upload ----------------------------");
|
||||||
|
println!("IP: {}", ip);
|
||||||
|
println!("Upload total: {}", style(convert(chart_b.up_total)).green());
|
||||||
|
println!(
|
||||||
|
"Max: {}",
|
||||||
|
style(convert(
|
||||||
|
chart_b
|
||||||
|
.up_list
|
||||||
|
.iter()
|
||||||
|
.max()
|
||||||
|
.cloned()
|
||||||
|
.map_or(0, |v| v as u64)
|
||||||
|
))
|
||||||
|
.green()
|
||||||
|
);
|
||||||
|
console_chart_b_list(chart_b.up_list);
|
||||||
|
println!("---------------------------- download ----------------------------");
|
||||||
|
println!("IP: {}", ip);
|
||||||
|
println!(
|
||||||
|
"Download total: {}",
|
||||||
|
style(convert(chart_b.down_total)).green()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"Max: {}",
|
||||||
|
style(convert(
|
||||||
|
chart_b
|
||||||
|
.down_list
|
||||||
|
.iter()
|
||||||
|
.max()
|
||||||
|
.cloned()
|
||||||
|
.map_or(0, |v| v as u64)
|
||||||
|
))
|
||||||
|
.green()
|
||||||
|
);
|
||||||
|
console_chart_b_list(chart_b.down_list);
|
||||||
|
}
|
||||||
|
fn console_chart_b_list(list: Vec<usize>) {
|
||||||
|
let max_value = *list.iter().max().unwrap_or(&0);
|
||||||
|
let max_value = max_value.max(1);
|
||||||
|
let max_height = max_value.min(20);
|
||||||
|
// 遍历从最大高度到0
|
||||||
|
for i in (0..=max_height).rev() {
|
||||||
|
for &value in &list {
|
||||||
|
let scaled_value = (value as f64 / max_value as f64 * max_height as f64) as usize;
|
||||||
|
if scaled_value >= i {
|
||||||
|
print!("█");
|
||||||
|
} else {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-18
@@ -52,6 +52,19 @@ pub fn get_unique_identifier() -> Option<String> {
|
|||||||
pub fn get_unique_identifier() -> Option<String> {
|
pub fn get_unique_identifier() -> Option<String> {
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
// Try to execute 'dmidecode' command to get the system identifier first.
|
||||||
|
if let Ok(output) = Command::new("dmidecode")
|
||||||
|
.arg("-s")
|
||||||
|
.arg("system-uuid")
|
||||||
|
.output()
|
||||||
|
{
|
||||||
|
let identifier = String::from_utf8_lossy(&output.stdout).trim().to_owned();
|
||||||
|
if !identifier.is_empty() {
|
||||||
|
return Some(identifier.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read file /etc/machine-id if 'dmidecode' command cannot be executed or get nothing.
|
||||||
// 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的
|
// 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的
|
||||||
// 唯一标识,而且某些环境没有预装`dmidecode`命令
|
// 唯一标识,而且某些环境没有预装`dmidecode`命令
|
||||||
if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") {
|
if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") {
|
||||||
@@ -61,22 +74,5 @@ pub fn get_unique_identifier() -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = match Command::new("dmidecode")
|
None
|
||||||
.arg("-s")
|
|
||||||
.arg("system-uuid")
|
|
||||||
.output()
|
|
||||||
{
|
|
||||||
Ok(output) => output,
|
|
||||||
Err(_) => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let identifier = result.trim();
|
|
||||||
if identifier.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(identifier.to_string())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,12 @@
|
|||||||
pub mod args_parse;
|
pub mod args_parse;
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
pub mod command;
|
||||||
|
pub mod config;
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
mod console_out;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
|
|
||||||
|
pub mod cli;
|
||||||
|
mod generated_serial_number;
|
||||||
|
|
||||||
|
pub mod callback;
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
[package]
|
||||||
|
name = "vn-link-cli"
|
||||||
|
version = "1.2.16"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
vn-link = { path = "../vn-link", default-features = false }
|
||||||
|
common = { path = "../common", default-features = false }
|
||||||
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
|
log = "0.4.17"
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.build-dependencies]
|
||||||
|
thunk-rs = { version = "0.3.3", features = ["win7"] }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["default-feature"]
|
||||||
|
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
|
||||||
|
|
||||||
|
openssl = ["vn-link/openssl", "common/openssl"]
|
||||||
|
openssl-vendored = ["vn-link/openssl-vendored", "common/openssl-vendored"]
|
||||||
|
ring-cipher = ["vn-link/ring-cipher", "common/ring-cipher"]
|
||||||
|
aes_cbc = ["vn-link/aes_cbc", "common/aes_cbc"]
|
||||||
|
aes_ecb = ["vn-link/aes_ecb", "common/aes_ecb"]
|
||||||
|
sm4_cbc = ["vn-link/sm4_cbc", "common/sm4_cbc"]
|
||||||
|
aes_gcm = ["vn-link/aes_gcm", "common/aes_gcm"]
|
||||||
|
chacha20_poly1305 = ["vn-link/chacha20_poly1305", "common/chacha20_poly1305"]
|
||||||
|
server_encrypt = ["vn-link/server_encrypt", "common/server_encrypt"]
|
||||||
|
port_mapping = ["vn-link/port_mapping", "common/port_mapping"]
|
||||||
|
lz4 = ["vn-link/lz4_compress", "common/lz4"]
|
||||||
|
zstd = ["vn-link/zstd_compress", "common/zstd"]
|
||||||
|
upnp = ["vn-link/upnp", "common/upnp"]
|
||||||
|
ws = ["vn-link/ws", "common/ws"]
|
||||||
|
wss = ["vn-link/wss", "common/wss"]
|
||||||
|
log = ["common/log"]
|
||||||
|
command = ["common/command"]
|
||||||
|
file_config = ["common/file_config"]
|
||||||
|
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# 端口映射模式
|
||||||
|
|
||||||
|
## 一、特点
|
||||||
|
|
||||||
|
1. 不需要tap/tun虚拟网卡
|
||||||
|
2. 不需要管理员/root权限
|
||||||
|
3. 不改变本地路由
|
||||||
|
4. 使用端口映射来访问目标服务
|
||||||
|
|
||||||
|
## 二、作用
|
||||||
|
|
||||||
|
和vnt互补,能简单快速构建网络,外部依赖更少
|
||||||
|
|
||||||
|
## 三、使用方式
|
||||||
|
|
||||||
|
和vnt的使用方式一样,只是多了"--vnt-mapping"这个参数
|
||||||
|
|
||||||
|
### vn-link作为被访问端,不需要额外配置vnt-mapping
|
||||||
|
|
||||||
|
### vn-link访问vnt或者vn-link,需要加vnt-mapping
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
设备A 运行vnt(虚拟IP 10.26.0.A),设备B 运行vn-link(虚拟IP 10.26.0.B)。
|
||||||
|
|
||||||
|
如果要用B访问A上的tcp 80端口,则在设备B上需要加--vnt-mapping "tcp:port1-10.26.0.A:80"
|
||||||
|
|
||||||
|
这个参数的作用是将B上的***本地端口port1***转发到设备A的地址10.26.0.A:
|
||||||
|
80,此时在设备B上可以访问本地port1端口从而间接访问10.26.0.A:80
|
||||||
|
|
||||||
|
## 四、vn-link的子网代理
|
||||||
|
|
||||||
|
vn-link也支持点对网参数。 还是接着上面的例子
|
||||||
|
|
||||||
|
假设 设备C在设备A的子网下,C的子网IP为192.168.1.C,A的子网IP为192.168.1.A,要在设备B上访问C
|
||||||
|
|
||||||
|
则在B上加这些参数
|
||||||
|
|
||||||
|
- --vnt-mapping "tcp:port2-192.168.1.C:80" (将本地port2端口映射到C的80端口)
|
||||||
|
- -i 192.168.1.0/24,10.26.0.A (将目标192.168.1.0/24的数据发送到10.26.0.A,也就是A节点)
|
||||||
|
|
||||||
|
在A上加参数
|
||||||
|
|
||||||
|
- -o 0.0.0.0/0 (允许所有流量转发)
|
||||||
|
|
||||||
|
***再次说明,vn-link作为被访问端时和vnt使用方式一致,vn-link作为访问端时需要加--vnt-mapping映射端口***
|
||||||
|
|
||||||
|
***vn-link是基于端口映射的使用模式,不会改变本地路由***
|
||||||
|
|
||||||
|
## 五、参数介绍
|
||||||
|
|
||||||
|
--vnt-mapping支持udp/tcp,例如 --vnt-mapping "tcp:port1-remoteIp:remotePort"
|
||||||
|
|
||||||
|
- 第一部分为协议,支持使用udp/tcp
|
||||||
|
- 第二部分是本地端口,注意不要和本地服务的端口冲突
|
||||||
|
- 第三部分是目标机器的地址,一般是目标虚拟IP地址,如果配置了点对网参数(-i和-o)则也可以是目标子网地址
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fn main() {
|
||||||
|
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
thunk::thunk();
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
use common::callback;
|
||||||
|
use vn_link::config::VnLinkConfig;
|
||||||
|
use vn_link::vnt::core::Config;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (config, vnt_link_config, cmd) = match common::cli::parse_args_config() {
|
||||||
|
Ok(rs) => {
|
||||||
|
if let Some(rs) = rs {
|
||||||
|
rs
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"parse error={:?} cmd={:?}",
|
||||||
|
e,
|
||||||
|
std::env::args().collect::<Vec<String>>()
|
||||||
|
);
|
||||||
|
println!("Error {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let vnt_link_config = VnLinkConfig::new(vn_link::config::convert(vnt_link_config).unwrap());
|
||||||
|
main0(config, vnt_link_config, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main0(config: Config, vn_link_config: VnLinkConfig, _show_cmd: bool) {
|
||||||
|
#[cfg(feature = "port_mapping")]
|
||||||
|
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
|
||||||
|
if *is_tcp {
|
||||||
|
println!("TCP port mapping {}->{}", addr, dest)
|
||||||
|
} else {
|
||||||
|
println!("UDP port mapping {}->{}", addr, dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for x in &vn_link_config.mapping {
|
||||||
|
if x.protocol.is_tcp() {
|
||||||
|
println!("TCP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
|
||||||
|
} else {
|
||||||
|
println!("UDP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let vnt_util = match vn_link::VnLink::new(config, vn_link_config, callback::VntHandler {}).await
|
||||||
|
{
|
||||||
|
Ok(vnt) => vnt,
|
||||||
|
Err(e) => {
|
||||||
|
println!("error: {:?}", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "command")]
|
||||||
|
{
|
||||||
|
let vnt_c = vnt_util.as_vnt().clone();
|
||||||
|
std::thread::Builder::new()
|
||||||
|
.name("CommandServer".into())
|
||||||
|
.spawn(move || {
|
||||||
|
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
|
||||||
|
log::warn!("cmd:{:?}", e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("CommandServer");
|
||||||
|
let vnt_c = vnt_util.as_vnt();
|
||||||
|
if _show_cmd {
|
||||||
|
use tokio::io::AsyncBufReadExt;
|
||||||
|
let mut cmd = String::new();
|
||||||
|
let mut reader = tokio::io::BufReader::new(tokio::io::stdin());
|
||||||
|
loop {
|
||||||
|
cmd.clear();
|
||||||
|
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
|
||||||
|
match reader.read_line(&mut cmd).await {
|
||||||
|
Ok(len) => {
|
||||||
|
if !common::command::command_str(&cmd[..len], vnt_c) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("input err:{}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vnt_util.wait().await
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[package]
|
||||||
|
name = "vn-link"
|
||||||
|
version = "1.2.16"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lwip-rs = { git = "https://github.com/vnt-dev/lwip-rs" }
|
||||||
|
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
||||||
|
log = "0.4.17"
|
||||||
|
anyhow = "1.0.82"
|
||||||
|
parking_lot = "0.12.1"
|
||||||
|
|
||||||
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
|
crossbeam-utils = "0.8"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "lz4_compress"]
|
||||||
|
openssl = ["vnt/openssl"]
|
||||||
|
openssl-vendored = ["vnt/openssl-vendored"]
|
||||||
|
ring-cipher = ["vnt/ring-cipher"]
|
||||||
|
aes_cbc = ["vnt/aes_cbc"]
|
||||||
|
aes_ecb = ["vnt/aes_ecb"]
|
||||||
|
sm4_cbc = ["vnt/sm4_cbc"]
|
||||||
|
aes_gcm = ["vnt/aes_gcm"]
|
||||||
|
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
|
||||||
|
server_encrypt = ["vnt/server_encrypt"]
|
||||||
|
port_mapping = ["vnt/port_mapping"]
|
||||||
|
lz4_compress = ["vnt/lz4_compress"]
|
||||||
|
zstd_compress = ["vnt/zstd_compress"]
|
||||||
|
upnp = ["vnt/upnp"]
|
||||||
|
ws = ["vnt/ws"]
|
||||||
|
wss = ["vnt/wss"]
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
use anyhow::Context;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct VnLinkConfig {
|
||||||
|
pub mapping: Vec<LinkItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VnLinkConfig {
|
||||||
|
pub fn new(mapping: Vec<LinkItem>) -> Self {
|
||||||
|
Self { mapping }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
|
pub enum LinkProtocol {
|
||||||
|
Tcp,
|
||||||
|
Udp,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinkProtocol {
|
||||||
|
pub fn is_tcp(&self) -> bool {
|
||||||
|
self == &LinkProtocol::Tcp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct LinkItem {
|
||||||
|
pub protocol: LinkProtocol,
|
||||||
|
pub src_port: u16,
|
||||||
|
pub dest: SocketAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinkItem {
|
||||||
|
pub fn new(protocol: LinkProtocol, src_port: u16, dest: SocketAddr) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol,
|
||||||
|
src_port,
|
||||||
|
dest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<LinkItem>> {
|
||||||
|
let mut rs = Vec::with_capacity(vec.len());
|
||||||
|
for x in vec {
|
||||||
|
let string = x.trim().to_lowercase();
|
||||||
|
if let Some(udp_mapping) = string.strip_prefix("udp:") {
|
||||||
|
let mut split = udp_mapping.split("-");
|
||||||
|
let bind_port = split
|
||||||
|
.next()
|
||||||
|
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
|
||||||
|
let bind_port = u16::from_str(bind_port)
|
||||||
|
.with_context(|| format!("udp_mapping error {}", bind_port))?;
|
||||||
|
let dest = split
|
||||||
|
.next()
|
||||||
|
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
|
||||||
|
let dest_addr = SocketAddr::from_str(dest)
|
||||||
|
.with_context(|| format!("udp_mapping error {}", dest))?;
|
||||||
|
rs.push(LinkItem::new(LinkProtocol::Udp, bind_port, dest_addr));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
|
||||||
|
let mut split = tcp_mapping.split("-");
|
||||||
|
let bind_port = split
|
||||||
|
.next()
|
||||||
|
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
|
||||||
|
let bind_port = u16::from_str(bind_port)
|
||||||
|
.with_context(|| format!("tcp_mapping error {}", bind_port))?;
|
||||||
|
let dest = split
|
||||||
|
.next()
|
||||||
|
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
|
||||||
|
let dest_addr = SocketAddr::from_str(dest)
|
||||||
|
.with_context(|| format!("tcp_mapping error {}", dest))?;
|
||||||
|
rs.push(LinkItem::new(LinkProtocol::Tcp, bind_port, dest_addr));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080",
|
||||||
|
x
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
Ok(rs)
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod tcp;
|
||||||
|
pub mod udp;
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
use crate::out_mapping::tcp::tcp_copy;
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
|
||||||
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
use vnt::handle::CurrentDeviceInfo;
|
||||||
|
|
||||||
|
pub async fn tcp_mapping_listen(
|
||||||
|
tcp_listener: TcpListener,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
dest: SocketAddr,
|
||||||
|
) {
|
||||||
|
loop {
|
||||||
|
let (stream, addr) = match tcp_listener.accept().await {
|
||||||
|
Ok((stream, addr)) => (stream, addr),
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("tcp_mapping_listen {:?} dest {}", e, dest);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let current_info = current_device.load();
|
||||||
|
if current_info.virtual_ip.is_unspecified() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let IpAddr::V4(ip) = dest.ip() {
|
||||||
|
if ip == current_info.virtual_ip {
|
||||||
|
//防止用错参数的
|
||||||
|
log::warn!("目的地址不能是本地虚拟ip tcp->{}", dest);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
|
||||||
|
tokio::spawn(async move {
|
||||||
|
match LwIpTcpStream::connect(src, dest, Duration::from_secs(5)).await {
|
||||||
|
Ok(lw_tcp) => {
|
||||||
|
tcp_copy(lw_tcp, stream);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("{} {}->{} {}", addr, src, dest, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
|
||||||
|
use lwip_rs::udp::UdpSocketWrite;
|
||||||
|
use vnt::handle::CurrentDeviceInfo;
|
||||||
|
|
||||||
|
pub async fn udp_mapping_start(
|
||||||
|
udp: UdpSocket,
|
||||||
|
lwip_udp_write: UdpSocketWrite,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
in_udp_map: &Arc<
|
||||||
|
Mutex<
|
||||||
|
HashMap<
|
||||||
|
(SocketAddr, SocketAddr),
|
||||||
|
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
|
||||||
|
dest: SocketAddr,
|
||||||
|
) {
|
||||||
|
let udp = Arc::new(udp);
|
||||||
|
let mut buf = [0u8; 65536];
|
||||||
|
loop {
|
||||||
|
let (len, addr) = match udp.recv_from(&mut buf).await {
|
||||||
|
Ok(rs) => rs,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("recv_from {} {}", dest, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let current_info = current_device.load();
|
||||||
|
if current_info.virtual_ip.is_unspecified() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let IpAddr::V4(ip) = dest.ip() {
|
||||||
|
if ip == current_info.virtual_ip {
|
||||||
|
//防止用错参数的
|
||||||
|
log::warn!("目的地址不能是本地虚拟ip udp->{}", dest);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
|
||||||
|
in_udp_map.lock().insert(
|
||||||
|
(dest, src),
|
||||||
|
(
|
||||||
|
udp.clone(),
|
||||||
|
Some(addr),
|
||||||
|
Arc::new(AtomicCell::new(Instant::now())),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = lwip_udp_write.send(&buf[..len], &src, &dest) {
|
||||||
|
log::warn!("lwip_udp_write {}->{} {}", src, dest, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
pub mod config;
|
||||||
|
mod in_mapping;
|
||||||
|
mod out_mapping;
|
||||||
|
mod vnt_link;
|
||||||
|
|
||||||
|
pub use vnt;
|
||||||
|
|
||||||
|
pub use vnt_link::*;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod tcp;
|
||||||
|
pub mod udp;
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
|
use lwip_rs::tcp_listener::TcpListener;
|
||||||
|
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
|
||||||
|
use vnt::handle::CurrentDeviceInfo;
|
||||||
|
|
||||||
|
pub async fn tcp_mapping_listen(
|
||||||
|
mut tcp_listener: TcpListener,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
) {
|
||||||
|
loop {
|
||||||
|
let stream = match tcp_listener.accept().await {
|
||||||
|
Ok(stream) => stream,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("tcp_mapping_listen err {:?}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let device_info = current_device.load();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let dest = stream.dest_addr();
|
||||||
|
let src = stream.src_addr();
|
||||||
|
if let Err(e) = tcp_mapping_handle(stream, device_info).await {
|
||||||
|
log::warn!("tcp_mapping_handle {}->{} {:?}", src, dest, e)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn tcp_mapping_handle(
|
||||||
|
tcp_stream: LwIpTcpStream,
|
||||||
|
device_info: CurrentDeviceInfo,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let mut dest = tcp_stream.dest_addr();
|
||||||
|
// let src = tcp_stream.src_addr();
|
||||||
|
if let IpAddr::V4(ip) = dest.ip() {
|
||||||
|
if ip.is_unspecified()
|
||||||
|
|| ip.is_broadcast()
|
||||||
|
|| ip.is_multicast()
|
||||||
|
|| ip == device_info.virtual_ip
|
||||||
|
|| ip == device_info.broadcast_ip
|
||||||
|
{
|
||||||
|
//是自己
|
||||||
|
dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let peer_stream = TcpStream::connect(dest).await?;
|
||||||
|
if dest.port() == peer_stream.local_addr()?.port() {
|
||||||
|
return Err(anyhow::anyhow!("tcp port loop"));
|
||||||
|
}
|
||||||
|
tcp_copy(tcp_stream, peer_stream);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn tcp_copy(lw_tcp: LwIpTcpStream, tokio_tcp: TcpStream) {
|
||||||
|
let (mut write, mut read) = lw_tcp.into_split();
|
||||||
|
let (mut peer_read, mut peer_write) = tokio_tcp.into_split();
|
||||||
|
tokio::spawn(async move { tokio::io::copy(&mut read, &mut peer_write).await });
|
||||||
|
tokio::spawn(async move { tokio::io::copy(&mut peer_read, &mut write).await });
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
use lwip_rs::udp::{UdpSocketRead, UdpSocketWrite};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
use vnt::handle::CurrentDeviceInfo;
|
||||||
|
|
||||||
|
pub async fn udp_mapping_start(
|
||||||
|
lwip_udp_write: UdpSocketWrite,
|
||||||
|
mut lwip_udp_read: UdpSocketRead,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
in_udp_map: Arc<
|
||||||
|
Mutex<
|
||||||
|
HashMap<
|
||||||
|
(SocketAddr, SocketAddr),
|
||||||
|
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
) {
|
||||||
|
loop {
|
||||||
|
let (buf, src, dest) = match lwip_udp_read.recv().await {
|
||||||
|
Ok(rs) => rs,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("udp_mapping err {:?}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Err(e) = handle(
|
||||||
|
¤t_device,
|
||||||
|
&lwip_udp_write,
|
||||||
|
&in_udp_map,
|
||||||
|
buf,
|
||||||
|
src,
|
||||||
|
dest,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log::warn!("udp_mapping err {}->{} {:?}", src, dest, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle(
|
||||||
|
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||||
|
lwip_udp_write: &UdpSocketWrite,
|
||||||
|
map: &Arc<
|
||||||
|
Mutex<
|
||||||
|
HashMap<
|
||||||
|
(SocketAddr, SocketAddr),
|
||||||
|
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
src: SocketAddr,
|
||||||
|
dest: SocketAddr,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let option = map.lock().get(&(src, dest)).cloned();
|
||||||
|
|
||||||
|
if let Some((dest_udp, addr, time)) = option {
|
||||||
|
time.store(Instant::now());
|
||||||
|
if let Some(addr) = addr {
|
||||||
|
dest_udp.send_to(&buf, addr).await?;
|
||||||
|
} else {
|
||||||
|
dest_udp.send(&buf).await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut real_dest = dest;
|
||||||
|
let peer_udp_socket = match UdpSocket::bind(format!("0.0.0.0:{}", src.port())).await {
|
||||||
|
Ok(udp) => udp,
|
||||||
|
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
|
||||||
|
};
|
||||||
|
if let IpAddr::V4(ip) = dest.ip() {
|
||||||
|
let device_info = current_device.load();
|
||||||
|
if ip.is_unspecified()
|
||||||
|
|| ip.is_broadcast()
|
||||||
|
|| ip.is_multicast()
|
||||||
|
|| ip == device_info.virtual_ip
|
||||||
|
|| ip == device_info.broadcast_ip
|
||||||
|
{
|
||||||
|
//是自己
|
||||||
|
real_dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peer_udp_socket.connect(real_dest).await?;
|
||||||
|
peer_udp_socket.send(&buf).await?;
|
||||||
|
let peer_udp_socket = Arc::new(peer_udp_socket);
|
||||||
|
let time = Arc::new(AtomicCell::new(Instant::now()));
|
||||||
|
let map = map.clone();
|
||||||
|
map.lock()
|
||||||
|
.insert((src, dest), (peer_udp_socket.clone(), None, time.clone()));
|
||||||
|
let lwip_udp_write = lwip_udp_write.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
peer_udp_handle(peer_udp_socket, lwip_udp_write, src, dest, time).await;
|
||||||
|
map.lock().remove(&(src, dest));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn peer_udp_handle(
|
||||||
|
peer_udp_socket: Arc<UdpSocket>,
|
||||||
|
lwip_udp_write: UdpSocketWrite,
|
||||||
|
src: SocketAddr,
|
||||||
|
dest: SocketAddr,
|
||||||
|
time: Arc<AtomicCell<Instant>>,
|
||||||
|
) {
|
||||||
|
let mut buf = [0u8; 65536];
|
||||||
|
loop {
|
||||||
|
match tokio::time::timeout(Duration::from_secs(600), peer_udp_socket.recv(&mut buf)).await {
|
||||||
|
Ok(rs) => match rs {
|
||||||
|
Ok(len) => match lwip_udp_write.send(&buf[..len], &dest, &src) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
if time.load().elapsed() > Duration::from_secs(580) {
|
||||||
|
//超时关闭
|
||||||
|
log::warn!("udp proxy timeout {}->{}", dest, src,);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use tokio::net::{TcpListener, UdpSocket};
|
||||||
|
use tokio::sync::watch::{channel, Sender};
|
||||||
|
|
||||||
|
use lwip_rs::stack::{NetStack, NetStackWrite};
|
||||||
|
use lwip_rs::tcp_listener::TcpListener as LwIPTcpListener;
|
||||||
|
use lwip_rs::udp::{UdpSocket as LwIpUdpSocket, UdpSocketWrite};
|
||||||
|
use vnt::channel::BUFFER_SIZE;
|
||||||
|
use vnt::core::{Config, Vnt};
|
||||||
|
use vnt::packet::ip::ipv4::packet::IpV4Packet;
|
||||||
|
use vnt::protocol::HEAD_LEN;
|
||||||
|
use vnt::vnt_device::DeviceWrite;
|
||||||
|
use vnt::VntCallback;
|
||||||
|
|
||||||
|
use crate::config::{LinkItem, LinkProtocol, VnLinkConfig};
|
||||||
|
use crate::{in_mapping, out_mapping};
|
||||||
|
|
||||||
|
pub struct VnLink {
|
||||||
|
vnt: Vnt,
|
||||||
|
in_udp_map: Arc<
|
||||||
|
Mutex<
|
||||||
|
HashMap<
|
||||||
|
(SocketAddr, SocketAddr),
|
||||||
|
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
lwip_udp_write: UdpSocketWrite,
|
||||||
|
shutdown_tx: Sender<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VnLink {
|
||||||
|
pub async fn new<Call: VntCallback>(
|
||||||
|
vnt_config: Config,
|
||||||
|
vn_link_config: VnLinkConfig,
|
||||||
|
callback: Call,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let stack = NetStack::new(HEAD_LEN, 1024, vnt_config.mtu.unwrap_or(1420) as u16).await;
|
||||||
|
let udp = LwIpUdpSocket::new()?;
|
||||||
|
let tcp_listener = LwIPTcpListener::new()?;
|
||||||
|
let (shutdown_tx, shutdown_rx) = channel(false);
|
||||||
|
let (net_stack_write, mut net_stack_read) = stack.into_split();
|
||||||
|
let vnt = Vnt::new_device(vnt_config, callback, VntDevice { net_stack_write })?;
|
||||||
|
let shutdown_tx_ = shutdown_tx.clone();
|
||||||
|
let w = vnt.add_stop_listener("vnt-link".into(), move || {
|
||||||
|
let _ = shutdown_tx_.send(true);
|
||||||
|
})?;
|
||||||
|
let ip_sender = vnt.ipv4_packet_sender().unwrap();
|
||||||
|
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut extend = [0; BUFFER_SIZE];
|
||||||
|
loop {
|
||||||
|
tokio::select! {
|
||||||
|
_ = shutdown_rx_.changed() => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rs = net_stack_read.recv_ip() => {
|
||||||
|
match rs{
|
||||||
|
Ok((mut buf, start_index, len)) => {
|
||||||
|
let ipv4_packet = if let Ok(packet) =
|
||||||
|
IpV4Packet::new(&buf[start_index..len])
|
||||||
|
{
|
||||||
|
packet
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let destination_ip = ipv4_packet.destination_ip();
|
||||||
|
let source_ip = ipv4_packet.source_ip();
|
||||||
|
|
||||||
|
if let Err(e) = ip_sender.send_ip(&mut buf, len, &mut extend, destination_ip) {
|
||||||
|
log::warn!("{}->{},{}", source_ip, destination_ip, e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("net_stack_read {:?}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.stop_all();
|
||||||
|
});
|
||||||
|
|
||||||
|
let (lwip_udp_write, lwip_udp_read) = udp.into_split();
|
||||||
|
let in_udp_map: Arc<
|
||||||
|
Mutex<
|
||||||
|
HashMap<
|
||||||
|
(SocketAddr, SocketAddr),
|
||||||
|
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
> = Arc::new(Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
|
let current_device_info = vnt.current_device_info();
|
||||||
|
let in_udp_map_ = in_udp_map.clone();
|
||||||
|
let lwip_udp_write_ = lwip_udp_write.clone();
|
||||||
|
let vnt_ = vnt.clone();
|
||||||
|
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
tokio::select! {
|
||||||
|
_ = shutdown_rx_.changed() => {}
|
||||||
|
_ = out_mapping::udp::udp_mapping_start(
|
||||||
|
lwip_udp_write_,
|
||||||
|
lwip_udp_read,
|
||||||
|
current_device_info,
|
||||||
|
in_udp_map_,
|
||||||
|
) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
vnt_.stop();
|
||||||
|
});
|
||||||
|
let current_device_info = vnt.current_device_info();
|
||||||
|
let vnt_ = vnt.clone();
|
||||||
|
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
tokio::select! {
|
||||||
|
_ = shutdown_rx_.changed() => {}
|
||||||
|
_ = out_mapping::tcp::tcp_mapping_listen(tcp_listener, current_device_info) => {}
|
||||||
|
}
|
||||||
|
vnt_.stop();
|
||||||
|
});
|
||||||
|
let link = Self {
|
||||||
|
vnt,
|
||||||
|
in_udp_map,
|
||||||
|
lwip_udp_write,
|
||||||
|
shutdown_tx,
|
||||||
|
};
|
||||||
|
link.add_mapping(vn_link_config.mapping).await?;
|
||||||
|
Ok(link)
|
||||||
|
}
|
||||||
|
pub async fn add_mapping(&self, mapping: Vec<LinkItem>) -> anyhow::Result<()> {
|
||||||
|
for item in mapping {
|
||||||
|
let current_device_info = self.vnt.current_device_info();
|
||||||
|
if item.dest.ip().is_unspecified() {
|
||||||
|
Err(anyhow::anyhow!("dest_address {:?} is_unspecified", item))?
|
||||||
|
}
|
||||||
|
let mut shutdown_rx_ = self.shutdown_tx.subscribe();
|
||||||
|
if *shutdown_rx_.borrow() {
|
||||||
|
Err(anyhow::anyhow!("mapping stop"))?
|
||||||
|
}
|
||||||
|
if item.protocol == LinkProtocol::Udp {
|
||||||
|
let lwip_udp_write = self.lwip_udp_write.clone();
|
||||||
|
let in_udp_map = self.in_udp_map.clone();
|
||||||
|
//只能本机访问,不然不同IP的相同来源端口会有问题
|
||||||
|
let udp = UdpSocket::bind(format!("127.0.0.1:{}", item.src_port))
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("udp bind failed {}", item.src_port))?;
|
||||||
|
tokio::spawn(async move {
|
||||||
|
tokio::select! {
|
||||||
|
_ = shutdown_rx_.changed() => {}
|
||||||
|
_ = in_mapping::udp::udp_mapping_start(
|
||||||
|
udp,
|
||||||
|
lwip_udp_write,
|
||||||
|
current_device_info,
|
||||||
|
&in_udp_map,
|
||||||
|
item.dest,
|
||||||
|
) => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let listener = TcpListener::bind(format!("127.0.0.1:{}", item.src_port))
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("tcp bind failed {}", item.src_port))?;
|
||||||
|
tokio::spawn(async move {
|
||||||
|
tokio::select! {
|
||||||
|
_ = shutdown_rx_.changed() => {}
|
||||||
|
_ = in_mapping::tcp::tcp_mapping_listen(
|
||||||
|
listener,
|
||||||
|
current_device_info,
|
||||||
|
item.dest,
|
||||||
|
) => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn stop(&self) {
|
||||||
|
self.as_vnt().stop()
|
||||||
|
}
|
||||||
|
pub async fn wait(&self) {
|
||||||
|
loop {
|
||||||
|
let mut receiver = self.shutdown_tx.subscribe();
|
||||||
|
if *receiver.borrow() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if receiver.changed().await.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_vnt(&self) -> &Vnt {
|
||||||
|
&self.vnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VntDevice {
|
||||||
|
net_stack_write: NetStackWrite,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceWrite for VntDevice {
|
||||||
|
fn write(&self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
self.net_stack_write.send_ip(buf)?;
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
-32
@@ -1,51 +1,51 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vnt-cli"
|
name = "vnt-cli"
|
||||||
version = "1.2.10"
|
version = "1.2.16"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
vnt = { path = "../vnt", package = "vnt", default-features = false, features = ["integrated_tun"] }
|
||||||
common = { path = "../common" }
|
common = { path = "../common", default-features = false, features = ["integrated_tun"] }
|
||||||
getopts = "0.2.21"
|
|
||||||
console = "0.15.2"
|
|
||||||
os_info = "3.7.0"
|
|
||||||
serde = "1.0"
|
|
||||||
serde_yaml = "0.9.32"
|
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
log4rs = { version = "1.2.0", optional = true }
|
|
||||||
anyhow = "1.0.82"
|
anyhow = "1.0.82"
|
||||||
[dependencies.uuid]
|
console = "0.15.2"
|
||||||
version = "1.4.1"
|
|
||||||
features = [
|
|
||||||
"v4", # Lets you generate random UUIDs
|
|
||||||
]
|
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||||
sudo = "0.6.0"
|
sudo = "0.6.0"
|
||||||
|
signal-hook = "0.3.17"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4"]
|
default = ["default-feature"]
|
||||||
openssl = ["vnt/openssl"]
|
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
|
||||||
openssl-vendored = ["vnt/openssl-vendored"]
|
|
||||||
ring-cipher = ["vnt/ring-cipher"]
|
openssl = ["vnt/openssl", "common/openssl"]
|
||||||
aes_cbc = ["vnt/aes_cbc"]
|
openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"]
|
||||||
aes_ecb = ["vnt/aes_ecb"]
|
ring-cipher = ["vnt/ring-cipher", "common/ring-cipher"]
|
||||||
sm4_cbc = ["vnt/sm4_cbc"]
|
aes_cbc = ["vnt/aes_cbc", "common/aes_cbc"]
|
||||||
aes_gcm = ["vnt/aes_gcm"]
|
aes_ecb = ["vnt/aes_ecb", "common/aes_ecb"]
|
||||||
server_encrypt = ["vnt/server_encrypt"]
|
sm4_cbc = ["vnt/sm4_cbc", "common/sm4_cbc"]
|
||||||
ip_proxy = ["vnt/ip_proxy"]
|
aes_gcm = ["vnt/aes_gcm", "common/aes_gcm"]
|
||||||
port_mapping = ["vnt/port_mapping"]
|
chacha20_poly1305 = ["vnt/chacha20_poly1305", "common/chacha20_poly1305"]
|
||||||
lz4 = ["vnt/lz4_compress"]
|
server_encrypt = ["vnt/server_encrypt", "common/server_encrypt"]
|
||||||
zstd = ["vnt/zstd_compress"]
|
port_mapping = ["vnt/port_mapping", "common/port_mapping"]
|
||||||
log = ["log4rs"]
|
lz4 = ["vnt/lz4_compress", "common/lz4"]
|
||||||
command = []
|
zstd = ["vnt/zstd_compress", "common/zstd"]
|
||||||
file_config = []
|
ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"]
|
||||||
|
upnp = ["vnt/upnp", "common/upnp"]
|
||||||
|
ws = ["vnt/ws", "common/ws"]
|
||||||
|
wss = ["vnt/wss", "common/wss"]
|
||||||
|
log = ["common/log"]
|
||||||
|
command = ["common/command"]
|
||||||
|
file_config = ["common/file_config"]
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
embed-manifest = "1.4.0"
|
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.build-dependencies]
|
||||||
|
thunk-rs = { version = "0.3.3", features = ["win7"] }
|
||||||
|
|||||||
+107
-24
@@ -1,33 +1,56 @@
|
|||||||
## 模块介绍
|
## 模块介绍
|
||||||
|
|
||||||
体积小,可以在服务器、路由器等环境使用
|
体积小,可以在服务器、路由器等环境使用
|
||||||
|
|
||||||
## 详细参数说明
|
## 详细参数说明
|
||||||
|
|
||||||
### -k `<token>`
|
### -k `<token>`
|
||||||
|
|
||||||
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
|
一个虚拟局域网的标识,在同一服务器下,相同token的设备会组建一个局域网
|
||||||
|
|
||||||
### -n `<name>`
|
### -n `<name>`
|
||||||
|
|
||||||
设备名称,方便区分不同设备
|
设备名称,方便区分不同设备
|
||||||
|
|
||||||
### -d `<id>`
|
### -d `<id>`
|
||||||
|
|
||||||
设备id,每台设备的唯一标识,注意不要重复
|
设备id,每台设备的唯一标识,注意不要重复
|
||||||
|
|
||||||
### -c
|
### -c
|
||||||
|
|
||||||
关闭控制台交互式命令,后台运行时可以加此参数
|
关闭控制台交互式命令,后台运行时可以加此参数
|
||||||
|
|
||||||
### -s `<server>`
|
### -s `<server>`
|
||||||
|
|
||||||
注册和中继服务器地址,注册和转发数据,以'TXT:'开头表示解析TXT记录,TXT记录内容必须是'host:port'形式的服务器地址
|
注册和中继服务器地址,注册和转发数据,以'TXT:'开头表示解析TXT记录,TXT记录内容必须是'host:port'形式的服务器地址
|
||||||
|
|
||||||
### -e `<stun-server>`
|
### -e `<stun-server>`
|
||||||
|
|
||||||
使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略
|
使用stun服务探测客户端NAT类型,不同类型有不同的打洞策略
|
||||||
|
|
||||||
### -a
|
### -a
|
||||||
|
|
||||||
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
|
加了此参数表示使用tap网卡,默认使用tun网卡,tun网卡效率更高
|
||||||
|
|
||||||
注意:仅在windows上支持使用tap,用于兼容低版本windows系统(低版本windows不支持wintun)
|
注意:仅在windows上支持使用tap,用于兼容低版本windows系统(低版本windows不支持wintun)
|
||||||
|
|
||||||
|
使用tap模式需要手动创建tap网卡,使用--nic参数指定已经创建好的tap网卡名称
|
||||||
|
|
||||||
### --nic `<tun0>`
|
### --nic `<tun0>`
|
||||||
|
|
||||||
指定虚拟网卡名称,默认tun模式使用vnt-tun,tap模式使用vnt-tap
|
指定虚拟网卡名称,默认tun模式使用vnt-tun,tap模式使用vnt-tap
|
||||||
|
|
||||||
### -i `<in-ip>`、-o `<out-ip>`
|
### -i `<in-ip>`、-o `<out-ip>`
|
||||||
|
|
||||||
配置点对网(IP代理)时使用,例如A(虚拟ip:10.26.0.2)通过B(虚拟ip:10.26.0.3,本地出口ip:192.168.0.10)访问C(目标网段192.168.0.0/24),
|
配置点对网(IP代理)时使用,例如A(虚拟ip:10.26.0.2)通过B(虚拟ip:10.26.0.3,本地出口ip:192.168.0.10)访问C(
|
||||||
|
目标网段192.168.0.0/24),
|
||||||
|
|
||||||
则在A配置 **'-i 192.168.0.0/24,10.26.0.3'** ,表示将192.168.0.0/24网段的数据都转发到10.26.0.3节点
|
则在A配置 **'-i 192.168.0.0/24,10.26.0.3'** ,表示将192.168.0.0/24网段的数据都转发到10.26.0.3节点
|
||||||
|
|
||||||
在B配置 **'-o 192.168.0.0/24'** ,表示允许将数据转发到 192.168.0.0/24 ,允许转发所有网段可以使用 **'-o 0.0.0.0/0'**
|
在B配置 **'-o 192.168.0.0/24'** ,表示允许将数据转发到 192.168.0.0/24 ,允许转发所有网段可以使用 **'-o 0.0.0.0/0'**
|
||||||
|
|
||||||
-i和-o参数均可使用多次,来指定不同网段,例如 **'-o 192.168.1.0/24 -o 192.168.2.0/24'** 表示允许转发目标为192.168.1.0/24或192.168.2.0/24这两个网段的数据
|
-i和-o参数均可使用多次,来指定不同网段,例如 **'-o 192.168.1.0/24 -o 192.168.2.0/24'**
|
||||||
|
表示允许转发目标为192.168.1.0/24或192.168.2.0/24这两个网段的数据
|
||||||
|
|
||||||
### -w `<password>`
|
### -w `<password>`
|
||||||
|
|
||||||
@@ -39,9 +62,11 @@
|
|||||||
| 大于等于8 | AES256-GCM |
|
| 大于等于8 | AES256-GCM |
|
||||||
|
|
||||||
### -W
|
### -W
|
||||||
|
|
||||||
开启和服务端通信的数据加密,采用rsa+aes256gcm加密客户端和服务端之间通信的数据,可以避免token泄漏、中间人攻击
|
开启和服务端通信的数据加密,采用rsa+aes256gcm加密客户端和服务端之间通信的数据,可以避免token泄漏、中间人攻击
|
||||||
|
|
||||||
注意:
|
注意:
|
||||||
|
|
||||||
1. -w `<password>`是用于客户端-客户端之间的加密,password不会传递到服务端,只添加这个参数不会加密客户端-服务端通信的数据
|
1. -w `<password>`是用于客户端-客户端之间的加密,password不会传递到服务端,只添加这个参数不会加密客户端-服务端通信的数据
|
||||||
2. -W 用于开启客户端-服务端之间的加密
|
2. -W 用于开启客户端-服务端之间的加密
|
||||||
|
|
||||||
@@ -49,54 +74,84 @@
|
|||||||
|
|
||||||
设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值,不加密默认为1450,加密默认为1410
|
设置虚拟网卡的mtu值,大多数情况下使用默认值效率会更高,也可根据实际情况微调这个值,不加密默认为1450,加密默认为1410
|
||||||
|
|
||||||
### --tcp
|
### ~~--tcp~~
|
||||||
和服务端使用tcp通信。有些网络提供商对UDP限制比较大,这个时候可以选择使用TCP模式,提高稳定性。一般来说udp延迟和消耗更低
|
|
||||||
|
~~和服务端使用tcp通信。有些网络提供商对UDP限制比较大,这个时候可以选择使用TCP模式,提高稳定性。一般来说udp延迟和消耗更低~~
|
||||||
|
|
||||||
|
新版本使用 `-s tcp://`的形式使用tcp
|
||||||
|
|
||||||
### --ip `<IP>`
|
### --ip `<IP>`
|
||||||
|
|
||||||
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
|
指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配
|
||||||
|
|
||||||
### --par `<parallel>`
|
### --par `<parallel>`
|
||||||
|
|
||||||
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
|
任务并行度(必须为正整数),默认值为1,该值表示处理网卡读写的任务数,组网设备数较多、处理延迟较大时可适当调大此值
|
||||||
|
|
||||||
### --model `<model>`
|
### --model `<model>`
|
||||||
加密模式,可选值 aes_gcm/aes_cbc/aes_ecb/sm4_cbc,默认使用aes_gcm,通常情况aes_gcm安全性高、aes_ecb性能更好,但是在低性能设备上sm4_cbc也许速度会更快;
|
|
||||||
|
|
||||||
|
加密模式,可选值
|
||||||
|
aes_gcm/aes_cbc/aes_ecb/sm4_cbc/chacha20_poly1305/chacha20/xor,默认使用aes_gcm,通常情况aes_gcm和chacha20_poly1305安全性高。
|
||||||
|
各种加密模式的安全性和速度都不相同,请按需选取
|
||||||
|
|
||||||
| 密码位数 | model | 加密算法 |
|
特别说明:xor只是对数据进行简单异或,仅仅避免了明文传输,安全性很差,同时对性能影响也极小;
|
||||||
|-------|---------|------------|
|
|
||||||
| 1~8位 | aes_gcm | AES128-GCM |
|
| 密码位数 | model | 加密算法 |
|
||||||
| `>=`8 | aes_gcm | AES256-GCM |
|
|--------|-------------------|-------------------|
|
||||||
| 1~8位 | aes_cbc | AES128-CBC |
|
| `< 8` | aes_gcm | AES128-GCM |
|
||||||
| `>=`8 | aes_cbc | AES256-CBC |
|
| `>= 8` | aes_gcm | AES256-GCM |
|
||||||
| 1~8位 | aes_ecb | AES128-ECB |
|
| `< 8` | aes_cbc | AES128-CBC |
|
||||||
| `>=`8 | aes_ecb | AES256-ECB |
|
| `>= 8` | aes_cbc | AES256-CBC |
|
||||||
| `>0` | sm4_cbc | SM4-CBC |
|
| `< 8` | aes_ecb | AES128-ECB |
|
||||||
### --finger
|
| `>= 8` | aes_ecb | AES256-ECB |
|
||||||
|
| `> 0` | sm4_cbc | SM4-CBC |
|
||||||
|
| `> 0` | chacha20_poly1305 | ChaCha20-Poly1305 |
|
||||||
|
| `> 0` | chacha20 | ChaCha20 |
|
||||||
|
| `> 0` | xor | 简单异或混淆 |
|
||||||
|
|
||||||
|
### --finger
|
||||||
|
|
||||||
开启数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启,开启会损耗一部分性能
|
开启数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启,开启会损耗一部分性能
|
||||||
|
|
||||||
注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数
|
注意:默认情况下服务端不会对中转的数据做校验,如果要对中转的数据做校验,则需要客户端、服务端都开启此参数
|
||||||
|
|
||||||
### --punch `<punch>`
|
### --punch `<punch>`
|
||||||
|
|
||||||
取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两者都会使用
|
取值ipv4/ipv6,选择只使用ipv4打洞或者只使用ipv6打洞,默认两者都会使用
|
||||||
|
|
||||||
### --ports `<port1,port2>`
|
### --ports `<port1,port2>`
|
||||||
|
|
||||||
指定本地监听的端口组,多个端口使用逗号分隔,多个端口可以分摊流量,增加并发、减缓流量限制,tcp会监听端口组的第一个端口,用于tcp直连
|
指定本地监听的端口组,多个端口使用逗号分隔,多个端口可以分摊流量,增加并发、减缓流量限制,tcp会监听端口组的第一个端口,用于tcp直连
|
||||||
|
|
||||||
- 例1:‘--ports 12345,12346,12347’ 表示udp监听12345、12346、12347这三个端口,tcp监听12345端口
|
- 例1:‘--ports 12345,12346,12347’ 表示udp监听12345、12346、12347这三个端口,tcp监听12345端口
|
||||||
- 例2:‘--ports 0,0’ 表示udp监听两个未使用的端口,tcp监听一个未使用的端口
|
- 例2:‘--ports 0,0’ 表示udp监听两个未使用的端口,tcp监听一个未使用的端口
|
||||||
|
|
||||||
### --cmd
|
### --cmd
|
||||||
|
|
||||||
开启交互式命令,开启后可以直接在窗口下输入命令,如需后台运行请勿开启
|
开启交互式命令,开启后可以直接在窗口下输入命令,如需后台运行请勿开启
|
||||||
|
|
||||||
### --first_latency
|
### --first_latency
|
||||||
|
|
||||||
优先使用低延迟通道,默认情况下优先使用p2p通道,某些情况下可能p2p比客户端中继延迟更高,可使用此参数进行优化传输
|
优先使用低延迟通道,默认情况下优先使用p2p通道,某些情况下可能p2p比客户端中继延迟更高,可使用此参数进行优化传输
|
||||||
|
|
||||||
### --no-proxy
|
### --no-proxy
|
||||||
|
|
||||||
关闭内置的ip代理,内置的代理较为简单,而且一般来说直接使用网卡NAT转发性能会更高,
|
关闭内置的ip代理,内置的代理较为简单,而且一般来说直接使用网卡NAT转发性能会更高,
|
||||||
有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/lbl8603/vnt#%E7%BC%96%E8%AF%91)
|
有需要可以自行配置NAT转发,[可参考‘编译’小节中的NAT配置](https://github.com/vnt-dev/vnt#%E7%BC%96%E8%AF%91)
|
||||||
|
|
||||||
### --dns `<223.5.5.5>`
|
### --dns `<223.5.5.5>`
|
||||||
|
|
||||||
设置域名解析服务器地址,可以设置多个。如果使用TXT记录的域名,则dns默认使用223.5.5.5和114.114.114.114,端口省略值为53
|
设置域名解析服务器地址,可以设置多个。如果使用TXT记录的域名,则dns默认使用223.5.5.5和114.114.114.114,端口省略值为53
|
||||||
|
|
||||||
当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果
|
当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果
|
||||||
|
|
||||||
### --mapping `<udp:0.0.0.0:80->10.26.0.10:80>`
|
### --mapping `<udp:0.0.0.0:80-10.26.0.10:80>`
|
||||||
端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.11:81'
|
|
||||||
|
端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80-10.26.0.10:80 --mapping tcp:0.0.0.0:80-10.26.0.11:81'
|
||||||
表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口
|
表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口
|
||||||
|
|
||||||
### --compressor `<lz4>`
|
### --compressor `<lz4>`
|
||||||
|
|
||||||
启用压缩,默认仅支持lz4压缩,开启压缩后,如果数据包长度大于等于128,则会使用压缩,否则还是会按原数据发送
|
启用压缩,默认仅支持lz4压缩,开启压缩后,如果数据包长度大于等于128,则会使用压缩,否则还是会按原数据发送
|
||||||
|
|
||||||
也支持开启zstd压缩,但是需要自行编译,编译时加入参数--features zstd
|
也支持开启zstd压缩,但是需要自行编译,编译时加入参数--features zstd
|
||||||
@@ -104,8 +159,10 @@
|
|||||||
如果宽度速度比较慢,可以考虑使用高级别的压缩
|
如果宽度速度比较慢,可以考虑使用高级别的压缩
|
||||||
|
|
||||||
### -f `<conf>`
|
### -f `<conf>`
|
||||||
|
|
||||||
指定配置文件
|
指定配置文件
|
||||||
配置文件采用yaml格式,可参考:
|
配置文件采用yaml格式,可参考:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# 全部参数
|
# 全部参数
|
||||||
tap: false #是否使用tap 仅在windows上支持使用tap
|
tap: false #是否使用tap 仅在windows上支持使用tap
|
||||||
@@ -113,7 +170,7 @@ token: xxx #组网token
|
|||||||
device_id: xxx #当前设备id
|
device_id: xxx #当前设备id
|
||||||
name: windows 11 #当前设备名称
|
name: windows 11 #当前设备名称
|
||||||
server_address: ip:port #注册和中继服务器
|
server_address: ip:port #注册和中继服务器
|
||||||
stun_server: #stun服务器
|
stun_server: #stun服务器
|
||||||
- stun1.l.google.com:19302
|
- stun1.l.google.com:19302
|
||||||
- stun2.l.google.com:19302
|
- stun2.l.google.com:19302
|
||||||
in_ips: #代理ip入站
|
in_ips: #代理ip入站
|
||||||
@@ -130,7 +187,7 @@ parallel: 1 #任务并行度
|
|||||||
cipher_model: aes_gcm #客户端加密算法
|
cipher_model: aes_gcm #客户端加密算法
|
||||||
finger: false #关闭数据指纹
|
finger: false #关闭数据指纹
|
||||||
punch_model: ipv4 #打洞模式,表示只使用ipv4地址打洞,默认会同时使用v6和v4
|
punch_model: ipv4 #打洞模式,表示只使用ipv4地址打洞,默认会同时使用v6和v4
|
||||||
ports:
|
ports:
|
||||||
- 0 #使用随机端口,tcp监听此端口
|
- 0 #使用随机端口,tcp监听此端口
|
||||||
- 0
|
- 0
|
||||||
cmd: false #关闭控制台输入
|
cmd: false #关闭控制台输入
|
||||||
@@ -143,31 +200,57 @@ dns:
|
|||||||
- 223.5.5.5 # 首选dns
|
- 223.5.5.5 # 首选dns
|
||||||
- 8.8.8.8 # 备选dns
|
- 8.8.8.8 # 备选dns
|
||||||
mapping:
|
mapping:
|
||||||
- udp:0.0.0.0:80->10.26.0.10:80 # 映射udp数据
|
- udp:0.0.0.0:80-10.26.0.10:80 # 映射udp数据
|
||||||
- tcp:0.0.0.0:80->10.26.0.10:81 # 映射tcp数据
|
- tcp:0.0.0.0:80-10.26.0.10:81 # 映射tcp数据
|
||||||
- tcp:0.0.0.0:82->localhost:83 # 映射tcp数据
|
- tcp:0.0.0.0:82-localhost:83 # 映射tcp数据
|
||||||
|
disable_stats: false # 为true表示关闭统计
|
||||||
|
allow_wire_guard: false # 为true则表示允许接入wg
|
||||||
```
|
```
|
||||||
|
|
||||||
或者需要哪个配置就加哪个,当然token是必须的
|
或者需要哪个配置就加哪个,当然token是必须的
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# 部分参数
|
# 部分参数
|
||||||
token: xxx #组网token
|
token: xxx #组网token
|
||||||
```
|
```
|
||||||
|
|
||||||
### --use-channel `<relay/p2p>`
|
### --use-channel `<relay/p2p>`
|
||||||
|
|
||||||
- relay:仅中继模式,会禁止打洞/p2p直连,只使用服务器转发
|
- relay:仅中继模式,会禁止打洞/p2p直连,只使用服务器转发
|
||||||
- p2p:仅直连模式,会禁止网络数据从服务器/客户端转发,只会使用服务器转发控制包
|
- p2p:仅直连模式,会禁止网络数据从服务器/客户端转发,只会使用服务器转发控制包
|
||||||
|
|
||||||
### --packet-loss `<0>`
|
### --packet-loss `<0>`
|
||||||
|
|
||||||
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境时会有帮助。
|
模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包。在模拟弱网环境时会有帮助。
|
||||||
|
|
||||||
### --packet-delay `<0>`
|
### --packet-delay `<0>`
|
||||||
|
|
||||||
模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网
|
模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网
|
||||||
|
|
||||||
|
### --disable-stats
|
||||||
|
|
||||||
|
关闭流量统计
|
||||||
|
|
||||||
|
### --allow-wg
|
||||||
|
|
||||||
|
允许接入WireGuard客户端,和wg混用时必须开启此参数
|
||||||
|
|
||||||
### --list
|
### --list
|
||||||
|
|
||||||
在后台运行时,查看其他设备列表
|
在后台运行时,查看其他设备列表
|
||||||
|
|
||||||
### --all
|
### --all
|
||||||
|
|
||||||
在后台运行时,查看其他设备完整信息
|
在后台运行时,查看其他设备完整信息
|
||||||
|
|
||||||
### --info
|
### --info
|
||||||
|
|
||||||
在后台运行时,查看当前设备信息
|
在后台运行时,查看当前设备信息
|
||||||
### --route
|
|
||||||
|
### --route
|
||||||
|
|
||||||
在后台运行时,查看数据转发路径
|
在后台运行时,查看数据转发路径
|
||||||
|
|
||||||
### --stop
|
### --stop
|
||||||
|
|
||||||
停止后台运行
|
停止后台运行
|
||||||
|
|||||||
+3
-14
@@ -1,16 +1,5 @@
|
|||||||
use rand::Rng;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let now_time = chrono::Local::now();
|
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
|
||||||
let serial_number = format!(
|
#[cfg(target_os = "windows")]
|
||||||
"{}-{}",
|
thunk::thunk();
|
||||||
&now_time.format("%y%m%d%H%M").to_string(),
|
|
||||||
rand::thread_rng().gen_range(100..1000)
|
|
||||||
);
|
|
||||||
let generated_code = format!(r#"pub const SERIAL_NUMBER: &str = "{}";"#, serial_number);
|
|
||||||
let dest_path = "src/generated_serial_number.rs";
|
|
||||||
let mut file = File::create(&dest_path).unwrap();
|
|
||||||
file.write_all(generated_code.as_bytes()).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-505
@@ -1,363 +1,35 @@
|
|||||||
use anyhow::anyhow;
|
use common::callback;
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use console::style;
|
use console::style;
|
||||||
use getopts::Options;
|
|
||||||
|
|
||||||
use common::args_parse::{ips_parse, out_ips_parse};
|
|
||||||
use vnt::channel::punch::PunchModel;
|
|
||||||
use vnt::channel::UseChannelType;
|
|
||||||
use vnt::cipher::CipherModel;
|
|
||||||
use vnt::compression::Compressor;
|
|
||||||
use vnt::core::{Config, Vnt};
|
use vnt::core::{Config, Vnt};
|
||||||
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
mod command;
|
|
||||||
mod config;
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
mod console_out;
|
|
||||||
mod generated_serial_number;
|
|
||||||
mod root_check;
|
mod root_check;
|
||||||
|
fn main() {
|
||||||
pub fn app_home() -> io::Result<PathBuf> {
|
let (config, _vnt_link_config, cmd) = match common::cli::parse_args_config() {
|
||||||
let root_path = match std::env::current_exe() {
|
Ok(rs) => {
|
||||||
Ok(path) => {
|
if let Some(rs) = rs {
|
||||||
if let Some(v) = path.as_path().parent() {
|
rs
|
||||||
v.to_path_buf()
|
|
||||||
} else {
|
} else {
|
||||||
log::warn!("current_exe parent none:{:?}", path);
|
return;
|
||||||
PathBuf::new()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("current_exe err:{:?}", e);
|
log::error!(
|
||||||
PathBuf::new()
|
"parse error={:?} cmd={:?}",
|
||||||
}
|
e,
|
||||||
};
|
std::env::args().collect::<Vec<String>>()
|
||||||
let path = root_path.join("env");
|
);
|
||||||
if !path.exists() {
|
println!("{}", style(format!("Error {:?}", e)).red());
|
||||||
std::fs::create_dir_all(&path)?;
|
|
||||||
}
|
|
||||||
Ok(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
#[cfg(feature = "log")]
|
|
||||||
let _ = log4rs::init_file("log4rs.yaml", Default::default());
|
|
||||||
let args: Vec<String> = std::env::args().collect();
|
|
||||||
let program = args[0].clone();
|
|
||||||
let mut opts = Options::new();
|
|
||||||
opts.optopt("k", "", "组网标识", "<token>");
|
|
||||||
opts.optopt("n", "", "设备名称", "<name>");
|
|
||||||
opts.optopt("d", "", "设备标识", "<id>");
|
|
||||||
opts.optflag("c", "", "关闭交互式命令");
|
|
||||||
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
|
|
||||||
opts.optmulti("e", "", "stun服务器", "<stun-server>");
|
|
||||||
opts.optflag("a", "", "使用tap模式");
|
|
||||||
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
|
|
||||||
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
|
|
||||||
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
|
|
||||||
opts.optopt("w", "", "客户端加密", "<password>");
|
|
||||||
opts.optflag("W", "", "服务端加密");
|
|
||||||
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
|
||||||
opts.optflag("", "tcp", "tcp");
|
|
||||||
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
|
|
||||||
opts.optflag("", "relay", "仅使用服务器转发");
|
|
||||||
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
|
|
||||||
opts.optopt("", "model", "加密模式", "<model>");
|
|
||||||
opts.optflag("", "finger", "指纹校验");
|
|
||||||
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
|
|
||||||
opts.optopt("", "ports", "监听的端口", "<port,port>");
|
|
||||||
opts.optflag("", "cmd", "开启窗口输入");
|
|
||||||
opts.optflag("", "no-proxy", "关闭内置代理");
|
|
||||||
opts.optflag("", "first-latency", "优先延迟");
|
|
||||||
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
|
|
||||||
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
|
|
||||||
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
|
|
||||||
opts.optmulti("", "dns", "dns", "<dns>");
|
|
||||||
opts.optmulti("", "mapping", "mapping", "<mapping>");
|
|
||||||
opts.optopt("f", "", "配置文件", "<conf>");
|
|
||||||
opts.optopt("", "compressor", "压缩算法", "<lz4>");
|
|
||||||
//"后台运行时,查看其他设备列表"
|
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if matches.opt_present("h") || args.len() == 1 {
|
main0(config, cmd)
|
||||||
print_usage(&program, opts);
|
}
|
||||||
return;
|
fn main0(config: Config, _show_cmd: bool) {
|
||||||
}
|
|
||||||
if !root_check::is_app_elevated() {
|
if !root_check::is_app_elevated() {
|
||||||
println!("Please run it with administrator or root privileges");
|
println!("Please run it with administrator or root privileges");
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
sudo::escalate_if_needed().unwrap();
|
sudo::escalate_if_needed().unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#[cfg(feature = "command")]
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
let conf = matches.opt_str("f");
|
|
||||||
let (config, cmd) = if conf.is_some() {
|
|
||||||
match config::read_config(&conf.unwrap()) {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
println!("conf err {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !matches.opt_present("k") {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
println!("parameter -k not found .");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
let tap = matches.opt_present("a");
|
|
||||||
let device_name = matches.opt_str("nic");
|
|
||||||
let token: String = matches.opt_get("k").unwrap().unwrap();
|
|
||||||
let device_id = matches.opt_get_default("d", String::new()).unwrap();
|
|
||||||
let device_id = if device_id.is_empty() {
|
|
||||||
config::get_device_id()
|
|
||||||
} else {
|
|
||||||
device_id
|
|
||||||
};
|
|
||||||
if device_id.is_empty() {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
println!("parameter -d not found .");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let name = matches
|
|
||||||
.opt_get_default("n", os_info::get().to_string())
|
|
||||||
.unwrap();
|
|
||||||
let server_address_str = matches
|
|
||||||
.opt_get_default("s", "nat1.wherewego.top:29872".to_string())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut stun_server = matches.opt_strs("e");
|
|
||||||
if stun_server.is_empty() {
|
|
||||||
stun_server.push("stun1.l.google.com:19302".to_string());
|
|
||||||
stun_server.push("stun2.l.google.com:19302".to_string());
|
|
||||||
stun_server.push("stun.miwifi.com:3478".to_string());
|
|
||||||
}
|
|
||||||
let dns = matches.opt_strs("dns");
|
|
||||||
let in_ip = matches.opt_strs("i");
|
|
||||||
let in_ip = match ips_parse(&in_ip) {
|
|
||||||
Ok(in_ip) => in_ip,
|
|
||||||
Err(e) => {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
println!();
|
|
||||||
println!("-i: {:?} {}", in_ip, e);
|
|
||||||
println!("example: -i 192.168.0.0/24,10.26.0.3");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let out_ip = matches.opt_strs("o");
|
|
||||||
let out_ip = match out_ips_parse(&out_ip) {
|
|
||||||
Ok(out_ip) => out_ip,
|
|
||||||
Err(e) => {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
println!();
|
|
||||||
println!("-o: {:?} {}", out_ip, e);
|
|
||||||
println!("example: -o 0.0.0.0/0");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let password: Option<String> = matches.opt_get("w").unwrap();
|
|
||||||
let server_encrypt = matches.opt_present("W");
|
|
||||||
#[cfg(not(feature = "server_encrypt"))]
|
|
||||||
{
|
|
||||||
if server_encrypt {
|
|
||||||
println!("Server encryption not supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mtu: Option<String> = matches.opt_get("u").unwrap();
|
|
||||||
let mtu = if let Some(mtu) = mtu {
|
|
||||||
match u32::from_str(&mtu) {
|
|
||||||
Ok(mtu) => Some(mtu),
|
|
||||||
Err(e) => {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
println!();
|
|
||||||
println!("'-u {}' {}", mtu, e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
|
|
||||||
let virtual_ip =
|
|
||||||
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
|
|
||||||
if let Some(virtual_ip) = virtual_ip {
|
|
||||||
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
|
|
||||||
{
|
|
||||||
println!("'--ip {}' invalid", virtual_ip);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let tcp_channel = matches.opt_present("tcp");
|
|
||||||
let relay = matches.opt_present("relay");
|
|
||||||
|
|
||||||
let parallel = matches.opt_get::<usize>("par").unwrap().unwrap_or(1);
|
|
||||||
if parallel == 0 {
|
|
||||||
println!("'--par {}' invalid", parallel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cipher_model = match matches.opt_get::<CipherModel>("model") {
|
|
||||||
Ok(model) => {
|
|
||||||
#[cfg(not(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
{
|
|
||||||
if password.is_some() && model.is_none() {
|
|
||||||
println!("Encryption not supported");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
|
||||||
{
|
|
||||||
if password.is_some() && model.is_none() {
|
|
||||||
println!("'--model ' undefined");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
model.unwrap_or(CipherModel::None)
|
|
||||||
}
|
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
|
||||||
model.unwrap_or(CipherModel::AesGcm)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("'--model ' invalid,{}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let finger = matches.opt_present("finger");
|
|
||||||
let punch_model = matches
|
|
||||||
.opt_get::<PunchModel>("punch")
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_or(PunchModel::All);
|
|
||||||
let use_channel_type = matches
|
|
||||||
.opt_get::<UseChannelType>("use-channel")
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
if relay {
|
|
||||||
UseChannelType::Relay
|
|
||||||
} else {
|
|
||||||
UseChannelType::All
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let ports = matches
|
|
||||||
.opt_get::<String>("ports")
|
|
||||||
.unwrap_or(None)
|
|
||||||
.map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect());
|
|
||||||
|
|
||||||
let cmd = matches.opt_present("cmd");
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
let no_proxy = matches.opt_present("no-proxy");
|
|
||||||
let first_latency = matches.opt_present("first-latency");
|
|
||||||
let packet_loss = matches
|
|
||||||
.opt_get::<f64>("packet-loss")
|
|
||||||
.expect("--packet-loss");
|
|
||||||
let packet_delay = matches
|
|
||||||
.opt_get::<u32>("packet-delay")
|
|
||||||
.expect("--packet-delay")
|
|
||||||
.unwrap_or(0);
|
|
||||||
#[cfg(feature = "port_mapping")]
|
|
||||||
let port_mapping_list = matches.opt_strs("mapping");
|
|
||||||
let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() {
|
|
||||||
Compressor::from_str(compressor)
|
|
||||||
.map_err(|e| anyhow!("{}", e))
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
|
||||||
Compressor::None
|
|
||||||
};
|
|
||||||
let config = match Config::new(
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
tap,
|
|
||||||
token,
|
|
||||||
device_id,
|
|
||||||
name,
|
|
||||||
server_address_str,
|
|
||||||
dns,
|
|
||||||
stun_server,
|
|
||||||
in_ip,
|
|
||||||
out_ip,
|
|
||||||
password,
|
|
||||||
mtu,
|
|
||||||
tcp_channel,
|
|
||||||
virtual_ip,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
no_proxy,
|
|
||||||
server_encrypt,
|
|
||||||
parallel,
|
|
||||||
cipher_model,
|
|
||||||
finger,
|
|
||||||
punch_model,
|
|
||||||
ports,
|
|
||||||
first_latency,
|
|
||||||
device_name,
|
|
||||||
use_channel_type,
|
|
||||||
packet_loss,
|
|
||||||
packet_delay,
|
|
||||||
#[cfg(feature = "port_mapping")]
|
|
||||||
port_mapping_list,
|
|
||||||
compressor,
|
|
||||||
) {
|
|
||||||
Ok(config) => config,
|
|
||||||
Err(e) => {
|
|
||||||
println!("config.toml error: {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(config, cmd)
|
|
||||||
};
|
|
||||||
println!("version {}", vnt::VNT_VERSION);
|
|
||||||
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
|
||||||
log::info!(
|
|
||||||
"version:{},Serial:{}",
|
|
||||||
vnt::VNT_VERSION,
|
|
||||||
generated_serial_number::SERIAL_NUMBER
|
|
||||||
);
|
|
||||||
main0(config, cmd);
|
|
||||||
std::process::exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
mod callback;
|
|
||||||
|
|
||||||
fn main0(config: Config, _show_cmd: bool) {
|
|
||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
|
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
|
||||||
if *is_tcp {
|
if *is_tcp {
|
||||||
@@ -366,14 +38,44 @@ fn main0(config: Config, _show_cmd: bool) {
|
|||||||
println!("UDP port mapping {}->{}", addr, dest)
|
println!("UDP port mapping {}->{}", addr, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let vnt_util = Vnt::new(config, callback::VntHandler {}).unwrap();
|
let vnt_util = match Vnt::new(config, callback::VntHandler {}) {
|
||||||
|
Ok(vnt) => vnt,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("vnt create error {:?}", e);
|
||||||
|
println!("error: {:?}", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
{
|
||||||
|
let vnt_c = vnt_util.clone();
|
||||||
|
let mut signals = signal_hook::iterator::Signals::new(&[
|
||||||
|
signal_hook::consts::SIGINT,
|
||||||
|
signal_hook::consts::SIGTERM,
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
let handle = signals.handle();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
for sig in signals.forever() {
|
||||||
|
match sig {
|
||||||
|
signal_hook::consts::SIGINT | signal_hook::consts::SIGTERM => {
|
||||||
|
println!("Received SIGINT, {}", sig);
|
||||||
|
vnt_c.stop();
|
||||||
|
handle.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
#[cfg(feature = "command")]
|
#[cfg(feature = "command")]
|
||||||
{
|
{
|
||||||
let vnt_c = vnt_util.clone();
|
let vnt_c = vnt_util.clone();
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("CommandServer".into())
|
.name("CommandServer".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
if let Err(e) = command::server::CommandServer::new().start(vnt_c) {
|
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
|
||||||
log::warn!("cmd:{:?}", e);
|
log::warn!("cmd:{:?}", e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -382,10 +84,10 @@ fn main0(config: Config, _show_cmd: bool) {
|
|||||||
let mut cmd = String::new();
|
let mut cmd = String::new();
|
||||||
loop {
|
loop {
|
||||||
cmd.clear();
|
cmd.clear();
|
||||||
println!("======== input:list,info,route,all,stop ========");
|
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
|
||||||
match io::stdin().read_line(&mut cmd) {
|
match std::io::stdin().read_line(&mut cmd) {
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
if !command(&cmd[..len], &vnt_util) {
|
if !common::command::command_str(&cmd[..len], &vnt_util) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,159 +102,3 @@ fn main0(config: Config, _show_cmd: bool) {
|
|||||||
|
|
||||||
vnt_util.wait()
|
vnt_util.wait()
|
||||||
}
|
}
|
||||||
#[cfg(feature = "command")]
|
|
||||||
fn command(cmd: &str, vnt: &Vnt) -> bool {
|
|
||||||
if cmd.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
match cmd.to_lowercase().trim() {
|
|
||||||
"list" => {
|
|
||||||
let list = command::command_list(&vnt);
|
|
||||||
console_out::console_device_list(list);
|
|
||||||
}
|
|
||||||
"info" => {
|
|
||||||
let info = command::command_info(&vnt);
|
|
||||||
console_out::console_info(info);
|
|
||||||
}
|
|
||||||
"route" => {
|
|
||||||
let route = command::command_route(&vnt);
|
|
||||||
console_out::console_route_table(route);
|
|
||||||
}
|
|
||||||
"all" => {
|
|
||||||
let list = command::command_list(&vnt);
|
|
||||||
console_out::console_device_list_all(list);
|
|
||||||
}
|
|
||||||
"stop" => {
|
|
||||||
let _ = vnt.stop();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
println!();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_usage(program: &str, _opts: Options) {
|
|
||||||
println!("Usage: {} [options]", program);
|
|
||||||
println!("version:{}", vnt::VNT_VERSION);
|
|
||||||
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
|
||||||
println!("Options:");
|
|
||||||
println!(
|
|
||||||
" -k <token> {}",
|
|
||||||
green("使用相同的token,就能组建一个局域网络".to_string())
|
|
||||||
);
|
|
||||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
|
||||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
|
|
||||||
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
|
|
||||||
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com");
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
println!(
|
|
||||||
" -a 使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡"
|
|
||||||
);
|
|
||||||
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,可指定多个网段");
|
|
||||||
#[cfg(not(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
let enums = String::new();
|
|
||||||
#[cfg(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
let mut enums = String::new();
|
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
|
||||||
enums.push_str("/aes_gcm");
|
|
||||||
#[cfg(feature = "aes_cbc")]
|
|
||||||
enums.push_str("/aes_cbc");
|
|
||||||
#[cfg(feature = "aes_ecb")]
|
|
||||||
enums.push_str("/aes_ecb");
|
|
||||||
#[cfg(feature = "sm4_cbc")]
|
|
||||||
enums.push_str("/sm4_cbc");
|
|
||||||
if !enums.is_empty() {
|
|
||||||
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
|
|
||||||
}
|
|
||||||
#[cfg(feature = "server_encrypt")]
|
|
||||||
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
|
|
||||||
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
|
|
||||||
#[cfg(feature = "file_config")]
|
|
||||||
println!(" -f <conf_file> 读取配置文件中的配置");
|
|
||||||
|
|
||||||
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
|
|
||||||
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
|
|
||||||
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
|
|
||||||
if !enums.is_empty() {
|
|
||||||
println!(
|
|
||||||
" --model <model> 加密模式(默认aes_gcm),可选值{}",
|
|
||||||
&enums[1..]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if !enums.is_empty() {
|
|
||||||
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
|
|
||||||
}
|
|
||||||
println!(" --punch <punch> 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞");
|
|
||||||
println!(" --ports <port,port> 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
|
|
||||||
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
|
|
||||||
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
|
|
||||||
println!(" --nic <tun0> 指定虚拟网卡名称");
|
|
||||||
println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网");
|
|
||||||
println!(
|
|
||||||
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
|
|
||||||
);
|
|
||||||
println!(" --dns <host:port> DNS服务器地址,可使用多个dns,不指定时使用系统解析");
|
|
||||||
#[cfg(feature = "port_mapping")]
|
|
||||||
println!(" --mapping <mapping> 端口映射,例如 --mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.10:80");
|
|
||||||
#[cfg(all(feature = "lz4", feature = "zstd"))]
|
|
||||||
println!(" --compressor <lz4> 启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10");
|
|
||||||
#[cfg(feature = "lz4")]
|
|
||||||
#[cfg(not(feature = "zstd"))]
|
|
||||||
println!(" --compressor <lz4> 启用压缩,可选值lz4,例如 --compressor lz4");
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
#[cfg(not(feature = "lz4"))]
|
|
||||||
println!(" --compressor <zstd> 启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10");
|
|
||||||
println!();
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
{
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
fn yellow(str: String) -> impl std::fmt::Display {
|
|
||||||
style(str).yellow()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "vnt-jni"
|
|
||||||
version = "1.2.10"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
common = { path = "../common" }
|
|
||||||
vnt = {path="../vnt"}
|
|
||||||
parking_lot = "0.12.1"
|
|
||||||
|
|
||||||
jni = { version = "0.21.1", default-features = false }
|
|
||||||
log = "0.4.20"
|
|
||||||
spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64","pem"]}
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
|
||||||
android_logger = "0.13"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = ["staticlib", "cdylib"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
## 提供给安卓端使用
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni;
|
|
||||||
|
|
||||||
import top.wherewego.vnt.jni.param.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回调
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public interface CallBack {
|
|
||||||
/**
|
|
||||||
* 连接成功的回调
|
|
||||||
*/
|
|
||||||
void success();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建虚拟网卡成功的回调方法
|
|
||||||
* 仅在 windows/linux/macos上使用
|
|
||||||
*
|
|
||||||
* @param info 网卡信息
|
|
||||||
*/
|
|
||||||
void createTun(DeviceInfo info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 连接服务端
|
|
||||||
*
|
|
||||||
* @param info 将要连接的服务端信息
|
|
||||||
*/
|
|
||||||
void connect(ConnectInfo info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 和服务端握手
|
|
||||||
*
|
|
||||||
* @param info 握手信息
|
|
||||||
* @return 是否确认握手
|
|
||||||
*/
|
|
||||||
boolean handshake(HandshakeInfo info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册成功回调
|
|
||||||
*
|
|
||||||
* @param info 注册信息
|
|
||||||
* @return 是否确认注册信息
|
|
||||||
*/
|
|
||||||
boolean register(RegisterInfo info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建网卡回调
|
|
||||||
* 仅在android上使用
|
|
||||||
*
|
|
||||||
* @param info 创建配置
|
|
||||||
* @return 网卡fd
|
|
||||||
*/
|
|
||||||
|
|
||||||
int generateTun(DeviceConfig info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对端用户列表
|
|
||||||
*
|
|
||||||
* @param infoArray
|
|
||||||
*/
|
|
||||||
void peerClientList(PeerClientInfo[] infoArray);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异常回调
|
|
||||||
*
|
|
||||||
* @param info 错误信息
|
|
||||||
*/
|
|
||||||
void error(ErrorInfo info);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务停止
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,333 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动配置
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class Config implements Serializable {
|
|
||||||
/**
|
|
||||||
* 是否是tap模式,仅支持windows
|
|
||||||
*/
|
|
||||||
private boolean tap;
|
|
||||||
/**
|
|
||||||
* 组网标识
|
|
||||||
*/
|
|
||||||
private String token;
|
|
||||||
/**
|
|
||||||
* 设备名称
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
/**
|
|
||||||
* 客户端间加密的密码
|
|
||||||
*/
|
|
||||||
private String password;
|
|
||||||
/**
|
|
||||||
* 客户端间加密模式 aes_gcm/aes_cbc/aes_ecb/sm4_cbc
|
|
||||||
*/
|
|
||||||
private String cipherModel;
|
|
||||||
/**
|
|
||||||
* 打洞模式 ipv4/ipv6/all
|
|
||||||
*/
|
|
||||||
private String punchModel;
|
|
||||||
/**
|
|
||||||
* mtu 默认自动计算
|
|
||||||
*/
|
|
||||||
private Integer mtu;
|
|
||||||
/**
|
|
||||||
* 是否开启服务端加密
|
|
||||||
*/
|
|
||||||
private boolean serverEncrypt;
|
|
||||||
/**
|
|
||||||
* 设备id,请使用唯一值
|
|
||||||
*/
|
|
||||||
private String deviceId;
|
|
||||||
/**
|
|
||||||
* 服务端地址
|
|
||||||
*/
|
|
||||||
private String server;
|
|
||||||
/**
|
|
||||||
* dns地址
|
|
||||||
*/
|
|
||||||
private String[] dns;
|
|
||||||
/**
|
|
||||||
* 端口映射
|
|
||||||
*/
|
|
||||||
private String[] portMapping;
|
|
||||||
/**
|
|
||||||
* stun服务地址
|
|
||||||
*/
|
|
||||||
private String[] stunServer;
|
|
||||||
/**
|
|
||||||
* 和服务端使用tcp通信,默认使用udp
|
|
||||||
*/
|
|
||||||
private boolean tcp;
|
|
||||||
/**
|
|
||||||
* 指定组网IP
|
|
||||||
*/
|
|
||||||
private String ip;
|
|
||||||
/**
|
|
||||||
* 开启加密指纹校验
|
|
||||||
*/
|
|
||||||
private boolean finger;
|
|
||||||
/**
|
|
||||||
* 延迟优先,默认p2p优先
|
|
||||||
*/
|
|
||||||
private boolean firstLatency;
|
|
||||||
/**
|
|
||||||
* 点对网入口 格式 192.168.0.0/26,10.26.0.2
|
|
||||||
*/
|
|
||||||
private String[] inIps;
|
|
||||||
/**
|
|
||||||
* 点对网出口 格式 192.168.0.0/26
|
|
||||||
*/
|
|
||||||
private String[] outIps;
|
|
||||||
/**
|
|
||||||
* 端口组,udp会监听一组端口,tcp监听ports[0]端口
|
|
||||||
*/
|
|
||||||
private int[] ports;
|
|
||||||
/**
|
|
||||||
* 虚拟网卡名称 仅在linux、windows、macos上支持
|
|
||||||
*/
|
|
||||||
private String deviceName;
|
|
||||||
/**
|
|
||||||
* enum: relay/p2p/all
|
|
||||||
*/
|
|
||||||
private String useChannel;
|
|
||||||
/**
|
|
||||||
* 模拟丢包率,取0~1之间的数,为null表示不丢包,1表示全部丢包
|
|
||||||
*/
|
|
||||||
private Double packetLossRate;
|
|
||||||
/**
|
|
||||||
* 模拟延迟 单位毫秒(ms)
|
|
||||||
*/
|
|
||||||
private Integer packetDelay;
|
|
||||||
|
|
||||||
public Config() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTap() {
|
|
||||||
return tap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTap(boolean tap) {
|
|
||||||
this.tap = tap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getToken() {
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setToken(String token) {
|
|
||||||
this.token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCipherModel() {
|
|
||||||
return cipherModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCipherModel(String cipherModel) {
|
|
||||||
this.cipherModel = cipherModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPunchModel() {
|
|
||||||
return punchModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPunchModel(String punchModel) {
|
|
||||||
this.punchModel = punchModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getMtu() {
|
|
||||||
return mtu;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMtu(Integer mtu) {
|
|
||||||
this.mtu = mtu;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isServerEncrypt() {
|
|
||||||
return serverEncrypt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setServerEncrypt(boolean serverEncrypt) {
|
|
||||||
this.serverEncrypt = serverEncrypt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getDeviceId() {
|
|
||||||
return deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeviceId(String deviceId) {
|
|
||||||
this.deviceId = deviceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getServer() {
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setServer(String server) {
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getDns() {
|
|
||||||
return dns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDns(String[] dns) {
|
|
||||||
this.dns = dns;
|
|
||||||
}
|
|
||||||
public String[] getPortMapping() {
|
|
||||||
return portMapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPortMapping(String[] portMapping) {
|
|
||||||
this.portMapping = portMapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getStunServer() {
|
|
||||||
return stunServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStunServer(String[] stunServer) {
|
|
||||||
this.stunServer = stunServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTcp() {
|
|
||||||
return tcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTcp(boolean tcp) {
|
|
||||||
this.tcp = tcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIp() {
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIp(String ip) {
|
|
||||||
this.ip = ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFinger() {
|
|
||||||
return finger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFinger(boolean finger) {
|
|
||||||
this.finger = finger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFirstLatency() {
|
|
||||||
return firstLatency;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstLatency(boolean firstLatency) {
|
|
||||||
this.firstLatency = firstLatency;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getInIps() {
|
|
||||||
return inIps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInIps(String[] inIps) {
|
|
||||||
this.inIps = inIps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getOutIps() {
|
|
||||||
return outIps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOutIps(String[] outIps) {
|
|
||||||
this.outIps = outIps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getPorts() {
|
|
||||||
return ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPorts(int[] ports) {
|
|
||||||
this.ports = ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceName() {
|
|
||||||
return deviceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeviceName(String deviceName) {
|
|
||||||
this.deviceName = deviceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUseChannel() {
|
|
||||||
return useChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUseChannel(String useChannel) {
|
|
||||||
this.useChannel = useChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Double getPacketLossRate() {
|
|
||||||
return packetLossRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPacketLossRate(Double packetLossRate) {
|
|
||||||
this.packetLossRate = packetLossRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getPacketDelay() {
|
|
||||||
return packetDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPacketDelay(Integer packetDelay) {
|
|
||||||
this.packetDelay = packetDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Config{" +
|
|
||||||
"tap=" + tap +
|
|
||||||
", token='" + token + '\'' +
|
|
||||||
", name='" + name + '\'' +
|
|
||||||
", password='" + password + '\'' +
|
|
||||||
", cipherModel='" + cipherModel + '\'' +
|
|
||||||
", punchModel='" + punchModel + '\'' +
|
|
||||||
", mtu=" + mtu +
|
|
||||||
", serverEncrypt=" + serverEncrypt +
|
|
||||||
", deviceId='" + deviceId + '\'' +
|
|
||||||
", server='" + server + '\'' +
|
|
||||||
", dns=" + Arrays.toString(dns) +
|
|
||||||
", portMapping=" + Arrays.toString(portMapping) +
|
|
||||||
", stunServer=" + Arrays.toString(stunServer) +
|
|
||||||
", tcp=" + tcp +
|
|
||||||
", ip='" + ip + '\'' +
|
|
||||||
", finger=" + finger +
|
|
||||||
", firstLatency=" + firstLatency +
|
|
||||||
", inIps=" + Arrays.toString(inIps) +
|
|
||||||
", outIps=" + Arrays.toString(outIps) +
|
|
||||||
", ports=" + Arrays.toString(ports) +
|
|
||||||
", deviceName='" + deviceName + '\'' +
|
|
||||||
", useChannel='" + useChannel + '\'' +
|
|
||||||
", packetLossRate=" + packetLossRate +
|
|
||||||
", packetDelay=" + packetDelay +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ip转换
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class IpUtils {
|
|
||||||
/**
|
|
||||||
* 将整数的ip地址转成字符串,例如 0 转成 "0.0.0.0"
|
|
||||||
*
|
|
||||||
* @param ipAddress
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String intToIpAddress(int ipAddress) {
|
|
||||||
|
|
||||||
return ((ipAddress & 0xFF000000) >>> 24) + "." +
|
|
||||||
((ipAddress & 0x00FF0000) >>> 16) + "." +
|
|
||||||
((ipAddress & 0x0000FF00) >>> 8) + "." +
|
|
||||||
(ipAddress & 0x000000FF);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回掩码的长度
|
|
||||||
*
|
|
||||||
* @param subnetMask
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static int subnetMaskToPrefixLength(int subnetMask) {
|
|
||||||
int prefixLength = 0;
|
|
||||||
int bit = 1 << 31;
|
|
||||||
|
|
||||||
while (subnetMask != 0) {
|
|
||||||
if ((subnetMask & bit) != bit) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prefixLength++;
|
|
||||||
subnetMask <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefixLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对端设备信息
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class PeerRouteInfo {
|
|
||||||
private final int virtualIp;
|
|
||||||
private final String name;
|
|
||||||
private final String status;
|
|
||||||
private final Route route;
|
|
||||||
|
|
||||||
public PeerRouteInfo(int virtualIp, String name, String status, Route route) {
|
|
||||||
this.virtualIp = virtualIp;
|
|
||||||
this.name = name;
|
|
||||||
this.status = status;
|
|
||||||
this.route = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualIp() {
|
|
||||||
return virtualIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Route getRoute() {
|
|
||||||
return route;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "PeerDeviceInfo{" +
|
|
||||||
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
|
|
||||||
", name='" + name + '\'' +
|
|
||||||
", status='" + status + '\'' +
|
|
||||||
", route=" + route +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 路由信息
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class Route {
|
|
||||||
/**
|
|
||||||
* 是否使用tcp
|
|
||||||
*/
|
|
||||||
private final boolean tcp;
|
|
||||||
private final String address;
|
|
||||||
private final byte metric;
|
|
||||||
private final int rt;
|
|
||||||
|
|
||||||
|
|
||||||
public Route(boolean tcp, String address, byte metric, int rt) {
|
|
||||||
this.tcp = tcp;
|
|
||||||
this.address = address;
|
|
||||||
this.metric = metric;
|
|
||||||
this.rt = rt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTcp() {
|
|
||||||
return tcp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getMetric() {
|
|
||||||
return metric;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRt() {
|
|
||||||
return rt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Route{" +
|
|
||||||
"tcp=" + tcp +
|
|
||||||
", address='" + address + '\'' +
|
|
||||||
", metric=" + metric +
|
|
||||||
", rt=" + rt +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* vnt的Java映射
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class Vnt implements Closeable {
|
|
||||||
private final long raw;
|
|
||||||
|
|
||||||
public Vnt(Config config, CallBack callBack) throws Exception {
|
|
||||||
this.raw = new0(config, callBack);
|
|
||||||
if (this.raw == 0) {
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
stop0(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void await() {
|
|
||||||
wait0(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean awaitTimeout(long ms) {
|
|
||||||
return waitTimeout0(raw, ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PeerRouteInfo[] list() {
|
|
||||||
return list0(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
private native long new0(Config config, CallBack callBack) throws Exception;
|
|
||||||
|
|
||||||
private native void stop0(long raw);
|
|
||||||
|
|
||||||
private native void wait0(long raw);
|
|
||||||
|
|
||||||
private native boolean waitTimeout0(long raw, long ms);
|
|
||||||
|
|
||||||
private native void drop0(long raw);
|
|
||||||
|
|
||||||
private native PeerRouteInfo[] list0(long raw);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
drop0(raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni.param;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 连接信息
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class ConnectInfo {
|
|
||||||
private final long count;
|
|
||||||
private final String address;
|
|
||||||
|
|
||||||
public ConnectInfo(long count, String address) {
|
|
||||||
this.count = count;
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCount() {
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ConnectInfo{" +
|
|
||||||
"count=" + count +
|
|
||||||
", address='" + address + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni.param;
|
|
||||||
|
|
||||||
import top.wherewego.vnt.jni.IpUtils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建网卡所需信息,仅在android上使用
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class DeviceConfig {
|
|
||||||
/**
|
|
||||||
* 虚拟IP
|
|
||||||
*/
|
|
||||||
public final int virtualIp;
|
|
||||||
/**
|
|
||||||
* 掩码
|
|
||||||
*/
|
|
||||||
public final int virtualNetmask;
|
|
||||||
/**
|
|
||||||
* 网关
|
|
||||||
*/
|
|
||||||
public final int virtualGateway;
|
|
||||||
/**
|
|
||||||
* 虚拟网段
|
|
||||||
*/
|
|
||||||
public final int virtualNetwork;
|
|
||||||
/**
|
|
||||||
* 额外路由,来自点对网的路由配置
|
|
||||||
*/
|
|
||||||
public final String[] externalRoute;
|
|
||||||
|
|
||||||
public DeviceConfig(int virtualIp, int virtualNetmask, int virtualGateway, int virtualNetwork, String[] externalRoute) {
|
|
||||||
this.virtualIp = virtualIp;
|
|
||||||
this.virtualNetmask = virtualNetmask;
|
|
||||||
this.virtualGateway = virtualGateway;
|
|
||||||
this.virtualNetwork = virtualNetwork;
|
|
||||||
this.externalRoute = externalRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualIp() {
|
|
||||||
return virtualIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualNetmask() {
|
|
||||||
return virtualNetmask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualGateway() {
|
|
||||||
return virtualGateway;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualNetwork() {
|
|
||||||
return virtualNetwork;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getExternalRoute() {
|
|
||||||
return externalRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "DeviceConfig{" +
|
|
||||||
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
|
|
||||||
", virtualNetmask=" + IpUtils.intToIpAddress(virtualNetmask) +
|
|
||||||
", virtualGateway=" + IpUtils.intToIpAddress(virtualGateway) +
|
|
||||||
", virtualNetwork=" + IpUtils.intToIpAddress(virtualNetwork) +
|
|
||||||
", externalRoute=" + Arrays.toString(externalRoute) +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni.param;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 网卡信息 仅在 windows/linux/macos上使用
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class DeviceInfo {
|
|
||||||
/**
|
|
||||||
* 虚拟网卡名称
|
|
||||||
*/
|
|
||||||
private final String name;
|
|
||||||
/**
|
|
||||||
* 虚拟网卡版本
|
|
||||||
*/
|
|
||||||
private final String version;
|
|
||||||
|
|
||||||
public DeviceInfo(String name, String version) {
|
|
||||||
this.name = name;
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "DeviceInfo{" +
|
|
||||||
"name='" + name + '\'' +
|
|
||||||
", version='" + version + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni.param;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异常回调信息
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class ErrorInfo {
|
|
||||||
/**
|
|
||||||
* 错误码
|
|
||||||
*/
|
|
||||||
public final ErrorCodeEnum code;
|
|
||||||
/**
|
|
||||||
* 错误信息,可能为空
|
|
||||||
*/
|
|
||||||
public final String msg;
|
|
||||||
|
|
||||||
public ErrorInfo(int code, String msg) {
|
|
||||||
switch (code) {
|
|
||||||
case 1:
|
|
||||||
this.code = ErrorCodeEnum.TokenError;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
this.code = ErrorCodeEnum.Disconnect;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
this.code = ErrorCodeEnum.AddressExhausted;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
this.code = ErrorCodeEnum.IpAlreadyExists;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
this.code = ErrorCodeEnum.InvalidIp;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.code = ErrorCodeEnum.Unknown;
|
|
||||||
}
|
|
||||||
this.msg = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ErrorCodeEnum getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMsg() {
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ErrorCodeEnum {
|
|
||||||
TokenError,
|
|
||||||
Disconnect,
|
|
||||||
AddressExhausted,
|
|
||||||
IpAlreadyExists,
|
|
||||||
InvalidIp,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ErrorInfo{" +
|
|
||||||
"code=" + code +
|
|
||||||
", msg='" + msg + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni.param;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 握手回调信息
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class HandshakeInfo {
|
|
||||||
/**
|
|
||||||
* 公钥 pem格式 CRLF分隔,不加密时为空
|
|
||||||
*/
|
|
||||||
private final String publicKey;
|
|
||||||
/**
|
|
||||||
* 公钥签名,不加密时为空
|
|
||||||
*/
|
|
||||||
private final String finger;
|
|
||||||
/**
|
|
||||||
* 服务端版本
|
|
||||||
*/
|
|
||||||
private final String version;
|
|
||||||
|
|
||||||
public HandshakeInfo() {
|
|
||||||
this.publicKey = "publicKey";
|
|
||||||
this.finger = "finger";
|
|
||||||
this.version = "version";
|
|
||||||
}
|
|
||||||
|
|
||||||
public HandshakeInfo(String publicKey, String finger, String version) {
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
this.finger = finger;
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPublicKey() {
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFinger() {
|
|
||||||
return finger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "HandshakeInfo{" +
|
|
||||||
"publicKey='" + publicKey + '\'' +
|
|
||||||
", finger='" + finger + '\'' +
|
|
||||||
", version='" + version + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni.param;
|
|
||||||
|
|
||||||
import top.wherewego.vnt.jni.IpUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建网卡所需信息,仅在android上使用
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class PeerClientInfo {
|
|
||||||
/**
|
|
||||||
* 虚拟IP
|
|
||||||
*/
|
|
||||||
public final int virtualIp;
|
|
||||||
/**
|
|
||||||
* 名称
|
|
||||||
*/
|
|
||||||
public final String name;
|
|
||||||
/**
|
|
||||||
* 是否在线
|
|
||||||
*/
|
|
||||||
public final boolean online;
|
|
||||||
/**
|
|
||||||
* 是否开启客户端加密,不同加密状态的不能通信
|
|
||||||
*/
|
|
||||||
public final boolean clientSecret;
|
|
||||||
|
|
||||||
public PeerClientInfo(int virtualIp, String name, boolean online, boolean clientSecret) {
|
|
||||||
this.virtualIp = virtualIp;
|
|
||||||
this.name = name;
|
|
||||||
this.online = online;
|
|
||||||
this.clientSecret = clientSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualIp() {
|
|
||||||
return virtualIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOnline() {
|
|
||||||
return online;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isClientSecret() {
|
|
||||||
return clientSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "PeerDeviceInfo{" +
|
|
||||||
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
|
|
||||||
", name='" + name + '\'' +
|
|
||||||
", online=" + online +
|
|
||||||
", clientSecret=" + clientSecret +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
package top.wherewego.vnt.jni.param;
|
|
||||||
|
|
||||||
import top.wherewego.vnt.jni.IpUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册回调信息
|
|
||||||
*
|
|
||||||
* @author https://github.com/lbl8603/vnt
|
|
||||||
*/
|
|
||||||
public class RegisterInfo {
|
|
||||||
/**
|
|
||||||
* 虚拟IP
|
|
||||||
*/
|
|
||||||
public final int virtualIp;
|
|
||||||
/**
|
|
||||||
* 掩码
|
|
||||||
*/
|
|
||||||
public final int virtualNetmask;
|
|
||||||
/**
|
|
||||||
* 网关
|
|
||||||
*/
|
|
||||||
public final int virtualGateway;
|
|
||||||
|
|
||||||
public RegisterInfo(int virtualIp, int virtualNetmask, int virtualGateway) {
|
|
||||||
this.virtualIp = virtualIp;
|
|
||||||
this.virtualNetmask = virtualNetmask;
|
|
||||||
this.virtualGateway = virtualGateway;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualIp() {
|
|
||||||
return virtualIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualNetmask() {
|
|
||||||
return virtualNetmask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVirtualGateway() {
|
|
||||||
return virtualGateway;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "RegisterInfo{" +
|
|
||||||
"virtualIp='" + IpUtils.intToIpAddress(virtualIp) + '\'' +
|
|
||||||
", virtualNetmask='" + IpUtils.intToIpAddress(virtualNetmask) + '\'' +
|
|
||||||
", virtualGateway='" + IpUtils.intToIpAddress(virtualGateway) + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,322 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use jni::objects::{GlobalRef, JClass, JObject, JString, JValue};
|
|
||||||
use jni::{JNIEnv, JavaVM};
|
|
||||||
use spki::der::pem::LineEnding;
|
|
||||||
use spki::EncodePublicKey;
|
|
||||||
|
|
||||||
use vnt::handle::callback::ConnectInfo;
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use vnt::handle::callback::DeviceConfig;
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
use vnt::DeviceInfo;
|
|
||||||
use vnt::{ErrorInfo, HandshakeInfo, PeerClientInfo, RegisterInfo, VntCallback};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CallBack {
|
|
||||||
jvm: Arc<JavaVM>,
|
|
||||||
this: GlobalRef,
|
|
||||||
connect_info_class: GlobalRef,
|
|
||||||
handshake_info_class: GlobalRef,
|
|
||||||
error_info_class: GlobalRef,
|
|
||||||
register_info_class: GlobalRef,
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
device_config_class: GlobalRef,
|
|
||||||
peer_client_info_class: GlobalRef,
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
device_info_class: GlobalRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for CallBack {}
|
|
||||||
|
|
||||||
fn find_class_global_ref(env: &mut JNIEnv, class: &str) -> jni::errors::Result<GlobalRef> {
|
|
||||||
let class = env.find_class(class)?;
|
|
||||||
env.new_global_ref(class)
|
|
||||||
}
|
|
||||||
impl CallBack {
|
|
||||||
pub fn new(jvm: JavaVM, this: GlobalRef) -> jni::errors::Result<Self> {
|
|
||||||
let mut env = jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let connect_info_class =
|
|
||||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ConnectInfo")?;
|
|
||||||
let handshake_info_class =
|
|
||||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/HandshakeInfo")?;
|
|
||||||
let error_info_class =
|
|
||||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ErrorInfo")?;
|
|
||||||
let register_info_class =
|
|
||||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/RegisterInfo")?;
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
let device_config_class = crate::callback::find_class_global_ref(
|
|
||||||
&mut env,
|
|
||||||
"top/wherewego/vnt/jni/param/DeviceConfig",
|
|
||||||
)?;
|
|
||||||
let peer_client_info_class =
|
|
||||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/PeerClientInfo")?;
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
let device_info_class =
|
|
||||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/DeviceInfo")?;
|
|
||||||
Ok(Self {
|
|
||||||
jvm: Arc::new(jvm),
|
|
||||||
this,
|
|
||||||
connect_info_class,
|
|
||||||
handshake_info_class,
|
|
||||||
error_info_class,
|
|
||||||
register_info_class,
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
device_config_class,
|
|
||||||
peer_client_info_class,
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
device_info_class,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CallBack {
|
|
||||||
fn success0(&self) -> jni::errors::Result<()> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
env.call_method(&self.this, "success", "()V", &[])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
fn create_tun0(&self, info: DeviceInfo) -> jni::errors::Result<()> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let class = unsafe { JClass::from_raw(self.device_info_class.as_raw()) };
|
|
||||||
let param = env.new_object(
|
|
||||||
class,
|
|
||||||
"(Ljava/lang/String;Ljava/lang/String;)V",
|
|
||||||
&[
|
|
||||||
JValue::Object(&env.new_string(info.name)?.into()),
|
|
||||||
JValue::Object(&env.new_string(info.version)?.into()),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
env.call_method(
|
|
||||||
&self.this,
|
|
||||||
"createTun",
|
|
||||||
"(Ltop/wherewego/vnt/jni/param/DeviceInfo;)V",
|
|
||||||
&[JValue::Object(¶m)],
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn connect0(&self, info: ConnectInfo) -> jni::errors::Result<()> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let class = unsafe { JClass::from_raw(self.connect_info_class.as_raw()) };
|
|
||||||
let param = env.new_object(
|
|
||||||
class,
|
|
||||||
"(JLjava/lang/String;)V",
|
|
||||||
&[
|
|
||||||
JValue::Long(info.count as _),
|
|
||||||
JValue::Object(&env.new_string(info.address.to_string())?.into()),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
env.call_method(
|
|
||||||
&self.this,
|
|
||||||
"connect",
|
|
||||||
"(Ltop/wherewego/vnt/jni/param/ConnectInfo;)V",
|
|
||||||
&[JValue::Object(¶m)],
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn handshake0(&self, info: HandshakeInfo) -> jni::errors::Result<bool> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let public_key = if let Some(public_key) = info.public_key {
|
|
||||||
match public_key.to_public_key_pem(LineEnding::CRLF) {
|
|
||||||
Ok(public_key) => env.new_string(public_key)?,
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
JString::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JString::default()
|
|
||||||
};
|
|
||||||
let finger = if let Some(finger) = info.finger {
|
|
||||||
env.new_string(finger)?
|
|
||||||
} else {
|
|
||||||
JString::default()
|
|
||||||
};
|
|
||||||
let class = unsafe { JClass::from_raw(self.handshake_info_class.as_raw()) };
|
|
||||||
|
|
||||||
let param = env.new_object(
|
|
||||||
class,
|
|
||||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
|
|
||||||
&[
|
|
||||||
JValue::Object(&public_key),
|
|
||||||
JValue::Object(&finger),
|
|
||||||
JValue::Object(&env.new_string(info.version)?.into()),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
let rs = env.call_method(
|
|
||||||
&self.this,
|
|
||||||
"handshake",
|
|
||||||
"(Ltop/wherewego/vnt/jni/param/HandshakeInfo;)Z",
|
|
||||||
&[JValue::Object(¶m)],
|
|
||||||
)?;
|
|
||||||
rs.z()
|
|
||||||
}
|
|
||||||
fn register0(&self, info: RegisterInfo) -> jni::errors::Result<bool> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let class = unsafe { JClass::from_raw(self.register_info_class.as_raw()) };
|
|
||||||
let param = env.new_object(
|
|
||||||
class,
|
|
||||||
"(III)V",
|
|
||||||
&[
|
|
||||||
JValue::Int(u32::from(info.virtual_ip) as _),
|
|
||||||
JValue::Int(u32::from(info.virtual_netmask) as _),
|
|
||||||
JValue::Int(u32::from(info.virtual_gateway) as _),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
let rs = env.call_method(
|
|
||||||
&self.this,
|
|
||||||
"register",
|
|
||||||
"(Ltop/wherewego/vnt/jni/param/RegisterInfo;)Z",
|
|
||||||
&[JValue::Object(¶m)],
|
|
||||||
)?;
|
|
||||||
rs.z()
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
fn generate_tun0(&self, info: DeviceConfig) -> jni::errors::Result<u32> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let class = unsafe { JClass::from_raw(self.device_config_class.as_raw()) };
|
|
||||||
|
|
||||||
let object_array = env.new_object_array(
|
|
||||||
info.external_route.len() as _,
|
|
||||||
"java/lang/String",
|
|
||||||
JObject::null(),
|
|
||||||
)?;
|
|
||||||
for (index, (network, mask)) in info.external_route.into_iter().enumerate() {
|
|
||||||
let param =
|
|
||||||
env.new_string(format!("{}/{}", network, u32::from(mask).leading_ones()))?;
|
|
||||||
env.set_object_array_element(&object_array, index as _, ¶m)?;
|
|
||||||
}
|
|
||||||
let param = env.new_object(
|
|
||||||
class,
|
|
||||||
"(IIII[Ljava/lang/String;)V",
|
|
||||||
&[
|
|
||||||
JValue::Int(u32::from(info.virtual_ip) as _),
|
|
||||||
JValue::Int(u32::from(info.virtual_netmask) as _),
|
|
||||||
JValue::Int(u32::from(info.virtual_gateway) as _),
|
|
||||||
JValue::Int(u32::from(info.virtual_network) as _),
|
|
||||||
JValue::Object(&object_array),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
let rs = env.call_method(
|
|
||||||
&self.this,
|
|
||||||
"generateTun",
|
|
||||||
"(Ltop/wherewego/vnt/jni/param/DeviceConfig;)I",
|
|
||||||
&[JValue::Object(¶m)],
|
|
||||||
)?;
|
|
||||||
rs.i().map(|v| v as _)
|
|
||||||
}
|
|
||||||
fn peer_client_list0(&self, info_vec: Vec<PeerClientInfo>) -> jni::errors::Result<()> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let class = unsafe { JClass::from_raw(self.peer_client_info_class.as_raw()) };
|
|
||||||
let object_array = env.new_object_array(info_vec.len() as _, &class, JObject::null())?;
|
|
||||||
for (index, info) in info_vec.into_iter().enumerate() {
|
|
||||||
let param = env.new_object(
|
|
||||||
&class,
|
|
||||||
"(ILjava/lang/String;ZZ)V",
|
|
||||||
&[
|
|
||||||
JValue::Int(u32::from(info.virtual_ip) as _),
|
|
||||||
JValue::Object(&env.new_string(info.name)?.into()),
|
|
||||||
JValue::Bool(info.status.is_online() as _),
|
|
||||||
JValue::Bool(info.client_secret as _),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
env.set_object_array_element(&object_array, index as _, ¶m)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
env.call_method(
|
|
||||||
&self.this,
|
|
||||||
"peerClientList",
|
|
||||||
"([Ltop/wherewego/vnt/jni/param/PeerClientInfo;)V",
|
|
||||||
&[JValue::Object(&object_array)],
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error0(&self, info: ErrorInfo) -> jni::errors::Result<()> {
|
|
||||||
let code: u8 = info.code.into();
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
let class = unsafe { JClass::from_raw(self.error_info_class.as_raw()) };
|
|
||||||
let msg = if let Some(msg) = info.msg {
|
|
||||||
env.new_string(msg)?
|
|
||||||
} else {
|
|
||||||
JString::default()
|
|
||||||
};
|
|
||||||
let param = env.new_object(
|
|
||||||
class,
|
|
||||||
"(ILjava/lang/String;)V",
|
|
||||||
&[JValue::Int(code as _), JValue::Object(&msg.into())],
|
|
||||||
)?;
|
|
||||||
env.call_method(
|
|
||||||
&self.this,
|
|
||||||
"error",
|
|
||||||
"(Ltop/wherewego/vnt/jni/param/ErrorInfo;)V",
|
|
||||||
&[JValue::Object(¶m)],
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn stop0(&self) -> jni::errors::Result<()> {
|
|
||||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
|
||||||
env.call_method(&self.this, "stop", "()V", &[])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VntCallback for CallBack {
|
|
||||||
fn success(&self) {
|
|
||||||
if let Err(e) = self.success0() {
|
|
||||||
log::warn!("success {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
fn create_tun(&self, info: DeviceInfo) {
|
|
||||||
if let Err(e) = self.create_tun0(info) {
|
|
||||||
log::warn!("create_tun {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn connect(&self, info: ConnectInfo) {
|
|
||||||
if let Err(e) = self.connect0(info) {
|
|
||||||
log::warn!("connect {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handshake(&self, info: HandshakeInfo) -> bool {
|
|
||||||
self.handshake0(info).unwrap_or_else(|e| {
|
|
||||||
log::warn!("handshake {:?}", e);
|
|
||||||
false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register(&self, info: RegisterInfo) -> bool {
|
|
||||||
self.register0(info).unwrap_or_else(|e| {
|
|
||||||
log::warn!("register {:?}", e);
|
|
||||||
false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
fn generate_tun(&self, info: DeviceConfig) -> u32 {
|
|
||||||
self.generate_tun0(info).unwrap_or_else(|e| {
|
|
||||||
log::warn!("generate_tun {:?}", e);
|
|
||||||
0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peer_client_list(&self, info: Vec<PeerClientInfo>) {
|
|
||||||
if let Err(e) = self.peer_client_list0(info) {
|
|
||||||
log::warn!("peer_client_list {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error(&self, info: ErrorInfo) {
|
|
||||||
if let Err(e) = self.error0(info) {
|
|
||||||
log::warn!("error {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self) {
|
|
||||||
if let Err(e) = self.stop0() {
|
|
||||||
log::warn!("stop {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use jni::errors::Error;
|
|
||||||
use jni::objects::JObject;
|
|
||||||
use jni::JNIEnv;
|
|
||||||
|
|
||||||
use vnt::channel::punch::PunchModel;
|
|
||||||
use vnt::channel::UseChannelType;
|
|
||||||
use vnt::cipher::CipherModel;
|
|
||||||
use vnt::compression::Compressor;
|
|
||||||
use vnt::core::Config;
|
|
||||||
|
|
||||||
use crate::utils::*;
|
|
||||||
|
|
||||||
pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
let tap = env.get_field(&config, "tap", "Z")?.z()?;
|
|
||||||
let token = to_string_not_null(env, &config, "token")?;
|
|
||||||
let name = to_string_not_null(env, &config, "name")?;
|
|
||||||
let device_id = to_string_not_null(env, &config, "deviceId")?;
|
|
||||||
let password = to_string(env, &config, "password")?;
|
|
||||||
let server_address_str = to_string_not_null(env, &config, "server")?;
|
|
||||||
let stun_server = to_string_array_not_null(env, &config, "stunServer")?;
|
|
||||||
let dns = to_string_array(env, &config, "dns")?.unwrap_or_else(|| vec![]);
|
|
||||||
let port_mapping = to_string_array(env, &config, "portMapping")?.unwrap_or_else(|| vec![]);
|
|
||||||
let cipher_model = to_string_not_null(env, &config, "cipherModel")?;
|
|
||||||
let punch_model = to_string(env, &config, "punchModel")?;
|
|
||||||
let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32);
|
|
||||||
let tcp = env.get_field(&config, "tcp", "Z")?.z()?;
|
|
||||||
let server_encrypt = env.get_field(&config, "serverEncrypt", "Z")?.z()?;
|
|
||||||
let use_channel = to_string(env, &config, "useChannel")?;
|
|
||||||
let finger = env.get_field(&config, "finger", "Z")?.z()?;
|
|
||||||
let first_latency = env.get_field(&config, "firstLatency", "Z")?.z()?;
|
|
||||||
let packet_delay = to_integer(env, &config, "packetDelay")?
|
|
||||||
.map(|v| v as u32)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let packet_loss_rate = to_double(env, &config, "packetLossRate")?;
|
|
||||||
|
|
||||||
let in_ips = to_string_array(env, &config, "inIps")?;
|
|
||||||
let out_ips = to_string_array(env, &config, "outIps")?;
|
|
||||||
let ports =
|
|
||||||
to_i32_array(env, &config, "ports")?.map(|v| v.into_iter().map(|v| v as u16).collect());
|
|
||||||
let ip = if let Some(ip) = to_string(env, &config, "ip")? {
|
|
||||||
match ip.parse() {
|
|
||||||
Ok(ip) => Some(ip),
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new(
|
|
||||||
"java/lang/RuntimeException",
|
|
||||||
format!("ip {} err: {}", ip, e),
|
|
||||||
)
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let in_ips = if let Some(in_ips) = in_ips {
|
|
||||||
match common::args_parse::ips_parse(&in_ips) {
|
|
||||||
Ok(in_ips) => in_ips,
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", format!("in_ips {}", e))
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
let out_ips = if let Some(out_ips) = out_ips {
|
|
||||||
match common::args_parse::out_ips_parse(&out_ips) {
|
|
||||||
Ok(out_ips) => out_ips,
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", format!("out_ips {}", e))
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
|
|
||||||
let cipher_model = match CipherModel::from_str(&cipher_model) {
|
|
||||||
Ok(cipher_model) => cipher_model,
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", format!("cipher_model {}", e))
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
let device_name = to_string(env, &config, "deviceName")?;
|
|
||||||
let config = match Config::new(
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
tap,
|
|
||||||
token,
|
|
||||||
device_id,
|
|
||||||
name,
|
|
||||||
server_address_str,
|
|
||||||
dns,
|
|
||||||
stun_server,
|
|
||||||
in_ips,
|
|
||||||
out_ips,
|
|
||||||
password,
|
|
||||||
mtu,
|
|
||||||
tcp,
|
|
||||||
ip,
|
|
||||||
false,
|
|
||||||
server_encrypt,
|
|
||||||
1,
|
|
||||||
cipher_model,
|
|
||||||
finger,
|
|
||||||
PunchModel::from_str(&punch_model.unwrap_or_default()).unwrap_or_default(),
|
|
||||||
ports,
|
|
||||||
first_latency,
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
device_name,
|
|
||||||
UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(),
|
|
||||||
packet_loss_rate,
|
|
||||||
packet_delay,
|
|
||||||
port_mapping,
|
|
||||||
Compressor::None,
|
|
||||||
) {
|
|
||||||
Ok(config) => config,
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new(
|
|
||||||
"java/lang/RuntimeException",
|
|
||||||
format!("vnt start error {:?}", e),
|
|
||||||
)
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(config)
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
pub mod callback;
|
|
||||||
pub mod config;
|
|
||||||
pub mod utils;
|
|
||||||
pub mod vnt;
|
|
||||||
pub(crate) mod vnt_logger;
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
use jni::errors::Error;
|
|
||||||
use jni::objects::{JIntArray, JObject, JObjectArray, JString};
|
|
||||||
use jni::JNIEnv;
|
|
||||||
|
|
||||||
pub fn to_string_not_null(
|
|
||||||
env: &mut JNIEnv,
|
|
||||||
config: &JObject,
|
|
||||||
name: &'static str,
|
|
||||||
) -> Result<String, Error> {
|
|
||||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
|
||||||
if value.is_null() {
|
|
||||||
env.throw_new("java/lang/NullPointerException", name)
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::NullPtr(name));
|
|
||||||
}
|
|
||||||
let binding = JString::from(value);
|
|
||||||
let value = env.get_string(binding.as_ref())?;
|
|
||||||
match value.to_str() {
|
|
||||||
Ok(value) => Ok(value.to_string()),
|
|
||||||
Err(_) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", "not utf-8")
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<String>, Error> {
|
|
||||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
|
||||||
if value.is_null() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let tmp = JString::from(value);
|
|
||||||
let value = env.get_string(tmp.as_ref())?;
|
|
||||||
match value.to_str() {
|
|
||||||
Ok(value) => Ok(Some(value.to_string())),
|
|
||||||
Err(_) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", "not utf-8")
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string_array_not_null(
|
|
||||||
env: &mut JNIEnv,
|
|
||||||
config: &JObject,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<Vec<String>, Error> {
|
|
||||||
match to_string_array(env, config, name)? {
|
|
||||||
None => {
|
|
||||||
env.throw_new("java/lang/NullPointerException", name)
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
Some(rs) => Ok(rs),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string_array(
|
|
||||||
env: &mut JNIEnv,
|
|
||||||
config: &JObject,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<Option<Vec<String>>, Error> {
|
|
||||||
let value = env.get_field(config, name, "[Ljava/lang/String;")?.l()?;
|
|
||||||
if value.is_null() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let arr = JObjectArray::from(value);
|
|
||||||
let len = env.get_array_length(&arr)?;
|
|
||||||
let mut rs = Vec::with_capacity(len as usize);
|
|
||||||
for index in 0..len {
|
|
||||||
let object = env.get_object_array_element(&arr, index)?;
|
|
||||||
if object.is_null() {
|
|
||||||
env.throw_new(
|
|
||||||
"java/lang/NullPointerException",
|
|
||||||
format!("{},index={}", name, index),
|
|
||||||
)
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
match env.get_string(JString::from(object).as_ref())?.to_str() {
|
|
||||||
Ok(value) => {
|
|
||||||
rs.push(value.to_string());
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", "not utf-8")
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Some(rs))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_i32_array(
|
|
||||||
env: &mut JNIEnv,
|
|
||||||
config: &JObject,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<Option<Vec<i32>>, Error> {
|
|
||||||
let obj = env.get_field(&config, name, "[I")?.l()?;
|
|
||||||
if obj.is_null() {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
let j_arr = JIntArray::from(obj);
|
|
||||||
let len = env.get_array_length(&j_arr)?;
|
|
||||||
let mut arr = vec![0i32; len as usize];
|
|
||||||
env.get_int_array_region(j_arr, 0, &mut arr)?;
|
|
||||||
Ok(Some(arr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn to_integer(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<i32>, Error> {
|
|
||||||
let value = env.get_field(config, name, "Ljava/lang/Integer;")?.l()?;
|
|
||||||
if value.is_null() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
// 调用 intValue
|
|
||||||
return Ok(Some(
|
|
||||||
env.call_method(value, "intValue", "()I", &[])?.i()? as _
|
|
||||||
));
|
|
||||||
}
|
|
||||||
pub fn to_double(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<f64>, Error> {
|
|
||||||
let value = env.get_field(config, name, "Ljava/lang/Double;")?.l()?;
|
|
||||||
if value.is_null() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
// 调用 intValue
|
|
||||||
return Ok(Some(
|
|
||||||
env.call_method(value, "doubleValue", "()D", &[])?.d()? as _,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
use std::ptr;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use jni::errors::Error;
|
|
||||||
use jni::objects::{JClass, JObject, JValue};
|
|
||||||
use jni::sys::{jboolean, jint, jlong, jobject, jobjectArray, jsize};
|
|
||||||
use jni::JNIEnv;
|
|
||||||
|
|
||||||
use vnt::channel::Route;
|
|
||||||
use vnt::core::Vnt;
|
|
||||||
use vnt::handle::PeerDeviceInfo;
|
|
||||||
|
|
||||||
use crate::callback::CallBack;
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0(
|
|
||||||
mut env: JNIEnv<'static>,
|
|
||||||
_class: JClass,
|
|
||||||
config: JObject,
|
|
||||||
call_back: JObject<'static>,
|
|
||||||
) -> jlong {
|
|
||||||
crate::vnt_logger::init_log();
|
|
||||||
let jvm = if let Ok(jvm) = env.get_java_vm() {
|
|
||||||
jvm
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
match crate::config::new_config(&mut env, config) {
|
|
||||||
Ok(config) => {
|
|
||||||
let call_back = if let Ok(call_back) = env.new_global_ref(call_back) {
|
|
||||||
call_back
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
let call_back = match CallBack::new(jvm, call_back) {
|
|
||||||
Ok(call_back) => call_back,
|
|
||||||
Err(_) => {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let vnt_util = match Vnt::new(config, call_back) {
|
|
||||||
Ok(vnt_util) => vnt_util,
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new(
|
|
||||||
"java/lang/RuntimeException",
|
|
||||||
format!("vnt start error {}", e),
|
|
||||||
)
|
|
||||||
.expect("throw");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let ptr = Box::into_raw(Box::new(vnt_util));
|
|
||||||
return ptr as jlong;
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_stop0(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_vnt: jlong,
|
|
||||||
) {
|
|
||||||
let vnt = raw_vnt as *mut Vnt;
|
|
||||||
let _ = (&*vnt).stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_vnt: jlong,
|
|
||||||
) {
|
|
||||||
let vnt = raw_vnt as *mut Vnt;
|
|
||||||
let _ = (&*vnt).wait();
|
|
||||||
}
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitTimeout0(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_vnt: jlong,
|
|
||||||
time: jlong,
|
|
||||||
) -> jboolean {
|
|
||||||
let vnt = raw_vnt as *mut Vnt;
|
|
||||||
(&*vnt).wait_timeout(Duration::from_millis(time as _)) as _
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_vnt: jlong,
|
|
||||||
) {
|
|
||||||
let vnt = raw_vnt as *mut Vnt;
|
|
||||||
let _ = Box::from_raw(vnt).stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0(
|
|
||||||
mut env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_vnt: jlong,
|
|
||||||
) -> jobjectArray {
|
|
||||||
let vnt = raw_vnt as *mut Vnt;
|
|
||||||
let vnt = &mut *vnt;
|
|
||||||
let list = vnt.device_list();
|
|
||||||
|
|
||||||
let arr = match env.new_object_array(
|
|
||||||
list.len() as jsize,
|
|
||||||
"top/wherewego/vnt/jni/PeerRouteInfo",
|
|
||||||
JObject::null(),
|
|
||||||
) {
|
|
||||||
Ok(arr) => arr,
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
|
||||||
.expect("throw");
|
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for (index, peer) in list.into_iter().enumerate() {
|
|
||||||
let route = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
|
||||||
match route_parse(&mut env, route) {
|
|
||||||
Ok(route) => JObject::from_raw(route),
|
|
||||||
Err(_) => JObject::null(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JObject::null()
|
|
||||||
};
|
|
||||||
match peer_device_info_parse(&mut env, peer, route) {
|
|
||||||
Ok(peer) => {
|
|
||||||
match env.set_object_array_element(&arr, index as jsize, JObject::from_raw(peer)) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
|
||||||
.expect("throw");
|
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
|
||||||
.expect("throw");
|
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arr.as_raw()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn route_parse(env: &mut JNIEnv, route: Route) -> Result<jobject, Error> {
|
|
||||||
let rs = env.new_object(
|
|
||||||
"top/wherewego/vnt/jni/Route",
|
|
||||||
"(ZLjava/lang/String;BI)V",
|
|
||||||
&[
|
|
||||||
JValue::Bool(route.is_tcp as _),
|
|
||||||
JValue::Object(&env.new_string(route.addr.to_string())?.into()),
|
|
||||||
JValue::Byte(route.metric as _),
|
|
||||||
JValue::Int(route.rt as _),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
Ok(rs.as_raw())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peer_device_info_parse(
|
|
||||||
env: &mut JNIEnv,
|
|
||||||
peer: PeerDeviceInfo,
|
|
||||||
route: JObject,
|
|
||||||
) -> Result<jobject, Error> {
|
|
||||||
let virtual_ip = u32::from(peer.virtual_ip);
|
|
||||||
let name = peer.name.to_string();
|
|
||||||
let status = format!("{:?}", peer.status);
|
|
||||||
let rs = env.new_object(
|
|
||||||
"top/wherewego/vnt/jni/PeerRouteInfo",
|
|
||||||
"(ILjava/lang/String;Ljava/lang/String;Ltop/wherewego/vnt/jni/Route;)V",
|
|
||||||
&[
|
|
||||||
JValue::Int(virtual_ip as jint),
|
|
||||||
JValue::Object(&env.new_string(name)?.into()),
|
|
||||||
JValue::Object(&env.new_string(status)?.into()),
|
|
||||||
JValue::Object(&route),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
Ok(rs.as_raw())
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#[cfg(target_os = "android")]
|
|
||||||
pub fn init_log() {
|
|
||||||
use android_logger::Config;
|
|
||||||
use log::LevelFilter;
|
|
||||||
android_logger::init_once(
|
|
||||||
Config::default()
|
|
||||||
.with_max_level(LevelFilter::Info) // limit log level
|
|
||||||
.with_tag("vnt_jni"), // logs will show under mytag tag
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
pub fn init_log() {}
|
|
||||||
+39
-14
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vnt"
|
name = "vnt"
|
||||||
version = "1.2.10"
|
version = "1.2.16"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tun = { path = "tun" }
|
tun-rs = { version = "2.5.0", optional = true, features = ["interruptible"] }
|
||||||
packet = { path = "./packet" }
|
packet = { path = "./packet" }
|
||||||
bytes = "1.5.0"
|
bytes = "1.5.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
@@ -17,38 +17,58 @@ parking_lot = "0.12.1"
|
|||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
protobuf = "3.2.0"
|
protobuf = "=3.2.0"
|
||||||
socket2 = { version = "0.5.2", features = ["all"] }
|
socket2 = { version = "0.5.7", features = ["all"] }
|
||||||
aes-gcm = { version = "0.10.2", optional = true }
|
aes-gcm = { version = "0.10.2", optional = true }
|
||||||
ring = { version = "0.17.0", optional = true }
|
ring = { version = "0.17.0", optional = true }
|
||||||
cbc = { version = "0.1.2", optional = true }
|
cbc = { version = "0.1.2", optional = true }
|
||||||
ecb = { version = "0.1.2", optional = true }
|
ecb = { version = "0.1.2", optional = true }
|
||||||
|
chacha20poly1305 = { version = "0.10.1", optional = true }
|
||||||
|
chacha20 = { version = "0.9.1", optional = true }
|
||||||
aes = "0.8.3"
|
aes = "0.8.3"
|
||||||
stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] }
|
stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] }
|
||||||
rsa = { version = "0.9.2", features = [], optional = true }
|
rsa = { version = "0.9.2", features = [], optional = true }
|
||||||
spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optional = true }
|
spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optional = true }
|
||||||
openssl-sys = { git = "https://github.com/lbl8603/rust-openssl", optional = true }
|
openssl-sys = { git = "https://github.com/vnt-dev/rust-openssl", optional = true }
|
||||||
libsm = { git = "https://github.com/lbl8603/libsm", optional = true }
|
libsm = { git = "https://github.com/vnt-dev/libsm", optional = true }
|
||||||
|
http_req = { git = "https://github.com/lmq8267/http_req.git", default-features = false, features = ["rust-tls"] }
|
||||||
|
|
||||||
mio = { version = "0.8.10", features = ["os-poll", "net", "os-ext"] }
|
mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] }
|
||||||
crossbeam-queue = "0.3.11"
|
crossbeam-queue = "0.3.11"
|
||||||
anyhow = "1.0.82"
|
anyhow = "1.0.82"
|
||||||
dns-parser = "0.8.0"
|
dns-parser = "0.8.0"
|
||||||
|
|
||||||
tokio = { version = "1.37.0", features = ["full"], optional = true }
|
tokio = { version = "1.46.1", features = ["full"] }
|
||||||
|
|
||||||
lz4_flex = { version = "0.11", default-features = false, optional = true }
|
lz4_flex = { version = "0.11", default-features = false, optional = true }
|
||||||
zstd = { version = "0.13.1", optional = true }
|
zstd = { version = "0.13.1", optional = true }
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
|
||||||
libloading = "0.8.0"
|
|
||||||
|
|
||||||
|
fnv = "1.0.7"
|
||||||
|
igd = { version = "0.12.1", optional = true }
|
||||||
|
tokio-tungstenite = { version = "0.23.1", optional = true }
|
||||||
|
rustls = { version = "0.23.0", features = ["ring", "tls12"], default-features = false, optional = true }
|
||||||
|
|
||||||
|
network-interface = "2.0.0"
|
||||||
|
|
||||||
|
futures-util = "0.3.30"
|
||||||
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
|
winreg = "0.55.0"
|
||||||
|
libloading = "0.8.0"
|
||||||
|
windows-sys = { version = "0.60.2", features = ["Win32_Foundation",
|
||||||
|
"Win32_NetworkManagement",
|
||||||
|
"Win32_NetworkManagement_IpHelper",
|
||||||
|
"Win32_Networking_WinSock",
|
||||||
|
"Win32_System_IO",
|
||||||
|
"Win32_System_Threading",
|
||||||
|
"Win32_System_WindowsProgramming", ] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
protobuf-codegen = "3.2.0"
|
protobuf-codegen = "=3.2.0"
|
||||||
protoc-bin-vendored = "3.0.0"
|
protoc-bin-vendored = "3.0.0"
|
||||||
|
cfg_aliases = "0.2.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping", "lz4_compress","zstd_compress"]
|
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress", "integrated_tun"]
|
||||||
openssl = ["openssl-sys"]
|
openssl = ["openssl-sys"]
|
||||||
# 从源码编译
|
# 从源码编译
|
||||||
openssl-vendored = ["openssl-sys/vendored"]
|
openssl-vendored = ["openssl-sys/vendored"]
|
||||||
@@ -57,8 +77,13 @@ aes_cbc = ["cbc"]
|
|||||||
aes_ecb = ["ecb"]
|
aes_ecb = ["ecb"]
|
||||||
sm4_cbc = ["libsm"]
|
sm4_cbc = ["libsm"]
|
||||||
aes_gcm = ["aes-gcm"]
|
aes_gcm = ["aes-gcm"]
|
||||||
|
chacha20_poly1305 = ["chacha20poly1305", "chacha20"]
|
||||||
server_encrypt = ["aes-gcm", "rsa", "spki"]
|
server_encrypt = ["aes-gcm", "rsa", "spki"]
|
||||||
ip_proxy = ["tokio"]
|
ip_proxy = []
|
||||||
port_mapping = ["tokio"]
|
port_mapping = []
|
||||||
lz4_compress = ["lz4_flex"]
|
lz4_compress = ["lz4_flex"]
|
||||||
zstd_compress = ["zstd"]
|
zstd_compress = ["zstd"]
|
||||||
|
integrated_tun = ["tun-rs"]
|
||||||
|
upnp = ["igd"]
|
||||||
|
ws = ["tokio-tungstenite"]
|
||||||
|
wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"]
|
||||||
|
|||||||
@@ -1,4 +1,17 @@
|
|||||||
|
use cfg_aliases::cfg_aliases;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
cfg_aliases! {
|
||||||
|
cipher: {
|
||||||
|
any(feature = "aes_gcm",
|
||||||
|
feature = "chacha20_poly1305",
|
||||||
|
feature = "server_encrypt",
|
||||||
|
feature = "aes_cbc",
|
||||||
|
feature = "aes_ecb",
|
||||||
|
feature = "sm4_cbc"
|
||||||
|
)},
|
||||||
|
}
|
||||||
|
|
||||||
std::fs::create_dir_all("src/proto").unwrap();
|
std::fs::create_dir_all("src/proto").unwrap();
|
||||||
protobuf_codegen::Codegen::new()
|
protobuf_codegen::Codegen::new()
|
||||||
.pure()
|
.pure()
|
||||||
|
|||||||
@@ -71,14 +71,12 @@ unsigned short getChecksum(unsigned short * iphead, int count)
|
|||||||
pub fn cal_checksum(buffer: &[u8]) -> u16 {
|
pub fn cal_checksum(buffer: &[u8]) -> u16 {
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
let mut sum = 0;
|
let mut sum = 0;
|
||||||
let length = buffer.len();
|
|
||||||
let mut buffer = Cursor::new(buffer);
|
let mut buffer = Cursor::new(buffer);
|
||||||
while let Ok(value) = buffer.read_u16::<BigEndian>() {
|
while let Ok(value) = buffer.read_u16::<BigEndian>() {
|
||||||
sum += u32::from(value);
|
sum += u32::from(value);
|
||||||
}
|
}
|
||||||
if length & 1 == 1 {
|
if let Ok(l) = buffer.read_u8() {
|
||||||
//奇数,说明还有一位,不足的补0
|
sum += u32c(l, 0);
|
||||||
sum += u32c(buffer.read_u8().unwrap(), 0);
|
|
||||||
}
|
}
|
||||||
while sum >> 16 != 0 {
|
while sum >> 16 != 0 {
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
@@ -119,9 +117,8 @@ pub fn ipv4_cal_checksum(
|
|||||||
while let Ok(value) = buffer.read_u16::<BigEndian>() {
|
while let Ok(value) = buffer.read_u16::<BigEndian>() {
|
||||||
sum += u32::from(value);
|
sum += u32::from(value);
|
||||||
}
|
}
|
||||||
if length & 1 == 1 {
|
if let Ok(l) = buffer.read_u8() {
|
||||||
//奇数,说明还有一位
|
sum += u32c(l, 0);
|
||||||
sum += u32c(buffer.read_u8().unwrap(), 0);
|
|
||||||
}
|
}
|
||||||
while sum >> 16 != 0 {
|
while sum >> 16 != 0 {
|
||||||
sum = (sum & 0xffff) + (sum >> 16);
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ message DeviceInfo {
|
|||||||
uint32 device_status = 3;
|
uint32 device_status = 3;
|
||||||
bool client_secret = 4;
|
bool client_secret = 4;
|
||||||
bytes client_secret_hash = 5;
|
bytes client_secret_hash = 5;
|
||||||
|
bool wireguard = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeviceList {
|
message DeviceList {
|
||||||
@@ -63,11 +64,23 @@ message PunchInfo {
|
|||||||
uint32 tcp_port = 11;
|
uint32 tcp_port = 11;
|
||||||
repeated uint32 udp_ports = 12;
|
repeated uint32 udp_ports = 12;
|
||||||
repeated uint32 public_ports = 13;
|
repeated uint32 public_ports = 13;
|
||||||
|
uint32 public_tcp_port = 14;
|
||||||
|
PunchNatModel punch_model = 15;
|
||||||
}
|
}
|
||||||
enum PunchNatType {
|
enum PunchNatType {
|
||||||
Symmetric = 0;
|
Symmetric = 0;
|
||||||
Cone = 1;
|
Cone = 1;
|
||||||
}
|
}
|
||||||
|
enum PunchNatModel {
|
||||||
|
All = 0;
|
||||||
|
IPv4 = 1;
|
||||||
|
IPv6 = 2;
|
||||||
|
IPv4Tcp = 3;
|
||||||
|
IPv4Udp = 4;
|
||||||
|
IPv6Tcp = 5;
|
||||||
|
IPv6Udp = 6;
|
||||||
|
}
|
||||||
|
|
||||||
/// 向服务器上报客户端状态信息
|
/// 向服务器上报客户端状态信息
|
||||||
message ClientStatusInfo {
|
message ClientStatusInfo {
|
||||||
fixed32 source = 1;
|
fixed32 source = 1;
|
||||||
|
|||||||
+151
-124
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use fnv::FnvHashMap;
|
||||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV6, UdpSocket};
|
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
@@ -11,8 +11,11 @@ use parking_lot::RwLock;
|
|||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::channel::punch::NatType;
|
use crate::channel::punch::NatType;
|
||||||
use crate::channel::sender::{AcceptSocketSender, ChannelSender, PacketSender};
|
use crate::channel::sender::{AcceptSocketSender, PacketSender};
|
||||||
use crate::channel::{Route, RouteKey, UseChannelType, DEFAULT_RT};
|
use crate::channel::socket::LocalInterface;
|
||||||
|
use crate::channel::{ConnectProtocol, Route, RouteKey, UseChannelType, DEFAULT_RT};
|
||||||
|
use crate::protocol::NetPacket;
|
||||||
|
use crate::util::limit::TrafficMeterMultiAddress;
|
||||||
|
|
||||||
/// 传输通道上下文,持有udp socket、tcp socket和路由信息
|
/// 传输通道上下文,持有udp socket、tcp socket和路由信息
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -23,14 +26,17 @@ pub struct ChannelContext {
|
|||||||
impl ChannelContext {
|
impl ChannelContext {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
main_udp_socket: Vec<UdpSocket>,
|
main_udp_socket: Vec<UdpSocket>,
|
||||||
|
v4_len: usize,
|
||||||
use_channel_type: UseChannelType,
|
use_channel_type: UseChannelType,
|
||||||
first_latency: bool,
|
first_latency: bool,
|
||||||
is_tcp: bool,
|
protocol: ConnectProtocol,
|
||||||
packet_loss_rate: Option<f64>,
|
packet_loss_rate: Option<f64>,
|
||||||
packet_delay: u32,
|
packet_delay: u32,
|
||||||
use_ipv6: bool,
|
up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
|
down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
|
default_interface: LocalInterface,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let channel_num = main_udp_socket.len();
|
let channel_num = v4_len;
|
||||||
assert_ne!(channel_num, 0, "not channel");
|
assert_ne!(channel_num, 0, "not channel");
|
||||||
let packet_loss_rate = packet_loss_rate
|
let packet_loss_rate = packet_loss_rate
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
@@ -44,22 +50,22 @@ impl ChannelContext {
|
|||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let inner = ContextInner {
|
let inner = ContextInner {
|
||||||
main_udp_socket,
|
main_udp_socket,
|
||||||
sub_udp_socket: RwLock::new(Vec::with_capacity(64)),
|
v4_len,
|
||||||
tcp_map: RwLock::new(HashMap::with_capacity(64)),
|
sub_udp_socket: RwLock::new(Vec::new()),
|
||||||
|
packet_map: RwLock::new(FnvHashMap::default()),
|
||||||
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
|
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
|
||||||
is_tcp,
|
protocol,
|
||||||
packet_loss_rate,
|
packet_loss_rate,
|
||||||
packet_delay,
|
packet_delay,
|
||||||
main_index: AtomicUsize::new(0),
|
up_traffic_meter,
|
||||||
use_ipv6,
|
down_traffic_meter,
|
||||||
|
default_interface,
|
||||||
|
default_route_key: AtomicCell::default(),
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(inner),
|
inner: Arc::new(inner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn sender(&self) -> ChannelSender {
|
|
||||||
ChannelSender::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for ChannelContext {
|
impl Deref for ChannelContext {
|
||||||
@@ -71,41 +77,50 @@ impl Deref for ChannelContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
|
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
|
||||||
pub const SYMMETRIC_CHANNEL_NUM: usize = 100;
|
pub const SYMMETRIC_CHANNEL_NUM: usize = 84;
|
||||||
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
|
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
|
||||||
|
|
||||||
pub struct ContextInner {
|
pub struct ContextInner {
|
||||||
// 核心udp socket
|
// 核心udp socket
|
||||||
pub(crate) main_udp_socket: Vec<UdpSocket>,
|
pub(crate) main_udp_socket: Vec<UdpSocket>,
|
||||||
|
v4_len: usize,
|
||||||
// 对称网络增加的udp socket
|
// 对称网络增加的udp socket
|
||||||
sub_udp_socket: RwLock<Vec<UdpSocket>>,
|
sub_udp_socket: RwLock<Vec<UdpSocket>>,
|
||||||
// tcp数据发送器
|
// tcp数据发送器
|
||||||
pub(crate) tcp_map: RwLock<HashMap<SocketAddr, PacketSender>>,
|
pub(crate) packet_map: RwLock<FnvHashMap<RouteKey, PacketSender>>,
|
||||||
// 路由信息
|
// 路由信息
|
||||||
pub route_table: RouteTable,
|
pub route_table: RouteTable,
|
||||||
// 是否使用tcp连接服务器
|
// 使用什么协议连接服务器
|
||||||
is_tcp: bool,
|
protocol: ConnectProtocol,
|
||||||
//控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000
|
//控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000
|
||||||
packet_loss_rate: u32,
|
packet_loss_rate: u32,
|
||||||
//控制延迟
|
//控制延迟
|
||||||
packet_delay: u32,
|
packet_delay: u32,
|
||||||
main_index: AtomicUsize,
|
pub(crate) up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
use_ipv6: bool,
|
pub(crate) down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
|
default_interface: LocalInterface,
|
||||||
|
default_route_key: AtomicCell<Option<RouteKey>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextInner {
|
impl ContextInner {
|
||||||
pub fn use_channel_type(&self) -> UseChannelType {
|
pub fn use_channel_type(&self) -> UseChannelType {
|
||||||
self.route_table.use_channel_type
|
self.route_table.use_channel_type
|
||||||
}
|
}
|
||||||
|
pub fn default_interface(&self) -> &LocalInterface {
|
||||||
|
&self.default_interface
|
||||||
|
}
|
||||||
|
pub fn set_default_route_key(&self, route_key: RouteKey) {
|
||||||
|
self.default_route_key.store(Some(route_key));
|
||||||
|
}
|
||||||
/// 通过sub_udp_socket是否为空来判断是否为锥形网络
|
/// 通过sub_udp_socket是否为空来判断是否为锥形网络
|
||||||
pub fn is_cone(&self) -> bool {
|
pub fn is_cone(&self) -> bool {
|
||||||
self.sub_udp_socket.read().is_empty()
|
self.sub_udp_socket.read().is_empty()
|
||||||
}
|
}
|
||||||
pub fn is_main_tcp(&self) -> bool {
|
pub fn main_protocol(&self) -> ConnectProtocol {
|
||||||
self.is_tcp
|
self.protocol
|
||||||
}
|
}
|
||||||
pub fn is_udp_main(&self, route_key: &RouteKey) -> bool {
|
pub fn is_udp_main(&self, route_key: &RouteKey) -> bool {
|
||||||
!route_key.is_tcp() && route_key.index < self.main_udp_socket.len()
|
route_key.protocol().is_udp() && route_key.index < self.main_udp_socket.len()
|
||||||
}
|
}
|
||||||
pub fn first_latency(&self) -> bool {
|
pub fn first_latency(&self) -> bool {
|
||||||
self.route_table.first_latency
|
self.route_table.first_latency
|
||||||
@@ -115,7 +130,7 @@ impl ContextInner {
|
|||||||
&self,
|
&self,
|
||||||
nat_type: NatType,
|
nat_type: NatType,
|
||||||
udp_socket_sender: &AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
|
udp_socket_sender: &AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut write_guard = self.sub_udp_socket.write();
|
let mut write_guard = self.sub_udp_socket.write();
|
||||||
match nat_type {
|
match nat_type {
|
||||||
NatType::Symmetric => {
|
NatType::Symmetric => {
|
||||||
@@ -124,9 +139,11 @@ impl ContextInner {
|
|||||||
}
|
}
|
||||||
let mut vec = Vec::with_capacity(SYMMETRIC_CHANNEL_NUM);
|
let mut vec = Vec::with_capacity(SYMMETRIC_CHANNEL_NUM);
|
||||||
for _ in 0..SYMMETRIC_CHANNEL_NUM {
|
for _ in 0..SYMMETRIC_CHANNEL_NUM {
|
||||||
let udp = UdpSocket::bind("0.0.0.0:0")?;
|
let udp = crate::channel::socket::bind_udp(
|
||||||
//副通道使用异步io
|
"0.0.0.0:0".parse().unwrap(),
|
||||||
udp.set_nonblocking(true)?;
|
&self.default_interface,
|
||||||
|
)?;
|
||||||
|
let udp: UdpSocket = udp.into();
|
||||||
vec.push(udp);
|
vec.push(udp);
|
||||||
}
|
}
|
||||||
let mut mio_vec = Vec::with_capacity(SYMMETRIC_CHANNEL_NUM);
|
let mut mio_vec = Vec::with_capacity(SYMMETRIC_CHANNEL_NUM);
|
||||||
@@ -147,54 +164,68 @@ impl ContextInner {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
pub fn channel_num(&self) -> usize {
|
pub fn channel_num(&self) -> usize {
|
||||||
|
self.v4_len
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn main_len(&self) -> usize {
|
||||||
self.main_udp_socket.len()
|
self.main_udp_socket.len()
|
||||||
}
|
}
|
||||||
/// 获取核心udp监听的端口,用于其他客户端连接
|
/// 获取核心udp监听的端口,用于其他客户端连接
|
||||||
pub fn main_local_udp_port(&self) -> io::Result<Vec<u16>> {
|
pub fn main_local_udp_port(&self) -> io::Result<Vec<u16>> {
|
||||||
let mut ports = Vec::new();
|
let mut ports = Vec::new();
|
||||||
for udp in self.main_udp_socket.iter() {
|
for udp in self.main_udp_socket[..self.v4_len].iter() {
|
||||||
ports.push(udp.local_addr()?.port())
|
ports.push(udp.local_addr()?.port())
|
||||||
}
|
}
|
||||||
Ok(ports)
|
Ok(ports)
|
||||||
}
|
}
|
||||||
pub fn send_tcp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
|
pub fn send_tcp(&self, buf: &[u8], route_key: &RouteKey) -> io::Result<()> {
|
||||||
if let Some(tcp) = self.tcp_map.read().get(&addr) {
|
if let Some(tcp) = self.packet_map.read().get(route_key) {
|
||||||
tcp.try_send(buf)
|
tcp.try_send(buf)
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::from(io::ErrorKind::NotFound))
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::NotFound,
|
||||||
|
format!("dest={:?}", route_key),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn send_main_udp(&self, index: usize, buf: &[u8], mut addr: SocketAddr) -> io::Result<()> {
|
pub fn send_main_udp(&self, index: usize, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
|
||||||
if self.use_ipv6 {
|
if let Some(udp) = self.main_udp_socket.get(index) {
|
||||||
//如果是v4地址则需要转换成v6
|
udp.send_to(buf, addr)?;
|
||||||
if let SocketAddr::V4(ipv4) = addr {
|
Ok(())
|
||||||
addr = SocketAddr::V6(SocketAddrV6::new(
|
} else {
|
||||||
ipv4.ip().to_ipv6_mapped(),
|
Err(io::Error::new(io::ErrorKind::Other, "overflow"))
|
||||||
ipv4.port(),
|
}
|
||||||
0,
|
}
|
||||||
0,
|
/// 将数据发送到默认通道,一般发往服务器才用此方法
|
||||||
|
pub fn send_default<B: AsRef<[u8]>>(
|
||||||
|
&self,
|
||||||
|
buf: &NetPacket<B>,
|
||||||
|
addr: SocketAddr,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if self.protocol.is_udp() {
|
||||||
|
if addr.is_ipv4() {
|
||||||
|
self.send_main_udp(0, buf.buffer(), addr)?
|
||||||
|
} else {
|
||||||
|
self.send_main_udp(self.v4_len, buf.buffer(), addr)?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(key) = self.default_route_key.load() {
|
||||||
|
self.send_tcp(buf.buffer(), &key)?
|
||||||
|
} else {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::NotFound,
|
||||||
|
format!("dest={:?}", addr),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.main_udp_socket[index].send_to(buf, addr)?;
|
if let Some(up_traffic_meter) = &self.up_traffic_meter {
|
||||||
|
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
/// 将数据发送到默认通道,一般发往服务器才用此方法
|
|
||||||
pub fn send_default(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
|
|
||||||
if self.is_tcp {
|
|
||||||
//服务端地址只在重连时检测变化
|
|
||||||
self.send_tcp(buf, addr)
|
|
||||||
} else {
|
|
||||||
self.send_main_udp(self.main_index.load(Ordering::Relaxed), buf, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn change_main_index(&self) {
|
|
||||||
let index = (self.main_index.load(Ordering::Relaxed) + 1) % self.main_udp_socket.len();
|
|
||||||
self.main_index.store(index, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
/// 此方法仅用于对称网络打洞
|
/// 此方法仅用于对称网络打洞
|
||||||
pub fn try_send_all(&self, buf: &[u8], addr: SocketAddr) {
|
pub fn try_send_all(&self, buf: &[u8], addr: SocketAddr) {
|
||||||
self.try_send_all_main(buf, addr);
|
self.try_send_all_main(buf, addr);
|
||||||
@@ -202,7 +233,7 @@ impl ContextInner {
|
|||||||
if let Err(e) = udp.send_to(buf, addr) {
|
if let Err(e) = udp.send_to(buf, addr) {
|
||||||
log::warn!("{:?},add={:?}", e, addr);
|
log::warn!("{:?},add={:?}", e, addr);
|
||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(1));
|
thread::sleep(Duration::from_millis(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn try_send_all_main(&self, buf: &[u8], addr: SocketAddr) {
|
pub fn try_send_all_main(&self, buf: &[u8], addr: SocketAddr) {
|
||||||
@@ -213,9 +244,9 @@ impl ContextInner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// 发送网络数据
|
/// 发送网络数据
|
||||||
pub fn send_ipv4_by_id(
|
pub fn send_ipv4_by_id<B: AsRef<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
buf: &[u8],
|
buf: &NetPacket<B>,
|
||||||
id: &Ipv4Addr,
|
id: &Ipv4Addr,
|
||||||
server_addr: SocketAddr,
|
server_addr: SocketAddr,
|
||||||
send_default: bool,
|
send_default: bool,
|
||||||
@@ -225,6 +256,7 @@ impl ContextInner {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.packet_delay > 0 {
|
if self.packet_delay > 0 {
|
||||||
thread::sleep(Duration::from_millis(self.packet_delay as _));
|
thread::sleep(Duration::from_millis(self.packet_delay as _));
|
||||||
}
|
}
|
||||||
@@ -241,7 +273,7 @@ impl ContextInner {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
/// 将数据发到指定id
|
/// 将数据发到指定id
|
||||||
pub fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<()> {
|
pub fn send_by_id<B: AsRef<[u8]>>(&self, buf: &NetPacket<B>, id: &Ipv4Addr) -> io::Result<()> {
|
||||||
let mut c = 0;
|
let mut c = 0;
|
||||||
loop {
|
loop {
|
||||||
let route = self.route_table.get_route_by_id(c, id)?;
|
let route = self.route_table.get_route_by_id(c, id)?;
|
||||||
@@ -261,25 +293,35 @@ impl ContextInner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// 将数据发到指定路由
|
/// 将数据发到指定路由
|
||||||
pub fn send_by_key(&self, buf: &[u8], route_key: RouteKey) -> io::Result<()> {
|
pub fn send_by_key<B: AsRef<[u8]>>(
|
||||||
if route_key.is_tcp {
|
&self,
|
||||||
self.send_tcp(buf, route_key.addr)
|
buf: &NetPacket<B>,
|
||||||
} else {
|
route_key: RouteKey,
|
||||||
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
|
) -> io::Result<()> {
|
||||||
main_udp.send_to(buf, route_key.addr)?;
|
match route_key.protocol() {
|
||||||
} else {
|
ConnectProtocol::UDP => {
|
||||||
if let Some(udp) = self
|
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
|
||||||
.sub_udp_socket
|
main_udp.send_to(buf.buffer(), route_key.addr)?;
|
||||||
.read()
|
|
||||||
.get(route_key.index - self.main_udp_socket.len())
|
|
||||||
{
|
|
||||||
udp.send_to(buf, route_key.addr)?;
|
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::from(io::ErrorKind::NotFound))?
|
if let Some(udp) = self
|
||||||
|
.sub_udp_socket
|
||||||
|
.read()
|
||||||
|
.get(route_key.index - self.main_len())
|
||||||
|
{
|
||||||
|
udp.send_to(buf.buffer(), route_key.addr)?;
|
||||||
|
} else {
|
||||||
|
Err(io::Error::from(io::ErrorKind::NotFound))?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
ConnectProtocol::TCP | ConnectProtocol::WS | ConnectProtocol::WSS => {
|
||||||
|
self.send_tcp(buf.buffer(), &route_key)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(up_traffic_meter) = &self.up_traffic_meter {
|
||||||
|
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn remove_route(&self, ip: &Ipv4Addr, route_key: RouteKey) {
|
pub fn remove_route(&self, ip: &Ipv4Addr, route_key: RouteKey) {
|
||||||
self.route_table.remove_route(ip, route_key)
|
self.route_table.remove_route(ip, route_key)
|
||||||
@@ -288,7 +330,7 @@ impl ContextInner {
|
|||||||
|
|
||||||
pub struct RouteTable {
|
pub struct RouteTable {
|
||||||
pub(crate) route_table:
|
pub(crate) route_table:
|
||||||
RwLock<HashMap<Ipv4Addr, (AtomicUsize, Vec<(Route, AtomicCell<Instant>)>)>>,
|
RwLock<FnvHashMap<Ipv4Addr, (AtomicUsize, Vec<(Route, AtomicCell<Instant>)>)>>,
|
||||||
first_latency: bool,
|
first_latency: bool,
|
||||||
channel_num: usize,
|
channel_num: usize,
|
||||||
use_channel_type: UseChannelType,
|
use_channel_type: UseChannelType,
|
||||||
@@ -297,7 +339,7 @@ pub struct RouteTable {
|
|||||||
impl RouteTable {
|
impl RouteTable {
|
||||||
fn new(use_channel_type: UseChannelType, first_latency: bool, channel_num: usize) -> Self {
|
fn new(use_channel_type: UseChannelType, first_latency: bool, channel_num: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
route_table: RwLock::new(HashMap::with_capacity(64)),
|
route_table: RwLock::new(FnvHashMap::with_capacity_and_hasher(64, Default::default())),
|
||||||
use_channel_type,
|
use_channel_type,
|
||||||
first_latency,
|
first_latency,
|
||||||
channel_num,
|
channel_num,
|
||||||
@@ -330,18 +372,18 @@ impl RouteTable {
|
|||||||
}
|
}
|
||||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||||
}
|
}
|
||||||
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) {
|
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) -> bool {
|
||||||
self.add_route_(id, route, true)
|
self.add_route_(id, route, true)
|
||||||
}
|
}
|
||||||
pub fn add_route(&self, id: Ipv4Addr, route: Route) {
|
pub fn add_route(&self, id: Ipv4Addr, route: Route) -> bool {
|
||||||
self.add_route_(id, route, false)
|
self.add_route_(id, route, false)
|
||||||
}
|
}
|
||||||
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) {
|
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) -> bool {
|
||||||
// 限制通道类型
|
// 限制通道类型
|
||||||
match self.use_channel_type {
|
match self.use_channel_type {
|
||||||
UseChannelType::P2p => {
|
UseChannelType::P2p => {
|
||||||
if !route.is_p2p() {
|
if !route.is_p2p() {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -351,7 +393,7 @@ impl RouteTable {
|
|||||||
if let Some((_, list)) = self.route_table.read().get(&id) {
|
if let Some((_, list)) = self.route_table.read().get(&id) {
|
||||||
for (x, _) in list {
|
for (x, _) in list {
|
||||||
if x.route_key() == key {
|
if x.route_key() == key {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,11 +406,11 @@ impl RouteTable {
|
|||||||
for (x, time) in list.iter_mut() {
|
for (x, time) in list.iter_mut() {
|
||||||
if x.metric < route.metric && !self.first_latency {
|
if x.metric < route.metric && !self.first_latency {
|
||||||
//非优先延迟的情况下 不能比当前的路径更长
|
//非优先延迟的情况下 不能比当前的路径更长
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if x.route_key() == key {
|
if x.route_key() == key {
|
||||||
if only_if_absent {
|
if only_if_absent {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
x.metric = route.metric;
|
x.metric = route.metric;
|
||||||
x.rt = route.rt;
|
x.rt = route.rt;
|
||||||
@@ -378,21 +420,7 @@ impl RouteTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if exist {
|
if exist {
|
||||||
// 这个排序还有待优化,因为后加入的大概率排最后,被直接淘汰的概率也大,可能导致更好的通道被移除了
|
|
||||||
list.sort_by_key(|(k, _)| k.rt);
|
list.sort_by_key(|(k, _)| k.rt);
|
||||||
//如果延迟都稳定了,则去除多余通道
|
|
||||||
for (route, _) in list.iter() {
|
|
||||||
if route.rt == DEFAULT_RT {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//延迟优先模式需要更多的通道探测延迟最低的路线
|
|
||||||
let limit_len = if self.first_latency {
|
|
||||||
self.channel_num + 2
|
|
||||||
} else {
|
|
||||||
self.channel_num
|
|
||||||
};
|
|
||||||
self.truncate_(list, limit_len);
|
|
||||||
} else {
|
} else {
|
||||||
if !self.first_latency {
|
if !self.first_latency {
|
||||||
if route.is_p2p() {
|
if route.is_p2p() {
|
||||||
@@ -400,35 +428,34 @@ impl RouteTable {
|
|||||||
list.retain(|(k, _)| k.is_p2p());
|
list.retain(|(k, _)| k.is_p2p());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//增加路由表容量,避免波动
|
|
||||||
let limit_len = self.channel_num * 2;
|
|
||||||
list.sort_by_key(|(k, _)| k.rt);
|
list.sort_by_key(|(k, _)| k.rt);
|
||||||
self.truncate_(list, limit_len);
|
|
||||||
list.push((route, AtomicCell::new(Instant::now())));
|
list.push((route, AtomicCell::new(Instant::now())));
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
fn truncate_(&self, list: &mut Vec<(Route, AtomicCell<Instant>)>, len: usize) {
|
// 直接移除会导致通道不稳定,所以废弃这个方法,后面改用多余通道不发心跳包,从而让通道自动过期
|
||||||
if list.len() <= len {
|
// fn truncate_(&self, list: &mut Vec<(Route, AtomicCell<Instant>)>, len: usize) {
|
||||||
return;
|
// if list.len() <= len {
|
||||||
}
|
// return;
|
||||||
if self.first_latency {
|
// }
|
||||||
//找到第一个p2p通道
|
// if self.first_latency {
|
||||||
if let Some(index) =
|
// //找到第一个p2p通道
|
||||||
list.iter()
|
// if let Some(index) =
|
||||||
.enumerate()
|
// list.iter()
|
||||||
.find_map(|(index, (route, _))| if route.is_p2p() { Some(index) } else { None })
|
// .enumerate()
|
||||||
{
|
// .find_map(|(index, (route, _))| if route.is_p2p() { Some(index) } else { None })
|
||||||
if index >= len {
|
// {
|
||||||
//保留第一个p2p通道
|
// if index >= len {
|
||||||
let route = list.remove(index);
|
// //保留第一个p2p通道
|
||||||
list.truncate(len - 1);
|
// let route = list.remove(index);
|
||||||
list.push(route);
|
// list.truncate(len - 1);
|
||||||
return;
|
// list.push(route);
|
||||||
}
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
list.truncate(len);
|
// }
|
||||||
}
|
// list.truncate(len);
|
||||||
|
// }
|
||||||
pub fn route(&self, id: &Ipv4Addr) -> Option<Vec<Route>> {
|
pub fn route(&self, id: &Ipv4Addr) -> Option<Vec<Route>> {
|
||||||
if let Some((_, v)) = self.route_table.read().get(id) {
|
if let Some((_, v)) = self.route_table.read().get(id) {
|
||||||
Some(v.iter().map(|(i, _)| *i).collect())
|
Some(v.iter().map(|(i, _)| *i).collect())
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::RouteKey;
|
use crate::channel::RouteKey;
|
||||||
|
|
||||||
pub trait RecvChannelHandler: Clone + Send + 'static {
|
pub trait RecvChannelHandler: Clone + Send + Sync + 'static {
|
||||||
fn handle(
|
fn handle(
|
||||||
&mut self,
|
&self,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
extend: &mut [u8],
|
extend: &mut [u8],
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl Idle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let sleep_time = self.read_idle - max;
|
let sleep_time = self.read_idle.checked_sub(max).unwrap_or_default();
|
||||||
return IdleType::Sleep(sleep_time);
|
return IdleType::Sleep(sleep_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+159
-54
@@ -1,12 +1,17 @@
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use std::net::{SocketAddr, UdpSocket};
|
use std::net::{SocketAddr, UdpSocket};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use tokio::sync::mpsc::channel;
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::handler::RecvChannelHandler;
|
use crate::channel::handler::RecvChannelHandler;
|
||||||
use crate::channel::sender::AcceptSocketSender;
|
use crate::channel::sender::{AcceptSocketSender, ConnectUtil};
|
||||||
|
use crate::channel::socket::{bind_udp, LocalInterface};
|
||||||
use crate::channel::tcp_channel::tcp_listen;
|
use crate::channel::tcp_channel::tcp_listen;
|
||||||
use crate::channel::udp_channel::udp_listen;
|
use crate::channel::udp_channel::udp_listen;
|
||||||
|
#[cfg(feature = "ws")]
|
||||||
|
use crate::channel::ws_channel::ws_connect_accept;
|
||||||
|
use crate::util::limit::TrafficMeterMultiAddress;
|
||||||
use crate::util::StopManager;
|
use crate::util::StopManager;
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
@@ -15,16 +20,24 @@ pub mod idle;
|
|||||||
pub mod notify;
|
pub mod notify;
|
||||||
pub mod punch;
|
pub mod punch;
|
||||||
pub mod sender;
|
pub mod sender;
|
||||||
|
pub mod socket;
|
||||||
pub mod tcp_channel;
|
pub mod tcp_channel;
|
||||||
pub mod udp_channel;
|
pub mod udp_channel;
|
||||||
|
#[cfg(feature = "ws")]
|
||||||
|
pub mod ws_channel;
|
||||||
|
|
||||||
|
pub const BUFFER_SIZE: usize = 1024 * 64;
|
||||||
|
// 这里留个坑,tcp是支持_TCP_MAX_PACKET_SIZE长度的,
|
||||||
|
// 但是缓存只用BUFFER_SIZE,会导致多余的数据接收不了
|
||||||
|
const TCP_MAX_PACKET_SIZE: usize = (1 << 24) - 1;
|
||||||
|
|
||||||
pub const BUFFER_SIZE: usize = 1024 * 16;
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum UseChannelType {
|
pub enum UseChannelType {
|
||||||
Relay,
|
Relay,
|
||||||
P2p,
|
P2p,
|
||||||
All,
|
All,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UseChannelType {
|
impl UseChannelType {
|
||||||
pub fn is_only_relay(&self) -> bool {
|
pub fn is_only_relay(&self) -> bool {
|
||||||
self == &UseChannelType::Relay
|
self == &UseChannelType::Relay
|
||||||
@@ -36,6 +49,7 @@ impl UseChannelType {
|
|||||||
self == &UseChannelType::All
|
self == &UseChannelType::All
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for UseChannelType {
|
impl FromStr for UseChannelType {
|
||||||
type Err = String;
|
type Err = String;
|
||||||
|
|
||||||
@@ -48,15 +62,49 @@ impl FromStr for UseChannelType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for UseChannelType {
|
impl Default for UseChannelType {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
UseChannelType::All
|
UseChannelType::All
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
pub enum ConnectProtocol {
|
||||||
|
UDP,
|
||||||
|
TCP,
|
||||||
|
WS,
|
||||||
|
WSS,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectProtocol {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_tcp(&self) -> bool {
|
||||||
|
self == &ConnectProtocol::TCP
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn is_udp(&self) -> bool {
|
||||||
|
self == &ConnectProtocol::UDP
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn is_ws(&self) -> bool {
|
||||||
|
self == &ConnectProtocol::WS
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn is_wss(&self) -> bool {
|
||||||
|
self == &ConnectProtocol::WSS
|
||||||
|
}
|
||||||
|
pub fn is_transport(&self) -> bool {
|
||||||
|
self.is_tcp() || self.is_udp()
|
||||||
|
}
|
||||||
|
pub fn is_base_tcp(&self) -> bool {
|
||||||
|
self.is_tcp() || self.is_ws() || self.is_wss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
pub is_tcp: bool,
|
pub protocol: ConnectProtocol,
|
||||||
index: usize,
|
index: usize,
|
||||||
pub addr: SocketAddr,
|
pub addr: SocketAddr,
|
||||||
pub metric: u8,
|
pub metric: u8,
|
||||||
@@ -68,11 +116,19 @@ pub struct RouteSortKey {
|
|||||||
pub metric: u8,
|
pub metric: u8,
|
||||||
pub rt: i64,
|
pub rt: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_RT: i64 = 9999;
|
const DEFAULT_RT: i64 = 9999;
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
pub fn new(is_tcp: bool, index: usize, addr: SocketAddr, metric: u8, rt: i64) -> Self {
|
pub fn new(
|
||||||
|
protocol: ConnectProtocol,
|
||||||
|
index: usize,
|
||||||
|
addr: SocketAddr,
|
||||||
|
metric: u8,
|
||||||
|
rt: i64,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_tcp,
|
protocol,
|
||||||
index,
|
index,
|
||||||
addr,
|
addr,
|
||||||
metric,
|
metric,
|
||||||
@@ -81,7 +137,7 @@ impl Route {
|
|||||||
}
|
}
|
||||||
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
|
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_tcp: route_key.is_tcp,
|
protocol: route_key.protocol,
|
||||||
index: route_key.index,
|
index: route_key.index,
|
||||||
addr: route_key.addr,
|
addr: route_key.addr,
|
||||||
metric,
|
metric,
|
||||||
@@ -90,7 +146,7 @@ impl Route {
|
|||||||
}
|
}
|
||||||
pub fn from_default_rt(route_key: RouteKey, metric: u8) -> Self {
|
pub fn from_default_rt(route_key: RouteKey, metric: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_tcp: route_key.is_tcp,
|
protocol: route_key.protocol,
|
||||||
index: route_key.index,
|
index: route_key.index,
|
||||||
addr: route_key.addr,
|
addr: route_key.addr,
|
||||||
metric,
|
metric,
|
||||||
@@ -99,7 +155,7 @@ impl Route {
|
|||||||
}
|
}
|
||||||
pub fn route_key(&self) -> RouteKey {
|
pub fn route_key(&self) -> RouteKey {
|
||||||
RouteKey {
|
RouteKey {
|
||||||
is_tcp: self.is_tcp,
|
protocol: self.protocol,
|
||||||
index: self.index,
|
index: self.index,
|
||||||
addr: self.addr,
|
addr: self.addr,
|
||||||
}
|
}
|
||||||
@@ -117,37 +173,43 @@ impl Route {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||||
pub struct RouteKey {
|
pub struct RouteKey {
|
||||||
is_tcp: bool,
|
protocol: ConnectProtocol,
|
||||||
index: usize,
|
index: usize,
|
||||||
pub addr: SocketAddr,
|
pub addr: SocketAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RouteKey {
|
impl RouteKey {
|
||||||
pub(crate) fn new(is_tcp: bool, index: usize, addr: SocketAddr) -> Self {
|
pub(crate) const fn new(protocol: ConnectProtocol, index: usize, addr: SocketAddr) -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_tcp,
|
protocol,
|
||||||
index,
|
index,
|
||||||
addr,
|
addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_tcp(&self) -> bool {
|
#[inline]
|
||||||
self.is_tcp
|
pub fn protocol(&self) -> ConnectProtocol {
|
||||||
|
self.protocol
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
pub fn index(&self) -> usize {
|
pub fn index(&self) -> usize {
|
||||||
self.index
|
self.index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_context(
|
pub(crate) fn init_context(
|
||||||
ports: Vec<u16>,
|
ports: Vec<u16>,
|
||||||
use_channel_type: UseChannelType,
|
use_channel_type: UseChannelType,
|
||||||
first_latency: bool,
|
first_latency: bool,
|
||||||
is_tcp: bool,
|
protocol: ConnectProtocol,
|
||||||
packet_loss_rate: Option<f64>,
|
packet_loss_rate: Option<f64>,
|
||||||
packet_delay: u32,
|
packet_delay: u32,
|
||||||
) -> anyhow::Result<(ChannelContext, mio::net::TcpListener)> {
|
default_interface: LocalInterface,
|
||||||
|
up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
|
down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
|
) -> anyhow::Result<(ChannelContext, std::net::TcpListener)> {
|
||||||
assert!(!ports.is_empty(), "not channel");
|
assert!(!ports.is_empty(), "not channel");
|
||||||
let mut udps = Vec::with_capacity(ports.len());
|
let mut main_udp_socket_v4 = Vec::with_capacity(ports.len());
|
||||||
|
let mut main_udp_socket_v6 = Vec::with_capacity(ports.len());
|
||||||
//检查系统是否支持ipv6
|
//检查系统是否支持ipv6
|
||||||
let use_ipv6 = match socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::DGRAM, None) {
|
let use_ipv6 = match socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::DGRAM, None) {
|
||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
@@ -157,41 +219,33 @@ pub fn init_context(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
for port in &ports {
|
for port in &ports {
|
||||||
//监听v6+v4双栈
|
let addr_v4: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
|
||||||
let (socket, address) = if use_ipv6 {
|
if use_ipv6 {
|
||||||
let address: SocketAddr = format!("[::]:{}", port).parse().unwrap();
|
let (main_channel_v4, main_channel_v6) = bind_udp_v4_and_v6(*port, &default_interface)?;
|
||||||
let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::DGRAM, None)?;
|
main_udp_socket_v4.push(main_channel_v4);
|
||||||
socket
|
main_udp_socket_v6.push(main_channel_v6);
|
||||||
.set_only_v6(false)
|
|
||||||
.with_context(|| format!("set_only_v6 failed: {}", &address))?;
|
|
||||||
(socket, address)
|
|
||||||
} else {
|
} else {
|
||||||
let address: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
|
let socket = bind_udp(addr_v4, &default_interface)?;
|
||||||
(
|
let main_channel_v4: UdpSocket = socket.into();
|
||||||
socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::DGRAM, None)?,
|
main_udp_socket_v4.push(main_channel_v4);
|
||||||
address,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
if let Err(e) = socket.set_send_buffer_size(2 * 1024 * 1024) {
|
|
||||||
log::warn!("set_send_buffer_size {:?}", e);
|
|
||||||
}
|
}
|
||||||
if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) {
|
|
||||||
log::warn!("set_send_buffer_size {:?}", e);
|
|
||||||
}
|
|
||||||
socket
|
|
||||||
.bind(&address.into())
|
|
||||||
.with_context(|| format!("bind failed: {}", &address))?;
|
|
||||||
let main_channel: UdpSocket = socket.into();
|
|
||||||
udps.push(main_channel);
|
|
||||||
}
|
}
|
||||||
|
let mut main_udp_socket =
|
||||||
|
Vec::with_capacity(main_udp_socket_v4.len() + main_udp_socket_v6.len());
|
||||||
|
let v4_len = main_udp_socket_v4.len();
|
||||||
|
main_udp_socket.append(&mut main_udp_socket_v4);
|
||||||
|
main_udp_socket.append(&mut main_udp_socket_v6);
|
||||||
let context = ChannelContext::new(
|
let context = ChannelContext::new(
|
||||||
udps,
|
main_udp_socket,
|
||||||
|
v4_len,
|
||||||
use_channel_type,
|
use_channel_type,
|
||||||
first_latency,
|
first_latency,
|
||||||
is_tcp,
|
protocol,
|
||||||
packet_loss_rate,
|
packet_loss_rate,
|
||||||
packet_delay,
|
packet_delay,
|
||||||
use_ipv6,
|
up_traffic_meter,
|
||||||
|
down_traffic_meter,
|
||||||
|
default_interface,
|
||||||
);
|
);
|
||||||
|
|
||||||
let port = context.main_local_udp_port()?[0];
|
let port = context.main_local_udp_port()?[0];
|
||||||
@@ -208,7 +262,13 @@ pub fn init_context(
|
|||||||
let socket = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, None)?;
|
let socket = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, None)?;
|
||||||
(socket, address)
|
(socket, address)
|
||||||
};
|
};
|
||||||
|
socket
|
||||||
|
.set_reuse_address(true)
|
||||||
|
.context("set_reuse_address")?;
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Err(e) = socket.set_reuse_port(true) {
|
||||||
|
log::warn!("set_reuse_port {:?}", e)
|
||||||
|
}
|
||||||
if let Err(e) = socket.bind(&address.into()) {
|
if let Err(e) = socket.bind(&address.into()) {
|
||||||
if ports[0] == 0 {
|
if ports[0] == 0 {
|
||||||
//端口可能冲突,则使用任意端口
|
//端口可能冲突,则使用任意端口
|
||||||
@@ -228,33 +288,78 @@ pub fn init_context(
|
|||||||
}
|
}
|
||||||
socket.listen(128)?;
|
socket.listen(128)?;
|
||||||
socket.set_nonblocking(true)?;
|
socket.set_nonblocking(true)?;
|
||||||
socket.set_nodelay(false)?;
|
socket.set_nodelay(true)?;
|
||||||
let tcp_listener = mio::net::TcpListener::from_std(socket.into());
|
Ok((context, socket.into()))
|
||||||
Ok((context, tcp_listener))
|
}
|
||||||
|
fn bind_udp_v4_and_v6(
|
||||||
|
port: u16,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<(UdpSocket, UdpSocket)> {
|
||||||
|
let mut count = 0;
|
||||||
|
loop {
|
||||||
|
let addr_v4: SocketAddr = format!("0.0.0.0:{}", port).parse().unwrap();
|
||||||
|
let socket = bind_udp(addr_v4, default_interface)?;
|
||||||
|
if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) {
|
||||||
|
log::warn!("set_recv_buffer_size {:?}", e);
|
||||||
|
}
|
||||||
|
let main_channel_v4: UdpSocket = socket.into();
|
||||||
|
let addr = main_channel_v4.local_addr()?;
|
||||||
|
let addr_v6: SocketAddr = format!("[::]:{}", addr.port()).parse().unwrap();
|
||||||
|
let socket = if port == 0 {
|
||||||
|
match bind_udp(addr_v6, default_interface) {
|
||||||
|
Ok(socket) => socket,
|
||||||
|
Err(e) => {
|
||||||
|
if count > 10 {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
if let Some(e) = e.downcast_ref::<std::io::Error>() {
|
||||||
|
if e.kind() == std::io::ErrorKind::AddrInUse {
|
||||||
|
count += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bind_udp(addr_v6, default_interface)?
|
||||||
|
};
|
||||||
|
if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) {
|
||||||
|
log::warn!("set_recv_buffer_size {:?}", e);
|
||||||
|
}
|
||||||
|
let main_channel_v6: UdpSocket = socket.into();
|
||||||
|
return Ok((main_channel_v4, main_channel_v6));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_channel<H>(
|
pub(crate) fn init_channel<H>(
|
||||||
tcp_listener: mio::net::TcpListener,
|
tcp_listener: std::net::TcpListener,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
recv_handler: H,
|
recv_handler: H,
|
||||||
) -> anyhow::Result<(
|
) -> anyhow::Result<(
|
||||||
AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
|
AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
|
||||||
AcceptSocketSender<(mio::net::TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
ConnectUtil,
|
||||||
)>
|
)>
|
||||||
where
|
where
|
||||||
H: RecvChannelHandler,
|
H: RecvChannelHandler,
|
||||||
{
|
{
|
||||||
|
let (tcp_connect_s, tcp_connect_r) = channel(16);
|
||||||
|
let (ws_connect_s, _ws_connect_r) = channel(16);
|
||||||
|
let connect_util = ConnectUtil::new(tcp_connect_s, ws_connect_s);
|
||||||
// udp监听,udp_socket_sender 用于NAT类型切换
|
// udp监听,udp_socket_sender 用于NAT类型切换
|
||||||
let udp_socket_sender =
|
let udp_socket_sender =
|
||||||
udp_listen(stop_manager.clone(), recv_handler.clone(), context.clone())?;
|
udp_listen(stop_manager.clone(), recv_handler.clone(), context.clone())?;
|
||||||
// 建立tcp监听,tcp_socket_sender 用于tcp 直连
|
// 建立tcp监听,tcp_socket_sender 用于tcp 直连
|
||||||
let tcp_socket_sender = tcp_listen(
|
tcp_listen(
|
||||||
tcp_listener,
|
tcp_listener,
|
||||||
stop_manager.clone(),
|
tcp_connect_r,
|
||||||
recv_handler.clone(),
|
recv_handler.clone(),
|
||||||
context.clone(),
|
context.clone(),
|
||||||
|
stop_manager.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
#[cfg(feature = "ws")]
|
||||||
|
ws_connect_accept(_ws_connect_r, recv_handler, context.clone(), stop_manager)?;
|
||||||
|
|
||||||
Ok((udp_socket_sender, tcp_socket_sender))
|
Ok((udp_socket_sender, connect_util))
|
||||||
}
|
}
|
||||||
|
|||||||
+181
-78
@@ -1,23 +1,51 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||||
|
use std::ops::{Div, Mul};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
|
|
||||||
use mio::net::TcpStream;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use rand::prelude::SliceRandom;
|
use rand::prelude::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::sender::AcceptSocketSender;
|
use crate::channel::sender::ConnectUtil;
|
||||||
use crate::external_route::ExternalRoute;
|
use crate::handle::CurrentDeviceInfo;
|
||||||
use crate::nat::NatTest;
|
use crate::nat::{is_ipv4_global, NatTest};
|
||||||
|
use crate::proto::message::{PunchNatModel, PunchNatType};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum PunchModel {
|
pub enum PunchModel {
|
||||||
|
All,
|
||||||
IPv4,
|
IPv4,
|
||||||
IPv6,
|
IPv6,
|
||||||
All,
|
IPv4Tcp,
|
||||||
|
IPv4Udp,
|
||||||
|
IPv6Tcp,
|
||||||
|
IPv6Udp,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PunchModel {
|
||||||
|
pub fn use_tcp(&self) -> bool {
|
||||||
|
self != &PunchModel::IPv4Udp && self != &PunchModel::IPv6Udp
|
||||||
|
}
|
||||||
|
pub fn use_udp(&self) -> bool {
|
||||||
|
self != &PunchModel::IPv4Tcp && self != &PunchModel::IPv6Tcp
|
||||||
|
}
|
||||||
|
pub fn use_ipv6(&self) -> bool {
|
||||||
|
self == &PunchModel::All
|
||||||
|
|| self == &PunchModel::IPv6
|
||||||
|
|| self == &PunchModel::IPv6Tcp
|
||||||
|
|| self == &PunchModel::IPv6Udp
|
||||||
|
}
|
||||||
|
pub fn use_ipv4(&self) -> bool {
|
||||||
|
self == &PunchModel::All
|
||||||
|
|| self == &PunchModel::IPv4
|
||||||
|
|| self == &PunchModel::IPv4Tcp
|
||||||
|
|| self == &PunchModel::IPv4Udp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for PunchModel {
|
impl FromStr for PunchModel {
|
||||||
@@ -27,8 +55,15 @@ impl FromStr for PunchModel {
|
|||||||
match s.to_lowercase().trim() {
|
match s.to_lowercase().trim() {
|
||||||
"ipv4" => Ok(PunchModel::IPv4),
|
"ipv4" => Ok(PunchModel::IPv4),
|
||||||
"ipv6" => Ok(PunchModel::IPv6),
|
"ipv6" => Ok(PunchModel::IPv6),
|
||||||
|
"ipv4-tcp" => Ok(PunchModel::IPv4Tcp),
|
||||||
|
"ipv4-udp" => Ok(PunchModel::IPv4Udp),
|
||||||
|
"ipv6-tcp" => Ok(PunchModel::IPv6Tcp),
|
||||||
|
"ipv6-udp" => Ok(PunchModel::IPv6Udp),
|
||||||
"all" => Ok(PunchModel::All),
|
"all" => Ok(PunchModel::All),
|
||||||
_ => Err(format!("not match '{}', enum: ipv4/ipv6/all", s)),
|
_ => Err(format!(
|
||||||
|
"not match '{}', enum: ipv4/ipv4-tcp/ipv4-udp/ipv6/ipv6-tcp/ipv6-udp/all",
|
||||||
|
s
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,6 +73,33 @@ impl Default for PunchModel {
|
|||||||
PunchModel::All
|
PunchModel::All
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl From<PunchModel> for PunchNatModel {
|
||||||
|
fn from(value: PunchModel) -> Self {
|
||||||
|
match value {
|
||||||
|
PunchModel::All => PunchNatModel::All,
|
||||||
|
PunchModel::IPv4 => PunchNatModel::IPv4,
|
||||||
|
PunchModel::IPv6 => PunchNatModel::IPv6,
|
||||||
|
PunchModel::IPv4Tcp => PunchNatModel::IPv4Tcp,
|
||||||
|
PunchModel::IPv4Udp => PunchNatModel::IPv4Udp,
|
||||||
|
PunchModel::IPv6Tcp => PunchNatModel::IPv6Tcp,
|
||||||
|
PunchModel::IPv6Udp => PunchNatModel::IPv6Udp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<PunchModel> for PunchNatModel {
|
||||||
|
fn into(self) -> PunchModel {
|
||||||
|
match self {
|
||||||
|
PunchNatModel::All => PunchModel::All,
|
||||||
|
PunchNatModel::IPv4 => PunchModel::IPv4,
|
||||||
|
PunchNatModel::IPv6 => PunchModel::IPv6,
|
||||||
|
PunchNatModel::IPv4Tcp => PunchModel::IPv4Tcp,
|
||||||
|
PunchNatModel::IPv4Udp => PunchModel::IPv4Udp,
|
||||||
|
PunchNatModel::IPv6Tcp => PunchModel::IPv6Tcp,
|
||||||
|
PunchNatModel::IPv6Udp => PunchModel::IPv6Udp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct NatInfo {
|
pub struct NatInfo {
|
||||||
@@ -47,8 +109,10 @@ pub struct NatInfo {
|
|||||||
pub nat_type: NatType,
|
pub nat_type: NatType,
|
||||||
pub(crate) local_ipv4: Option<Ipv4Addr>,
|
pub(crate) local_ipv4: Option<Ipv4Addr>,
|
||||||
pub(crate) ipv6: Option<Ipv6Addr>,
|
pub(crate) ipv6: Option<Ipv6Addr>,
|
||||||
pub(crate) udp_ports: Vec<u16>,
|
pub udp_ports: Vec<u16>,
|
||||||
pub tcp_port: u16,
|
pub tcp_port: u16,
|
||||||
|
pub public_tcp_port: u16,
|
||||||
|
pub punch_model: PunchModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
@@ -57,6 +121,29 @@ pub enum NatType {
|
|||||||
Cone,
|
Cone,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NatType {
|
||||||
|
pub fn is_cone(&self) -> bool {
|
||||||
|
self == &NatType::Cone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 NatInfo {
|
impl NatInfo {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
mut public_ips: Vec<Ipv4Addr>,
|
mut public_ips: Vec<Ipv4Addr>,
|
||||||
@@ -66,7 +153,9 @@ impl NatInfo {
|
|||||||
mut ipv6: Option<Ipv6Addr>,
|
mut ipv6: Option<Ipv6Addr>,
|
||||||
udp_ports: Vec<u16>,
|
udp_ports: Vec<u16>,
|
||||||
tcp_port: u16,
|
tcp_port: u16,
|
||||||
|
public_tcp_port: u16,
|
||||||
mut nat_type: NatType,
|
mut nat_type: NatType,
|
||||||
|
punch_model: PunchModel,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
public_ips.retain(|ip| {
|
public_ips.retain(|ip| {
|
||||||
!ip.is_multicast()
|
!ip.is_multicast()
|
||||||
@@ -96,29 +185,33 @@ impl NatInfo {
|
|||||||
ipv6,
|
ipv6,
|
||||||
udp_ports,
|
udp_ports,
|
||||||
tcp_port,
|
tcp_port,
|
||||||
|
public_tcp_port,
|
||||||
nat_type,
|
nat_type,
|
||||||
|
punch_model,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) {
|
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
|
||||||
|
let mut updated = false;
|
||||||
if port != 0 {
|
if port != 0 {
|
||||||
if let Some(public_port) = self.public_ports.get_mut(index) {
|
if let Some(public_port) = self.public_ports.get_mut(index) {
|
||||||
if *public_port != port {
|
if *public_port != port {
|
||||||
|
updated = true;
|
||||||
log::info!("端口变化={}:{} index={}", ip, port, index)
|
log::info!("端口变化={}:{} index={}", ip, port, index)
|
||||||
}
|
}
|
||||||
*public_port = port;
|
*public_port = port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ip.is_multicast()
|
if is_ipv4_global(&ip) {
|
||||||
&& !ip.is_broadcast()
|
|
||||||
&& !ip.is_unspecified()
|
|
||||||
&& !ip.is_loopback()
|
|
||||||
&& !ip.is_private()
|
|
||||||
{
|
|
||||||
if !self.public_ips.contains(&ip) {
|
if !self.public_ips.contains(&ip) {
|
||||||
self.public_ips.push(ip);
|
self.public_ips.push(ip);
|
||||||
|
updated = true;
|
||||||
log::info!("ip变化={},{:?}", ip, self.public_ips)
|
log::info!("ip变化={},{:?}", ip, self.public_ips)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updated
|
||||||
|
}
|
||||||
|
pub fn update_tcp_port(&mut self, port: u16) {
|
||||||
|
self.public_tcp_port = port;
|
||||||
}
|
}
|
||||||
pub fn local_ipv4(&self) -> Option<Ipv4Addr> {
|
pub fn local_ipv4(&self) -> Option<Ipv4Addr> {
|
||||||
self.local_ipv4
|
self.local_ipv4
|
||||||
@@ -185,20 +278,18 @@ pub struct Punch {
|
|||||||
port_vec: Vec<u16>,
|
port_vec: Vec<u16>,
|
||||||
port_index: HashMap<Ipv4Addr, usize>,
|
port_index: HashMap<Ipv4Addr, usize>,
|
||||||
punch_model: PunchModel,
|
punch_model: PunchModel,
|
||||||
is_tcp: bool,
|
connect_util: ConnectUtil,
|
||||||
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
|
||||||
external_route: ExternalRoute,
|
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Punch {
|
impl Punch {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
punch_model: PunchModel,
|
punch_model: PunchModel,
|
||||||
is_tcp: bool,
|
connect_util: ConnectUtil,
|
||||||
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
|
||||||
external_route: ExternalRoute,
|
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut port_vec: Vec<u16> = (1..65535).collect();
|
let mut port_vec: Vec<u16> = (1..65535).collect();
|
||||||
port_vec.push(65535);
|
port_vec.push(65535);
|
||||||
@@ -209,35 +300,22 @@ impl Punch {
|
|||||||
port_vec,
|
port_vec,
|
||||||
port_index: HashMap::new(),
|
port_index: HashMap::new(),
|
||||||
punch_model,
|
punch_model,
|
||||||
is_tcp,
|
connect_util,
|
||||||
tcp_socket_sender,
|
|
||||||
external_route,
|
|
||||||
nat_test,
|
nat_test,
|
||||||
|
current_device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Punch {
|
impl Punch {
|
||||||
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) -> bool {
|
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) {
|
||||||
if self.nat_test.is_local_address(true, addr) {
|
if self.nat_test.is_local_address(true, addr) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
// mio是非阻塞的,不能立马判断是否能连接成功,所以用标准库的tcp
|
if addr.ip().is_unspecified() || addr.port() == 0 {
|
||||||
match std::net::TcpStream::connect_timeout(&addr, Duration::from_millis(100)) {
|
return;
|
||||||
Ok(tcp_stream) => {
|
|
||||||
if tcp_stream.set_nonblocking(true).is_err() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return self
|
|
||||||
.tcp_socket_sender
|
|
||||||
.try_add_socket((TcpStream::from_std(tcp_stream), addr, Some(buf.to_vec())))
|
|
||||||
.is_ok();
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("连接到tcp失败,addr={},err={}", addr, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
false
|
self.connect_util.try_connect_tcp_punch(buf.to_vec(), addr);
|
||||||
}
|
}
|
||||||
pub fn punch(
|
pub fn punch(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -245,46 +323,65 @@ impl Punch {
|
|||||||
id: Ipv4Addr,
|
id: Ipv4Addr,
|
||||||
mut nat_info: NatInfo,
|
mut nat_info: NatInfo,
|
||||||
punch_tcp: bool,
|
punch_tcp: bool,
|
||||||
|
count: usize,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
if self.context.route_table.no_need_punch(&id) {
|
if self.context.route_table.no_need_punch(&id) {
|
||||||
log::info!("已打洞成功,无需打洞:{:?}", id);
|
log::info!("已打洞成功,无需打洞:{:?}", id);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let device_info = self.current_device.load();
|
||||||
|
|
||||||
nat_info
|
nat_info
|
||||||
.public_ips
|
.public_ips
|
||||||
.retain(|ip| self.external_route.route(&ip).is_none());
|
.retain(|ip| is_ipv4_global(ip) && device_info.not_in_network(*ip));
|
||||||
nat_info
|
nat_info.public_ports.retain(|port| *port != 0);
|
||||||
|
nat_info.udp_ports.retain(|port| *port != 0);
|
||||||
|
|
||||||
|
nat_info.local_ipv4 = nat_info
|
||||||
.local_ipv4
|
.local_ipv4
|
||||||
.filter(|ip| self.external_route.route(&ip).is_none());
|
.filter(|ip| device_info.not_in_network(*ip));
|
||||||
nat_info.ipv6.filter(|ip| {
|
if punch_tcp && self.punch_model.use_tcp() && nat_info.punch_model.use_tcp() {
|
||||||
if let Some(ip) = ip.to_ipv4_mapped() {
|
|
||||||
self.external_route.route(&ip).is_none()
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if punch_tcp && self.is_tcp && nat_info.tcp_port != 0 {
|
|
||||||
//向tcp发起连接
|
//向tcp发起连接
|
||||||
if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() {
|
if self.punch_model.use_ipv6() && nat_info.punch_model.use_ipv6() {
|
||||||
if self.connect_tcp(buf, ipv6_addr) {
|
if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() {
|
||||||
// return Ok(());
|
self.connect_tcp(buf, ipv6_addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//向tcp发起连接
|
if self.punch_model.use_ipv4() && nat_info.punch_model.use_ipv4() {
|
||||||
if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() {
|
if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() {
|
||||||
if self.connect_tcp(buf, ipv4_addr) {
|
self.connect_tcp(buf, ipv4_addr)
|
||||||
// return Ok(());
|
|
||||||
}
|
}
|
||||||
}
|
for ip in &nat_info.public_ips {
|
||||||
if nat_info.nat_type == NatType::Cone && nat_info.public_ips.len() == 1 {
|
let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.tcp_port));
|
||||||
let addr =
|
self.connect_tcp(buf, addr);
|
||||||
SocketAddr::V4(SocketAddrV4::new(nat_info.public_ips[0], nat_info.tcp_port));
|
}
|
||||||
if self.connect_tcp(buf, addr) {
|
if nat_info.nat_type.is_cone() && nat_info.public_tcp_port != 0 {
|
||||||
// return Ok(());
|
for ip in &nat_info.public_ips {
|
||||||
|
let addr = SocketAddr::V4(SocketAddrV4::new(*ip, nat_info.public_tcp_port));
|
||||||
|
self.connect_tcp(buf, addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !self.punch_model.use_udp() || !nat_info.punch_model.use_udp() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let channel_num = self.context.channel_num();
|
let channel_num = self.context.channel_num();
|
||||||
|
let main_len = self.context.main_len();
|
||||||
|
|
||||||
|
if self.punch_model.use_ipv6() && nat_info.punch_model.use_ipv6() {
|
||||||
|
for index in channel_num..main_len {
|
||||||
|
if let Some(ipv6_addr) = nat_info.local_udp_ipv6addr(index) {
|
||||||
|
if !self.nat_test.is_local_address(false, ipv6_addr) {
|
||||||
|
let rs = self.context.send_main_udp(index, buf, ipv6_addr);
|
||||||
|
log::info!("发送到ipv6地址:{:?},rs={:?} {}", ipv6_addr, rs, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !self.punch_model.use_ipv4() || !nat_info.punch_model.use_ipv4() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
for index in 0..channel_num {
|
for index in 0..channel_num {
|
||||||
if let Some(ipv4_addr) = nat_info.local_udp_ipv4addr(index) {
|
if let Some(ipv4_addr) = nat_info.local_udp_ipv4addr(index) {
|
||||||
if !self.nat_test.is_local_address(false, ipv4_addr) {
|
if !self.nat_test.is_local_address(false, ipv4_addr) {
|
||||||
@@ -292,20 +389,23 @@ impl Punch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 可能是开放了端口的,需要打洞
|
||||||
if self.punch_model != PunchModel::IPv4 {
|
for index in 0..channel_num {
|
||||||
for index in 0..channel_num {
|
for port in &nat_info.udp_ports {
|
||||||
if let Some(ipv6_addr) = nat_info.local_udp_ipv6addr(index) {
|
if *port == 0 {
|
||||||
if !self.nat_test.is_local_address(false, ipv6_addr) {
|
continue;
|
||||||
let rs = self.context.send_main_udp(index, buf, ipv6_addr);
|
}
|
||||||
log::info!("发送到ipv6地址:{:?},rs={:?}", ipv6_addr, rs);
|
for ip in &nat_info.public_ips {
|
||||||
if rs.is_ok() && self.punch_model == PunchModel::IPv6 {
|
if ip.is_unspecified() {
|
||||||
return Ok(());
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let addr = SocketAddrV4::new(*ip, *port);
|
||||||
|
let _ = self.context.send_main_udp(index, buf, addr.into());
|
||||||
|
thread::sleep(Duration::from_millis(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match nat_info.nat_type {
|
match nat_info.nat_type {
|
||||||
NatType::Symmetric => {
|
NatType::Symmetric => {
|
||||||
// 假设对方绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,自己随机尝试k次的情况下
|
// 假设对方绑定n个端口,通过NAT对外映射出n个 公网ip:公网端口,自己随机尝试k次的情况下
|
||||||
@@ -316,7 +416,11 @@ impl Punch {
|
|||||||
//预测范围内最多发送max_k1个包
|
//预测范围内最多发送max_k1个包
|
||||||
let max_k1 = 60;
|
let max_k1 = 60;
|
||||||
//全局最多发送max_k2个包
|
//全局最多发送max_k2个包
|
||||||
let max_k2 = rand::thread_rng().gen_range(600..800);
|
let mut max_k2: usize = rand::thread_rng().gen_range(600..800);
|
||||||
|
if count > 2 {
|
||||||
|
//递减探测规模
|
||||||
|
max_k2 = max_k2.mul(2).div(count).max(max_k1 as usize);
|
||||||
|
}
|
||||||
let port = nat_info.public_ports.get(0).map(|e| *e).unwrap_or(0);
|
let port = nat_info.public_ports.get(0).map(|e| *e).unwrap_or(0);
|
||||||
if nat_info.public_port_range < max_k1 * 3 {
|
if nat_info.public_port_range < max_k1 * 3 {
|
||||||
//端口变化不大时,在预测的范围内随机发送
|
//端口变化不大时,在预测的范围内随机发送
|
||||||
@@ -332,8 +436,7 @@ impl Punch {
|
|||||||
} else {
|
} else {
|
||||||
(max_port - min_port + 1) as usize
|
(max_port - min_port + 1) as usize
|
||||||
};
|
};
|
||||||
let mut nums: Vec<u16> = (min_port..max_port).collect();
|
let mut nums: Vec<u16> = (min_port..=max_port).collect();
|
||||||
nums.push(max_port);
|
|
||||||
nums.shuffle(&mut rand::thread_rng());
|
nums.shuffle(&mut rand::thread_rng());
|
||||||
self.punch_symmetric(&nums[..k], buf, &nat_info.public_ips, max_k1 as usize)?;
|
self.punch_symmetric(&nums[..k], buf, &nat_info.public_ips, max_k1 as usize)?;
|
||||||
}
|
}
|
||||||
@@ -397,7 +500,7 @@ impl Punch {
|
|||||||
}
|
}
|
||||||
let addr = SocketAddr::V4(SocketAddrV4::new(*pub_ip, *port));
|
let addr = SocketAddr::V4(SocketAddrV4::new(*pub_ip, *port));
|
||||||
self.context.send_main_udp(0, buf, addr)?;
|
self.context.send_main_udp(0, buf, addr)?;
|
||||||
thread::sleep(Duration::from_millis(2));
|
thread::sleep(Duration::from_millis(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ports.len())
|
Ok(ports.len())
|
||||||
|
|||||||
+218
-51
@@ -1,31 +1,190 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::ops::Deref;
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
use std::sync::mpsc::{SyncSender, TrySendError};
|
use std::sync::mpsc::{SyncSender, TrySendError};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use mio::Token;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use tokio::sync::mpsc::Sender;
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::notify::{AcceptNotify, WritableNotify};
|
use crate::channel::notify::AcceptNotify;
|
||||||
|
use crate::cipher::Cipher;
|
||||||
|
use crate::compression::Compressor;
|
||||||
|
use crate::external_route::ExternalRoute;
|
||||||
|
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
|
use crate::protocol;
|
||||||
|
use crate::protocol::{ip_turn_packet, NetPacket};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ChannelSender {
|
pub struct IpPacketSender {
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
compressor: Compressor,
|
||||||
|
client_cipher: Cipher,
|
||||||
|
server_cipher: Cipher,
|
||||||
|
ip_route: ExternalRoute,
|
||||||
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
|
allow_wire_guard: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelSender {
|
impl IpPacketSender {
|
||||||
pub fn new(context: ChannelContext) -> Self {
|
pub fn new(
|
||||||
Self { context }
|
context: ChannelContext,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
compressor: Compressor,
|
||||||
|
client_cipher: Cipher,
|
||||||
|
server_cipher: Cipher,
|
||||||
|
ip_route: ExternalRoute,
|
||||||
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
|
allow_wire_guard: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
context,
|
||||||
|
current_device,
|
||||||
|
compressor,
|
||||||
|
client_cipher,
|
||||||
|
server_cipher,
|
||||||
|
ip_route,
|
||||||
|
device_map,
|
||||||
|
allow_wire_guard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn self_virtual_ip(&self) -> Ipv4Addr {
|
||||||
|
self.current_device.load().virtual_ip
|
||||||
|
}
|
||||||
|
pub fn send_ip(
|
||||||
|
&self,
|
||||||
|
buf: &mut [u8],
|
||||||
|
data_len: usize,
|
||||||
|
auxiliary_buf: &mut [u8],
|
||||||
|
mut dest_ip: Ipv4Addr,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let device_info = self.current_device.load();
|
||||||
|
let src_ip = device_info.virtual_ip;
|
||||||
|
if src_ip.is_unspecified() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if let Some(v) = self.ip_route.route(&dest_ip) {
|
||||||
|
dest_ip = v;
|
||||||
|
}
|
||||||
|
if dest_ip.is_multicast() {
|
||||||
|
//广播
|
||||||
|
dest_ip = Ipv4Addr::BROADCAST;
|
||||||
|
}
|
||||||
|
let mut net_packet = NetPacket::new0(data_len, buf)?;
|
||||||
|
net_packet.set_default_version();
|
||||||
|
net_packet.set_protocol(protocol::Protocol::IpTurn);
|
||||||
|
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
|
||||||
|
net_packet.first_set_ttl(6);
|
||||||
|
net_packet.set_source(src_ip);
|
||||||
|
net_packet.set_destination(dest_ip);
|
||||||
|
if self.allow_wire_guard {
|
||||||
|
if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip {
|
||||||
|
let exists_wg = self
|
||||||
|
.device_map
|
||||||
|
.lock()
|
||||||
|
.1
|
||||||
|
.values()
|
||||||
|
.any(|v| v.status.is_online() && v.wireguard);
|
||||||
|
if exists_wg {
|
||||||
|
send_to_wg_broadcast(
|
||||||
|
&self.context,
|
||||||
|
&net_packet,
|
||||||
|
&self.server_cipher,
|
||||||
|
&device_info,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let guard = self.device_map.lock();
|
||||||
|
if let Some(peer_info) = guard.1.get(&dest_ip) {
|
||||||
|
if peer_info.wireguard {
|
||||||
|
if peer_info.status.is_offline() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
drop(guard);
|
||||||
|
send_to_wg(
|
||||||
|
&self.context,
|
||||||
|
&mut net_packet,
|
||||||
|
&self.server_cipher,
|
||||||
|
&device_info,
|
||||||
|
)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut auxiliary = NetPacket::new(auxiliary_buf)?;
|
||||||
|
|
||||||
|
let mut net_packet = if self.compressor.compress(&net_packet, &mut auxiliary)? {
|
||||||
|
auxiliary.set_default_version();
|
||||||
|
auxiliary.set_protocol(protocol::Protocol::IpTurn);
|
||||||
|
auxiliary.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
|
||||||
|
auxiliary.first_set_ttl(6);
|
||||||
|
auxiliary.set_source(src_ip);
|
||||||
|
auxiliary.set_destination(dest_ip);
|
||||||
|
auxiliary
|
||||||
|
} else {
|
||||||
|
net_packet
|
||||||
|
};
|
||||||
|
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
|
if dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip {
|
||||||
|
//走服务端广播
|
||||||
|
self.context
|
||||||
|
.send_default(&net_packet, device_info.connect_server)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if device_info.not_in_network(dest_ip) {
|
||||||
|
//不是一个网段的直接忽略
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.context.send_ipv4_by_id(
|
||||||
|
&net_packet,
|
||||||
|
&dest_ip,
|
||||||
|
device_info.connect_server,
|
||||||
|
device_info.status.online(),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for ChannelSender {
|
pub fn send_to_wg_broadcast(
|
||||||
type Target = ChannelContext;
|
sender: &ChannelContext,
|
||||||
|
net_packet: &NetPacket<&mut [u8]>,
|
||||||
|
server_cipher: &Cipher,
|
||||||
|
current_device: &CurrentDeviceInfo,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let mut copy_packet = NetPacket::new0(net_packet.data_len(), [0; 65536])?;
|
||||||
|
copy_packet.set_default_version();
|
||||||
|
copy_packet.set_protocol(protocol::Protocol::IpTurn);
|
||||||
|
copy_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into());
|
||||||
|
copy_packet.first_set_ttl(6);
|
||||||
|
copy_packet.set_source(net_packet.source());
|
||||||
|
copy_packet.set_destination(net_packet.destination());
|
||||||
|
copy_packet.set_gateway_flag(true);
|
||||||
|
copy_packet.set_payload(net_packet.payload())?;
|
||||||
|
server_cipher.encrypt_ipv4(&mut copy_packet)?;
|
||||||
|
sender.send_default(©_packet, current_device.connect_server)?;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
Ok(())
|
||||||
&self.context
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pub fn send_to_wg(
|
||||||
|
sender: &ChannelContext,
|
||||||
|
net_packet: &mut NetPacket<&mut [u8]>,
|
||||||
|
server_cipher: &Cipher,
|
||||||
|
current_device: &CurrentDeviceInfo,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
net_packet.set_transport_protocol(ip_turn_packet::Protocol::WGIpv4.into());
|
||||||
|
net_packet.set_gateway_flag(true);
|
||||||
|
server_cipher.encrypt_ipv4(net_packet)?;
|
||||||
|
sender.send_default(&net_packet, current_device.connect_server)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AcceptSocketSender<T> {
|
pub struct AcceptSocketSender<T> {
|
||||||
sender: SyncSender<T>,
|
sender: SyncSender<T>,
|
||||||
notify: AcceptNotify,
|
notify: AcceptNotify,
|
||||||
@@ -39,6 +198,7 @@ impl<T> Clone for AcceptSocketSender<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AcceptSocketSender<T> {
|
impl<T> AcceptSocketSender<T> {
|
||||||
pub fn new(notify: AcceptNotify, sender: SyncSender<T>) -> Self {
|
pub fn new(notify: AcceptNotify, sender: SyncSender<T>) -> Self {
|
||||||
Self { sender, notify }
|
Self { sender, notify }
|
||||||
@@ -53,53 +213,60 @@ impl<T> AcceptSocketSender<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PacketSender {
|
pub struct PacketSender {
|
||||||
inner: Arc<PacketSenderInner>,
|
sender: Sender<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketSender {
|
impl PacketSender {
|
||||||
pub fn new(notify: WritableNotify, buffer: SyncSender<Vec<u8>>, token: Token) -> Self {
|
pub fn new(sender: Sender<Vec<u8>>) -> Self {
|
||||||
Self {
|
Self { sender }
|
||||||
inner: Arc::new(PacketSenderInner {
|
|
||||||
token,
|
|
||||||
notify,
|
|
||||||
buffer,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[inline]
|
|
||||||
pub fn try_send(&self, buf: &[u8]) -> io::Result<()> {
|
pub fn try_send(&self, buf: &[u8]) -> io::Result<()> {
|
||||||
self.inner.try_send(buf)
|
match self.sender.try_send(buf.to_vec()) {
|
||||||
}
|
Ok(_) => Ok(()),
|
||||||
pub fn shutdown(&self) -> io::Result<()> {
|
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Err(io::Error::new(
|
||||||
self.inner.shutdown()
|
io::ErrorKind::WouldBlock,
|
||||||
}
|
"通道已满,发生丢包",
|
||||||
}
|
)),
|
||||||
|
Err(_) => Err(io::Error::new(
|
||||||
pub struct PacketSenderInner {
|
io::ErrorKind::ConnectionRefused,
|
||||||
token: Token,
|
"通道关闭,发生丢包",
|
||||||
notify: WritableNotify,
|
)),
|
||||||
buffer: SyncSender<Vec<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PacketSenderInner {
|
|
||||||
#[inline]
|
|
||||||
fn try_send(&self, buf: &[u8]) -> io::Result<()> {
|
|
||||||
let len = buf.len();
|
|
||||||
let mut buf_vec = Vec::with_capacity(buf.len() + 4);
|
|
||||||
buf_vec.extend_from_slice(&[0, 0, (len >> 8) as u8, (len & 0xFF) as u8]);
|
|
||||||
buf_vec.extend_from_slice(buf);
|
|
||||||
match self.buffer.try_send(buf_vec) {
|
|
||||||
Ok(_) => self.notify.notify(self.token, true),
|
|
||||||
Err(e) => match e {
|
|
||||||
TrySendError::Disconnected(_) => Err(io::Error::from(io::ErrorKind::WriteZero)),
|
|
||||||
TrySendError::Full(_) => Err(io::Error::from(io::ErrorKind::WouldBlock)),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
}
|
||||||
self.notify.notify(self.token, false)
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ConnectUtil {
|
||||||
|
connect_tcp: Sender<(Vec<u8>, Option<u16>, SocketAddr)>,
|
||||||
|
connect_ws: Sender<(Vec<u8>, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectUtil {
|
||||||
|
pub fn new(
|
||||||
|
connect_tcp: Sender<(Vec<u8>, Option<u16>, SocketAddr)>,
|
||||||
|
connect_ws: Sender<(Vec<u8>, String)>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
connect_tcp,
|
||||||
|
connect_ws,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_connect_tcp(&self, buf: Vec<u8>, addr: SocketAddr) {
|
||||||
|
if self.connect_tcp.try_send((buf, None, addr)).is_err() {
|
||||||
|
log::warn!("try_connect_tcp failed {}", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_connect_tcp_punch(&self, buf: Vec<u8>, addr: SocketAddr) {
|
||||||
|
// 打洞的连接可以绑定随机端口
|
||||||
|
if self.connect_tcp.try_send((buf, Some(0), addr)).is_err() {
|
||||||
|
log::warn!("try_connect_tcp failed {}", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_connect_ws(&self, buf: Vec<u8>, addr: String) {
|
||||||
|
if self.connect_ws.try_send((buf, addr)).is_err() {
|
||||||
|
log::warn!("try_connect_ws failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
use anyhow::{anyhow, Context};
|
||||||
|
use network_interface::{NetworkInterface, NetworkInterfaceConfig};
|
||||||
|
use socket2::Protocol;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
mod unix;
|
||||||
|
#[cfg(windows)]
|
||||||
|
mod windows;
|
||||||
|
|
||||||
|
pub trait VntSocketTrait {
|
||||||
|
fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct LocalInterface {
|
||||||
|
index: u32,
|
||||||
|
#[cfg(unix)]
|
||||||
|
name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn connect_tcp(
|
||||||
|
addr: SocketAddr,
|
||||||
|
bind_port: u16,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<tokio::net::TcpStream> {
|
||||||
|
let socket = create_tcp0(addr.is_ipv4(), bind_port, default_interface)?;
|
||||||
|
Ok(socket.connect(addr).await?)
|
||||||
|
}
|
||||||
|
pub fn create_tcp(
|
||||||
|
v4: bool,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<tokio::net::TcpSocket> {
|
||||||
|
create_tcp0(v4, 0, default_interface)
|
||||||
|
}
|
||||||
|
pub fn create_tcp0(
|
||||||
|
v4: bool,
|
||||||
|
bind_port: u16,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<tokio::net::TcpSocket> {
|
||||||
|
let socket = if v4 {
|
||||||
|
socket2::Socket::new(
|
||||||
|
socket2::Domain::IPV4,
|
||||||
|
socket2::Type::STREAM,
|
||||||
|
Some(Protocol::TCP),
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
socket2::Socket::new(
|
||||||
|
socket2::Domain::IPV6,
|
||||||
|
socket2::Type::STREAM,
|
||||||
|
Some(Protocol::TCP),
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
if v4 {
|
||||||
|
if let Err(e) = socket.set_ip_unicast_if(default_interface) {
|
||||||
|
log::warn!("set_ip_unicast_if {:?}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bind_port != 0 {
|
||||||
|
socket
|
||||||
|
.set_reuse_address(true)
|
||||||
|
.context("set_reuse_address")?;
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Err(e) = socket.set_reuse_port(true) {
|
||||||
|
log::warn!("set_reuse_port {:?}", e)
|
||||||
|
}
|
||||||
|
if v4 {
|
||||||
|
let addr: SocketAddr = format!("0.0.0.0:{}", bind_port).parse().unwrap();
|
||||||
|
socket.bind(&addr.into())?;
|
||||||
|
} else {
|
||||||
|
socket.set_only_v6(true)?;
|
||||||
|
let addr: SocketAddr = format!("[::]:{}", bind_port).parse().unwrap();
|
||||||
|
socket.bind(&addr.into())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socket.set_nonblocking(true)?;
|
||||||
|
socket.set_nodelay(true)?;
|
||||||
|
Ok(tokio::net::TcpSocket::from_std_stream(socket.into()))
|
||||||
|
}
|
||||||
|
pub fn bind_udp_ops(
|
||||||
|
addr: SocketAddr,
|
||||||
|
only_v6: bool,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<socket2::Socket> {
|
||||||
|
let socket = if addr.is_ipv4() {
|
||||||
|
let socket = socket2::Socket::new(
|
||||||
|
socket2::Domain::IPV4,
|
||||||
|
socket2::Type::DGRAM,
|
||||||
|
Some(Protocol::UDP),
|
||||||
|
)?;
|
||||||
|
if let Err(e) = socket.set_ip_unicast_if(default_interface) {
|
||||||
|
log::warn!("set_ip_unicast_if {:?}", e)
|
||||||
|
}
|
||||||
|
socket
|
||||||
|
} else {
|
||||||
|
let socket = socket2::Socket::new(
|
||||||
|
socket2::Domain::IPV6,
|
||||||
|
socket2::Type::DGRAM,
|
||||||
|
Some(Protocol::UDP),
|
||||||
|
)?;
|
||||||
|
socket
|
||||||
|
.set_only_v6(only_v6)
|
||||||
|
.with_context(|| format!("set_only_v6 failed: {}", &addr))?;
|
||||||
|
socket
|
||||||
|
};
|
||||||
|
socket.set_nonblocking(true)?;
|
||||||
|
socket.bind(&addr.into())?;
|
||||||
|
Ok(socket)
|
||||||
|
}
|
||||||
|
pub fn bind_udp(
|
||||||
|
addr: SocketAddr,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<socket2::Socket> {
|
||||||
|
bind_udp_ops(addr, true, default_interface).with_context(|| format!("{}", addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_interface(dest_name: String) -> anyhow::Result<(LocalInterface, Ipv4Addr)> {
|
||||||
|
let network_interfaces = NetworkInterface::show()?;
|
||||||
|
for iface in network_interfaces {
|
||||||
|
if iface.name == dest_name {
|
||||||
|
for addr in iface.addr {
|
||||||
|
if let IpAddr::V4(ip) = addr.ip() {
|
||||||
|
return Ok((
|
||||||
|
LocalInterface {
|
||||||
|
index: iface.index,
|
||||||
|
#[cfg(unix)]
|
||||||
|
name: Some(iface.name),
|
||||||
|
},
|
||||||
|
ip,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(anyhow!("No network card with name {} found", dest_name))
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
use crate::channel::socket::{LocalInterface, VntSocketTrait};
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
impl VntSocketTrait for socket2::Socket {
|
||||||
|
fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> {
|
||||||
|
if let Some(name) = &interface.name {
|
||||||
|
self.bind_device(Some(name.as_bytes()))
|
||||||
|
.context("bind_device")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
impl VntSocketTrait for socket2::Socket {
|
||||||
|
fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> {
|
||||||
|
if interface.index != 0 {
|
||||||
|
self.bind_device_by_index_v4(std::num::NonZeroU32::new(interface.index))
|
||||||
|
.with_context(|| format!("bind_device_by_index_v4 {:?}", interface))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
impl VntSocketTrait for socket2::Socket {
|
||||||
|
fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
// pub fn get_best_interface(dest_ip: Ipv4Addr) -> anyhow::Result<LocalInterface> {
|
||||||
|
// match get_interface(dest_ip) {
|
||||||
|
// Ok(iface) => return Ok(iface),
|
||||||
|
// Err(e) => {
|
||||||
|
// log::warn!("not find interface e={:?},ip={}", e, dest_ip);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // 应该再查路由表找到默认路由的
|
||||||
|
// Ok(LocalInterface::default())
|
||||||
|
// }
|
||||||
|
// #[cfg(target_os = "android")]
|
||||||
|
// pub fn get_best_interface(_dest_ip: Ipv4Addr) -> anyhow::Result<LocalInterface> {
|
||||||
|
// Ok(LocalInterface::default())
|
||||||
|
// }
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
use std::mem;
|
||||||
|
use std::os::windows::io::AsRawSocket;
|
||||||
|
|
||||||
|
use windows_sys::core::PCSTR;
|
||||||
|
use windows_sys::Win32::Networking::WinSock::{
|
||||||
|
htonl, setsockopt, IPPROTO_IP, IP_UNICAST_IF, SOCKET_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::channel::socket::{LocalInterface, VntSocketTrait};
|
||||||
|
|
||||||
|
impl VntSocketTrait for socket2::Socket {
|
||||||
|
fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> {
|
||||||
|
let index = interface.index;
|
||||||
|
if index == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let raw_socket = self.as_raw_socket();
|
||||||
|
let result = unsafe {
|
||||||
|
let best_interface = htonl(index);
|
||||||
|
setsockopt(
|
||||||
|
raw_socket as usize,
|
||||||
|
IPPROTO_IP,
|
||||||
|
IP_UNICAST_IF,
|
||||||
|
&best_interface as *const _ as PCSTR,
|
||||||
|
mem::size_of_val(&best_interface) as i32,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if result == SOCKET_ERROR {
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Failed to set IP_UNICAST_IF: {:?} {}",
|
||||||
|
std::io::Error::last_os_error(),
|
||||||
|
index
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn get_best_interface(dest_ip: Ipv4Addr) -> anyhow::Result<LocalInterface> {
|
||||||
|
// // 获取最佳接口
|
||||||
|
// let index = unsafe {
|
||||||
|
// let mut dest: SOCKADDR_IN = mem::zeroed();
|
||||||
|
// dest.sin_family = AF_INET as u16;
|
||||||
|
// dest.sin_addr.S_un.S_addr = u32::from_ne_bytes(dest_ip.octets());
|
||||||
|
//
|
||||||
|
// let mut index: u32 = 0;
|
||||||
|
// if GetBestInterfaceEx(&dest as *const _ as *mut SOCKADDR, &mut index) != 0 {
|
||||||
|
// Err(anyhow::anyhow!(
|
||||||
|
// "Failed to GetBestInterfaceEx: {:?}",
|
||||||
|
// std::io::Error::last_os_error()
|
||||||
|
// ))?;
|
||||||
|
// }
|
||||||
|
// index
|
||||||
|
// };
|
||||||
|
// Ok(LocalInterface { index })
|
||||||
|
// }
|
||||||
+174
-424
@@ -1,462 +1,212 @@
|
|||||||
use std::collections::HashMap;
|
use anyhow::{anyhow, Context};
|
||||||
use std::io::{Read, Write};
|
use std::net::SocketAddr;
|
||||||
use std::net::{Shutdown, SocketAddr};
|
#[cfg(unix)]
|
||||||
#[cfg(any(unix))]
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::os::fd::FromRawFd;
|
|
||||||
#[cfg(any(unix))]
|
|
||||||
use std::os::fd::IntoRawFd;
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::os::windows::io::FromRawSocket;
|
use std::os::windows::io::AsRawSocket;
|
||||||
#[cfg(windows)]
|
use std::thread;
|
||||||
use std::os::windows::io::IntoRawSocket;
|
use std::time::Duration;
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError, TrySendError};
|
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
use std::{io, thread};
|
use tokio::net::tcp::OwnedReadHalf;
|
||||||
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use mio::net::{TcpListener, TcpStream};
|
use tokio::sync::mpsc::{channel, Receiver};
|
||||||
use mio::{Events, Interest, Poll, Registry, Token, Waker};
|
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::handler::RecvChannelHandler;
|
use crate::channel::handler::RecvChannelHandler;
|
||||||
use crate::channel::notify::{AcceptNotify, WritableNotify};
|
use crate::channel::sender::PacketSender;
|
||||||
use crate::channel::sender::{AcceptSocketSender, PacketSender};
|
use crate::channel::socket::create_tcp0;
|
||||||
use crate::channel::{RouteKey, BUFFER_SIZE};
|
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE, TCP_MAX_PACKET_SIZE};
|
||||||
use crate::util::StopManager;
|
use crate::util::StopManager;
|
||||||
|
|
||||||
const SERVER: Token = Token(0);
|
|
||||||
const NOTIFY: Token = Token(1);
|
|
||||||
|
|
||||||
/// 监听tcp端口,等待客户端连接
|
/// 监听tcp端口,等待客户端连接
|
||||||
pub fn tcp_listen<H>(
|
pub fn tcp_listen<H>(
|
||||||
tcp_server: TcpListener,
|
tcp_server: std::net::TcpListener,
|
||||||
stop_manager: StopManager,
|
receiver: Receiver<(Vec<u8>, Option<u16>, SocketAddr)>,
|
||||||
recv_handler: H,
|
recv_handler: H,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
) -> io::Result<AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>>
|
|
||||||
where
|
|
||||||
H: RecvChannelHandler,
|
|
||||||
{
|
|
||||||
let (tcp_sender, tcp_receiver) = sync_channel(64);
|
|
||||||
let poll = Poll::new()?;
|
|
||||||
let waker = AcceptNotify::new(Waker::new(poll.registry(), NOTIFY)?);
|
|
||||||
let accept = AcceptSocketSender::new(waker.clone(), tcp_sender);
|
|
||||||
let worker = {
|
|
||||||
let waker = waker.clone();
|
|
||||||
stop_manager.add_listener("tcp_listen".into(), move || {
|
|
||||||
if let Err(e) = waker.stop() {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
}
|
|
||||||
})?
|
|
||||||
};
|
|
||||||
|
|
||||||
thread::Builder::new()
|
|
||||||
.name("tcpRead".into())
|
|
||||||
.spawn(move || {
|
|
||||||
if let Err(e) = tcp_listen0(
|
|
||||||
poll,
|
|
||||||
tcp_server,
|
|
||||||
&stop_manager,
|
|
||||||
waker,
|
|
||||||
tcp_receiver,
|
|
||||||
recv_handler,
|
|
||||||
context,
|
|
||||||
) {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
}
|
|
||||||
worker.stop_all();
|
|
||||||
})?;
|
|
||||||
Ok(accept)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tcp_listen0<H>(
|
|
||||||
mut poll: Poll,
|
|
||||||
mut tcp_server: TcpListener,
|
|
||||||
stop_manager: &StopManager,
|
|
||||||
accept_notify: AcceptNotify,
|
|
||||||
accept_tcp_receiver: Receiver<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
|
||||||
mut recv_handler: H,
|
|
||||||
context: ChannelContext,
|
|
||||||
) -> io::Result<()>
|
|
||||||
where
|
|
||||||
H: RecvChannelHandler,
|
|
||||||
{
|
|
||||||
let (tcp_sender, tcp_receiver) = sync_channel(64);
|
|
||||||
let write_waker = init_writable_handler(tcp_receiver, stop_manager.clone(), context.clone())?;
|
|
||||||
poll.registry()
|
|
||||||
.register(&mut tcp_server, SERVER, Interest::READABLE)?;
|
|
||||||
let mut events = Events::with_capacity(1024);
|
|
||||||
|
|
||||||
let mut read_map: HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)> =
|
|
||||||
HashMap::with_capacity(32);
|
|
||||||
let mut extend = [0; BUFFER_SIZE];
|
|
||||||
loop {
|
|
||||||
poll.poll(&mut events, None)?;
|
|
||||||
for event in events.iter() {
|
|
||||||
match event.token() {
|
|
||||||
SERVER => loop {
|
|
||||||
match tcp_server.accept() {
|
|
||||||
Ok((stream, addr)) => {
|
|
||||||
accept_handle(
|
|
||||||
stream,
|
|
||||||
addr,
|
|
||||||
None,
|
|
||||||
&write_waker,
|
|
||||||
&mut read_map,
|
|
||||||
&tcp_sender,
|
|
||||||
poll.registry(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() == io::ErrorKind::WouldBlock {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NOTIFY => {
|
|
||||||
if accept_notify.is_stop() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if accept_notify.is_add_socket() {
|
|
||||||
while let Ok((stream, addr, init_buf)) = accept_tcp_receiver.try_recv() {
|
|
||||||
accept_handle(
|
|
||||||
stream,
|
|
||||||
addr,
|
|
||||||
init_buf,
|
|
||||||
&write_waker,
|
|
||||||
&mut read_map,
|
|
||||||
&tcp_sender,
|
|
||||||
poll.registry(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
token => {
|
|
||||||
if event.is_readable() {
|
|
||||||
if let Err(e) = readable_handle(
|
|
||||||
&token,
|
|
||||||
&mut read_map,
|
|
||||||
&mut recv_handler,
|
|
||||||
&context,
|
|
||||||
&mut extend,
|
|
||||||
) {
|
|
||||||
closed_handle_r(&token, &mut read_map);
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
if let Err(e) = write_waker.notify(token, false) {
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
closed_handle_r(&token, &mut read_map);
|
|
||||||
if let Err(e) = write_waker.notify(token, false) {
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 处理写事件
|
|
||||||
|
|
||||||
fn init_writable_handler(
|
|
||||||
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
|
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
context: ChannelContext,
|
) -> anyhow::Result<()>
|
||||||
) -> io::Result<WritableNotify> {
|
where
|
||||||
let poll = Poll::new()?;
|
H: RecvChannelHandler,
|
||||||
let writable_notify = WritableNotify::new(Waker::new(poll.registry(), NOTIFY)?);
|
{
|
||||||
let worker = {
|
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
|
||||||
let writable_notify = writable_notify.clone();
|
let worker = stop_manager.add_listener("tcpChannel".into(), move || {
|
||||||
stop_manager.add_listener("tcp_writable_handler".into(), move || {
|
let _ = stop_sender.send(());
|
||||||
if let Err(e) = writable_notify.stop() {
|
})?;
|
||||||
log::error!("{:?}", e);
|
let bind_port = tcp_server.local_addr()?.port();
|
||||||
}
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||||
})?
|
.worker_threads(2)
|
||||||
};
|
.enable_all()
|
||||||
{
|
.build()
|
||||||
let writable_notify = writable_notify.clone();
|
.context("tcp tokio runtime build failed")?;
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("tcpWriteableListen".into())
|
.name("tcpChannel".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
if let Err(e) = tcp_writable_listen(receiver, poll, writable_notify, &context) {
|
runtime.spawn(async move {
|
||||||
log::error!("{:?}", e);
|
{
|
||||||
|
let recv_handler = recv_handler.clone();
|
||||||
|
let context = context.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = tcp_accept(tcp_server, recv_handler, context).await {
|
||||||
|
log::warn!("tcp_listen {:?}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
worker.stop_all();
|
tokio::spawn(async move {
|
||||||
})?;
|
connect_tcp_handle(receiver, recv_handler, context, bind_port).await
|
||||||
}
|
});
|
||||||
|
});
|
||||||
Ok(writable_notify)
|
runtime.block_on(async {
|
||||||
|
let _ = stop_receiver.await;
|
||||||
|
});
|
||||||
|
runtime.shutdown_background();
|
||||||
|
worker.stop_all();
|
||||||
|
})
|
||||||
|
.context("tcp thread build failed")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 处理写事件
|
async fn connect_tcp_handle<H>(
|
||||||
fn tcp_writable_listen(
|
mut receiver: Receiver<(Vec<u8>, Option<u16>, SocketAddr)>,
|
||||||
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
|
recv_handler: H,
|
||||||
mut poll: Poll,
|
context: ChannelContext,
|
||||||
writable_notify: WritableNotify,
|
listener_bind_port: u16,
|
||||||
context: &ChannelContext,
|
) where
|
||||||
) -> io::Result<()> {
|
H: RecvChannelHandler,
|
||||||
let mut events = Events::with_capacity(1024);
|
{
|
||||||
let mut write_map: HashMap<
|
while let Some((data, bind_port, addr)) = receiver.recv().await {
|
||||||
Token,
|
let recv_handler = recv_handler.clone();
|
||||||
(
|
let context = context.clone();
|
||||||
TcpStream,
|
let bind_port = if let Some(bind_port) = bind_port {
|
||||||
SocketAddr,
|
bind_port
|
||||||
Receiver<Vec<u8>>,
|
} else {
|
||||||
Option<(Vec<u8>, usize)>,
|
listener_bind_port
|
||||||
),
|
};
|
||||||
> = HashMap::with_capacity(32);
|
tokio::spawn(async move {
|
||||||
loop {
|
if let Err(e) = connect_tcp0(data, addr, recv_handler, context, bind_port).await {
|
||||||
poll.poll(&mut events, None)?;
|
log::warn!("连接失败,链接终止:{:?},{:?}", addr, e);
|
||||||
for event in events.iter() {
|
}
|
||||||
match event.token() {
|
});
|
||||||
NOTIFY => {
|
}
|
||||||
if writable_notify.is_stop() {
|
}
|
||||||
//服务停止
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if writable_notify.is_need_write() {
|
|
||||||
// 需要写入数据
|
|
||||||
if let Some(tokens) = writable_notify.take_all() {
|
|
||||||
for (token, state) in tokens {
|
|
||||||
if !state {
|
|
||||||
closed_handle_w(&token, &mut write_map, &context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Err(e) = writable_handle(&token, &mut write_map) {
|
|
||||||
closed_handle_w(&token, &mut write_map, &context);
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if writable_notify.is_add_socket() {
|
|
||||||
//添加tcp连接,并监听写事件
|
|
||||||
while let Ok((mut stream, token, addr, init_buf)) = receiver.try_recv() {
|
|
||||||
if let Err(e) = stream.set_nodelay(true) {
|
|
||||||
log::warn!("set_nodelay err={:?}", e);
|
|
||||||
}
|
|
||||||
if let Err(e) =
|
|
||||||
poll.registry()
|
|
||||||
.register(&mut stream, token, Interest::WRITABLE)
|
|
||||||
{
|
|
||||||
log::warn!("registry err={:?}", e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let (sender, receiver) = sync_channel(128);
|
|
||||||
let packet_sender =
|
|
||||||
PacketSender::new(writable_notify.clone(), sender, token);
|
|
||||||
if let Some(init_buf) = init_buf {
|
|
||||||
packet_sender.try_send(&init_buf)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.tcp_map.write().insert(addr, packet_sender);
|
async fn connect_tcp0<H>(
|
||||||
write_map.insert(token, (stream, addr, receiver, None));
|
data: Vec<u8>,
|
||||||
}
|
addr: SocketAddr,
|
||||||
}
|
recv_handler: H,
|
||||||
}
|
context: ChannelContext,
|
||||||
token => {
|
bind_port: u16,
|
||||||
if event.is_writable() {
|
) -> anyhow::Result<()>
|
||||||
if let Err(e) = writable_handle(&token, &mut write_map) {
|
where
|
||||||
closed_handle_w(&token, &mut write_map, &context);
|
H: RecvChannelHandler,
|
||||||
log::warn!("{:?}", e);
|
{
|
||||||
}
|
let socket = if bind_port != 0 {
|
||||||
} else {
|
match create_tcp0(addr.is_ipv4(), bind_port, context.default_interface()) {
|
||||||
closed_handle_w(&token, &mut write_map, &context);
|
Ok(socket) => socket,
|
||||||
}
|
Err(e) => {
|
||||||
}
|
log::warn!("{:?}", e);
|
||||||
|
create_tcp0(addr.is_ipv4(), 0, context.default_interface())?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
create_tcp0(addr.is_ipv4(), 0, context.default_interface())?
|
||||||
|
};
|
||||||
|
let mut stream = tokio::time::timeout(Duration::from_secs(3), socket.connect(addr)).await??;
|
||||||
|
tcp_write(&mut stream, &data).await?;
|
||||||
|
|
||||||
|
tcp_stream_handle(stream, addr, recv_handler, context).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn tcp_accept<H>(
|
||||||
|
tcp_server: std::net::TcpListener,
|
||||||
|
recv_handler: H,
|
||||||
|
context: ChannelContext,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
H: RecvChannelHandler,
|
||||||
|
{
|
||||||
|
let tcp_server = TcpListener::from_std(tcp_server)?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (stream, addr) = tcp_server.accept().await?;
|
||||||
|
|
||||||
|
tcp_stream_handle(stream, addr, recv_handler.clone(), context.clone()).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_handle(
|
pub async fn tcp_stream_handle<H>(
|
||||||
stream: TcpStream,
|
stream: TcpStream,
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
init_buf: Option<Vec<u8>>,
|
recv_handler: H,
|
||||||
write_waker: &WritableNotify,
|
context: ChannelContext,
|
||||||
read_map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
|
) where
|
||||||
tcp_sender: &SyncSender<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
|
H: RecvChannelHandler,
|
||||||
registry: &Registry,
|
{
|
||||||
) -> io::Result<()> {
|
let _ = stream.set_nodelay(true);
|
||||||
|
let local = stream.local_addr();
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let (tcp_stream, index) = unsafe {
|
let index = stream.as_raw_socket() as usize;
|
||||||
let fd = stream.into_raw_socket();
|
#[cfg(unix)]
|
||||||
(std::net::TcpStream::from_raw_socket(fd), fd as usize)
|
let index = stream.as_raw_fd() as usize;
|
||||||
};
|
let route_key = RouteKey::new(ConnectProtocol::TCP, index, addr);
|
||||||
#[cfg(any(unix))]
|
let (r, mut w) = stream.into_split();
|
||||||
let (tcp_stream, index) = unsafe {
|
let (sender, mut receiver) = channel::<Vec<u8>>(100);
|
||||||
let fd = stream.into_raw_fd();
|
context
|
||||||
(std::net::TcpStream::from_raw_fd(fd), fd as usize)
|
.packet_map
|
||||||
};
|
.write()
|
||||||
if index == 0 || index == 1 {
|
.insert(route_key, PacketSender::new(sender));
|
||||||
log::error!("index err={:?}", addr);
|
tokio::spawn(async move {
|
||||||
return Ok(());
|
while let Some(data) = receiver.recv().await {
|
||||||
}
|
if let Err(e) = tcp_write(&mut w, &data).await {
|
||||||
let token = Token(index);
|
log::info!("发送失败,tcp链接终止:{:?},{:?}", addr, e);
|
||||||
match tcp_stream.try_clone() {
|
break;
|
||||||
Ok(tcp_writer) => {
|
|
||||||
match tcp_sender.try_send((TcpStream::from_std(tcp_writer), token, addr, init_buf)) {
|
|
||||||
Ok(_) => {
|
|
||||||
if let Err(e) = write_waker.add_socket() {
|
|
||||||
log::error!("write_waker,err={:?},addr={:?}", e, addr);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
return match e {
|
|
||||||
TrySendError::Full(_) => {
|
|
||||||
log::error!("Full,addr={:?}", addr);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
TrySendError::Disconnected(_) => {
|
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "write thread exit"))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
let _ = w.shutdown().await;
|
||||||
log::error!("try_clone err={:?},addr={:?}", e, addr);
|
});
|
||||||
return Ok(());
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = tcp_read(r, addr, &context, recv_handler, route_key).await {
|
||||||
|
log::warn!("tcp_read {:?} {local:?}-{addr}", e)
|
||||||
}
|
}
|
||||||
|
context.packet_map.write().remove(&route_key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn tcp_write<W: AsyncWrite + Unpin>(w: &mut W, buf: &[u8]) -> anyhow::Result<()> {
|
||||||
|
let len = buf.len();
|
||||||
|
if len > TCP_MAX_PACKET_SIZE {
|
||||||
|
return Err(anyhow!("超过了tcp的最大长度传输"));
|
||||||
}
|
}
|
||||||
let mut stream = TcpStream::from_std(tcp_stream);
|
w.write_all(&[0, (len >> 16) as u8, (len >> 8) as u8, len as u8])
|
||||||
if let Err(e) = registry.register(&mut stream, token, Interest::READABLE) {
|
.await?;
|
||||||
log::error!("registry err={:?},addr={:?}", e, addr);
|
w.write_all(&buf).await?;
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
read_map.insert(
|
|
||||||
token,
|
|
||||||
(
|
|
||||||
RouteKey::new(true, index, addr),
|
|
||||||
stream,
|
|
||||||
Box::new([0; BUFFER_SIZE]),
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readable_handle<H>(
|
async fn tcp_read<H>(
|
||||||
token: &Token,
|
mut read: OwnedReadHalf,
|
||||||
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
|
addr: SocketAddr,
|
||||||
recv_handler: &mut H,
|
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
extend: &mut [u8],
|
recv_handler: H,
|
||||||
) -> io::Result<()>
|
route_key: RouteKey,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
H: RecvChannelHandler,
|
H: RecvChannelHandler,
|
||||||
{
|
{
|
||||||
if let Some((route_key, stream, buf, begin)) = map.get_mut(token) {
|
let mut head = [0; 4];
|
||||||
loop {
|
let mut buf = [0; BUFFER_SIZE];
|
||||||
let end = if *begin >= 4 {
|
let mut extend = [0; BUFFER_SIZE];
|
||||||
4 + (((buf[2] as u16) << 8) | buf[3] as u16) as usize
|
loop {
|
||||||
} else {
|
read.read_exact(&mut head).await?;
|
||||||
4
|
if head[0] != 0 {
|
||||||
};
|
return Err(anyhow!("tcp数据流错误 {}", addr));
|
||||||
if end > BUFFER_SIZE {
|
|
||||||
return Err(io::Error::from(io::ErrorKind::InvalidData));
|
|
||||||
}
|
|
||||||
match stream.read(&mut buf[*begin..end]) {
|
|
||||||
Ok(len) => {
|
|
||||||
if len == 0 {
|
|
||||||
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
|
|
||||||
}
|
|
||||||
*begin += len;
|
|
||||||
if end > 4 && *begin == end {
|
|
||||||
recv_handler.handle(&mut buf[4..end], extend, *route_key, context);
|
|
||||||
*begin = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() == io::ErrorKind::WouldBlock {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
let len = ((head[1] as usize) << 16) | ((head[2] as usize) << 8) | head[3] as usize;
|
||||||
Ok(())
|
if len < 12 || len > buf.len() {
|
||||||
}
|
return Err(anyhow!("tcp数据长度无效 {}", addr));
|
||||||
|
|
||||||
fn writable_handle(
|
|
||||||
token: &Token,
|
|
||||||
map: &mut HashMap<
|
|
||||||
Token,
|
|
||||||
(
|
|
||||||
TcpStream,
|
|
||||||
SocketAddr,
|
|
||||||
Receiver<Vec<u8>>,
|
|
||||||
Option<(Vec<u8>, usize)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
if let Some((stream, _, receiver, last)) = map.get_mut(token) {
|
|
||||||
loop {
|
|
||||||
if let Some((buf, begin)) = last {
|
|
||||||
match stream.write(&buf[*begin..]) {
|
|
||||||
Ok(len) => {
|
|
||||||
if len == 0 {
|
|
||||||
return Err(io::Error::from(io::ErrorKind::WriteZero));
|
|
||||||
}
|
|
||||||
if len + *begin == buf.len() {
|
|
||||||
*last = None;
|
|
||||||
} else {
|
|
||||||
*begin += len;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() == io::ErrorKind::WouldBlock {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match receiver.try_recv() {
|
|
||||||
Ok(buf) => *last = Some((buf, 0)),
|
|
||||||
Err(e) => match e {
|
|
||||||
TryRecvError::Empty => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TryRecvError::Disconnected => {
|
|
||||||
return Err(io::Error::from(io::ErrorKind::Other));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
read.read_exact(&mut buf[..len]).await?;
|
||||||
Ok(())
|
recv_handler.handle(&mut buf[..len], &mut extend, route_key, context);
|
||||||
}
|
|
||||||
|
|
||||||
fn closed_handle_r(
|
|
||||||
token: &Token,
|
|
||||||
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
|
|
||||||
) {
|
|
||||||
if let Some((_, tcp, _, _)) = map.remove(token) {
|
|
||||||
let _ = tcp.shutdown(Shutdown::Both);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn closed_handle_w(
|
|
||||||
token: &Token,
|
|
||||||
map: &mut HashMap<
|
|
||||||
Token,
|
|
||||||
(
|
|
||||||
TcpStream,
|
|
||||||
SocketAddr,
|
|
||||||
Receiver<Vec<u8>>,
|
|
||||||
Option<(Vec<u8>, usize)>,
|
|
||||||
),
|
|
||||||
>,
|
|
||||||
context: &ChannelContext,
|
|
||||||
) {
|
|
||||||
if let Some((tcp, addr, _, _)) = map.remove(token) {
|
|
||||||
context.tcp_map.write().remove(&addr);
|
|
||||||
let _ = tcp.shutdown(Shutdown::Both);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::mpsc::{sync_channel, Receiver};
|
use std::sync::mpsc::{sync_channel, Receiver};
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
|
|
||||||
@@ -10,14 +9,14 @@ use crate::channel::context::ChannelContext;
|
|||||||
use crate::channel::handler::RecvChannelHandler;
|
use crate::channel::handler::RecvChannelHandler;
|
||||||
use crate::channel::notify::AcceptNotify;
|
use crate::channel::notify::AcceptNotify;
|
||||||
use crate::channel::sender::AcceptSocketSender;
|
use crate::channel::sender::AcceptSocketSender;
|
||||||
use crate::channel::{RouteKey, BUFFER_SIZE};
|
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
|
||||||
use crate::util::StopManager;
|
use crate::util::StopManager;
|
||||||
|
|
||||||
pub fn udp_listen<H>(
|
pub fn udp_listen<H>(
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
recv_handler: H,
|
recv_handler: H,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
) -> io::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
|
) -> anyhow::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
|
||||||
where
|
where
|
||||||
H: RecvChannelHandler,
|
H: RecvChannelHandler,
|
||||||
{
|
{
|
||||||
@@ -31,7 +30,7 @@ fn sub_udp_listen<H>(
|
|||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
recv_handler: H,
|
recv_handler: H,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
) -> io::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
|
) -> anyhow::Result<AcceptSocketSender<Option<Vec<UdpSocket>>>>
|
||||||
where
|
where
|
||||||
H: RecvChannelHandler,
|
H: RecvChannelHandler,
|
||||||
{
|
{
|
||||||
@@ -60,7 +59,7 @@ where
|
|||||||
|
|
||||||
fn sub_udp_listen0<H>(
|
fn sub_udp_listen0<H>(
|
||||||
mut poll: Poll,
|
mut poll: Poll,
|
||||||
mut recv_handler: H,
|
recv_handler: H,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
accept_notify: AcceptNotify,
|
accept_notify: AcceptNotify,
|
||||||
accept_receiver: Receiver<Option<Vec<UdpSocket>>>,
|
accept_receiver: Receiver<Option<Vec<UdpSocket>>>,
|
||||||
@@ -71,9 +70,13 @@ where
|
|||||||
let mut events = Events::with_capacity(1024);
|
let mut events = Events::with_capacity(1024);
|
||||||
let mut buf = [0; BUFFER_SIZE];
|
let mut buf = [0; BUFFER_SIZE];
|
||||||
let mut extend = [0; BUFFER_SIZE];
|
let mut extend = [0; BUFFER_SIZE];
|
||||||
let mut read_map: HashMap<Token, UdpSocket> = HashMap::with_capacity(32);
|
let mut list: Vec<UdpSocket> = Vec::with_capacity(100);
|
||||||
|
let main_len = context.main_len();
|
||||||
loop {
|
loop {
|
||||||
poll.poll(&mut events, None)?;
|
if let Err(e) = poll.poll(&mut events, None) {
|
||||||
|
crate::ignore_io_interrupted(e)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for event in events.iter() {
|
for event in events.iter() {
|
||||||
match event.token() {
|
match event.token() {
|
||||||
NOTIFY => {
|
NOTIFY => {
|
||||||
@@ -85,39 +88,43 @@ where
|
|||||||
match option {
|
match option {
|
||||||
None => {
|
None => {
|
||||||
log::info!("切换成锥形模式");
|
log::info!("切换成锥形模式");
|
||||||
for (_, mut udp_socket) in read_map.drain() {
|
for mut udp_socket in list.drain(..) {
|
||||||
if let Err(e) = udp_socket.deregister(poll.registry()) {
|
if let Err(e) = udp_socket.deregister(poll.registry()) {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(socket_list) => {
|
Some(socket_list) => {
|
||||||
|
for mut udp_socket in list.drain(..) {
|
||||||
|
if let Err(e) = udp_socket.deregister(poll.registry()) {
|
||||||
|
log::error!("deregister {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
log::info!("切换成对称模式 监听端口数:{}", socket_list.len());
|
log::info!("切换成对称模式 监听端口数:{}", socket_list.len());
|
||||||
for (index, mut udp_socket) in
|
for (index, mut udp_socket) in
|
||||||
socket_list.into_iter().enumerate()
|
socket_list.into_iter().enumerate()
|
||||||
{
|
{
|
||||||
let token = Token(index + context.channel_num());
|
|
||||||
poll.registry().register(
|
poll.registry().register(
|
||||||
&mut udp_socket,
|
&mut udp_socket,
|
||||||
token,
|
Token(index),
|
||||||
Interest::READABLE,
|
Interest::READABLE,
|
||||||
)?;
|
)?;
|
||||||
read_map.insert(token, udp_socket);
|
list.push(udp_socket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
token => {
|
Token(index) => {
|
||||||
if let Some(udp_socket) = read_map.get(&token) {
|
if let Some(udp_socket) = list.get(index) {
|
||||||
loop {
|
loop {
|
||||||
match udp_socket.recv_from(&mut buf) {
|
match udp_socket.recv_from(&mut buf) {
|
||||||
Ok((len, addr)) => {
|
Ok((len, addr)) => {
|
||||||
recv_handler.handle(
|
recv_handler.handle(
|
||||||
&mut buf[..len],
|
&mut buf[..len],
|
||||||
&mut extend,
|
&mut extend,
|
||||||
RouteKey::new(false, token.0, addr),
|
RouteKey::new(ConnectProtocol::UDP, index + main_len, addr),
|
||||||
&context,
|
&context,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -208,7 +215,7 @@ fn main_udp_listen<H>(
|
|||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
recv_handler: H,
|
recv_handler: H,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
) -> io::Result<()>
|
) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
H: RecvChannelHandler,
|
H: RecvChannelHandler,
|
||||||
{
|
{
|
||||||
@@ -235,7 +242,7 @@ where
|
|||||||
|
|
||||||
pub fn main_udp_listen0<H>(
|
pub fn main_udp_listen0<H>(
|
||||||
mut poll: Poll,
|
mut poll: Poll,
|
||||||
mut recv_handler: H,
|
recv_handler: H,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
) -> io::Result<()>
|
) -> io::Result<()>
|
||||||
where
|
where
|
||||||
@@ -256,10 +263,14 @@ where
|
|||||||
let mut events = Events::with_capacity(udps.len());
|
let mut events = Events::with_capacity(udps.len());
|
||||||
let mut extend = [0; BUFFER_SIZE];
|
let mut extend = [0; BUFFER_SIZE];
|
||||||
loop {
|
loop {
|
||||||
poll.poll(&mut events, None)?;
|
if let Err(e) = poll.poll(&mut events, None) {
|
||||||
|
crate::ignore_io_interrupted(e)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for x in events.iter() {
|
for x in events.iter() {
|
||||||
let index = match x.token() {
|
let index = match x.token() {
|
||||||
NOTIFY => return Ok(()),
|
NOTIFY => return Ok(()),
|
||||||
|
// 0的位置留给NOTIFY了,这里要再减回去,因为路由是通过index来找到对应udp的
|
||||||
Token(index) => index - 1,
|
Token(index) => index - 1,
|
||||||
};
|
};
|
||||||
let udp = if let Some(udp) = udps.get(index) {
|
let udp = if let Some(udp) = udps.get(index) {
|
||||||
@@ -274,7 +285,7 @@ where
|
|||||||
recv_handler.handle(
|
recv_handler.handle(
|
||||||
&mut buf[..len],
|
&mut buf[..len],
|
||||||
&mut extend,
|
&mut extend,
|
||||||
RouteKey::new(false, index, addr),
|
RouteKey::new(ConnectProtocol::UDP, index, addr),
|
||||||
&context,
|
&context,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
|
||||||
|
use anyhow::Context;
|
||||||
|
use futures_util::stream::SplitStream;
|
||||||
|
use futures_util::{SinkExt, StreamExt};
|
||||||
|
use std::convert::Into;
|
||||||
|
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio::sync::mpsc::{channel, Receiver};
|
||||||
|
use tokio_tungstenite::tungstenite::http::StatusCode;
|
||||||
|
use tokio_tungstenite::tungstenite::{Error, Message};
|
||||||
|
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
||||||
|
|
||||||
|
use crate::channel::context::ChannelContext;
|
||||||
|
use crate::channel::handler::RecvChannelHandler;
|
||||||
|
use crate::channel::sender::PacketSender;
|
||||||
|
use crate::util::StopManager;
|
||||||
|
|
||||||
|
/// ws协议,
|
||||||
|
/// 暂时只允许用ws连服务端,不能用ws打洞/连客户端
|
||||||
|
pub fn ws_connect_accept<H>(
|
||||||
|
receiver: Receiver<(Vec<u8>, String)>,
|
||||||
|
recv_handler: H,
|
||||||
|
context: ChannelContext,
|
||||||
|
stop_manager: StopManager,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
H: RecvChannelHandler,
|
||||||
|
{
|
||||||
|
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
|
||||||
|
let worker = stop_manager.add_listener("wsChannel".into(), move || {
|
||||||
|
let _ = stop_sender.send(());
|
||||||
|
})?;
|
||||||
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.worker_threads(2)
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.context("ws tokio runtime build failed")?;
|
||||||
|
thread::Builder::new()
|
||||||
|
.name("wsChannel".into())
|
||||||
|
.spawn(move || {
|
||||||
|
runtime.spawn(async move { connect_ws_handle(receiver, recv_handler, context).await });
|
||||||
|
runtime.block_on(async {
|
||||||
|
let _ = stop_receiver.await;
|
||||||
|
});
|
||||||
|
runtime.shutdown_background();
|
||||||
|
worker.stop_all();
|
||||||
|
})
|
||||||
|
.context("ws thread build failed")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn connect_ws_handle<H>(
|
||||||
|
mut receiver: Receiver<(Vec<u8>, String)>,
|
||||||
|
recv_handler: H,
|
||||||
|
context: ChannelContext,
|
||||||
|
) where
|
||||||
|
H: RecvChannelHandler,
|
||||||
|
{
|
||||||
|
let mut index = 0;
|
||||||
|
while let Some((data, url)) = receiver.recv().await {
|
||||||
|
let recv_handler = recv_handler.clone();
|
||||||
|
let context = context.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = connect_ws(data, url, recv_handler, context, index).await {
|
||||||
|
log::warn!("发送失败,ws链接终止:{:?}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const WS_ADDR: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0));
|
||||||
|
|
||||||
|
async fn connect_ws<H>(
|
||||||
|
data: Vec<u8>,
|
||||||
|
mut url: String,
|
||||||
|
recv_handler: H,
|
||||||
|
context: ChannelContext,
|
||||||
|
index: usize,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
H: RecvChannelHandler,
|
||||||
|
{
|
||||||
|
let mut count = 0;
|
||||||
|
log::info!("尝试建立连接 {:?}", url);
|
||||||
|
let (mut ws, response) = loop {
|
||||||
|
count += 1;
|
||||||
|
if count > 3 {
|
||||||
|
Err(anyhow::anyhow!("发生多次重定向,链接终止"))?
|
||||||
|
}
|
||||||
|
match tokio::time::timeout(Duration::from_secs(3), connect_async(url)).await? {
|
||||||
|
Ok(rs) => break rs,
|
||||||
|
Err(e) => {
|
||||||
|
if let Error::Http(res) = &e {
|
||||||
|
if res.status() == StatusCode::MOVED_PERMANENTLY
|
||||||
|
|| res.status() == StatusCode::FOUND
|
||||||
|
|| res.status() == StatusCode::SEE_OTHER
|
||||||
|
|| res.status() == StatusCode::TEMPORARY_REDIRECT
|
||||||
|
|| res.status() == StatusCode::PERMANENT_REDIRECT
|
||||||
|
{
|
||||||
|
if let Some(v) = res.headers().get("Location") {
|
||||||
|
if let Ok(redirect) = v.to_str() {
|
||||||
|
log::info!("url重定向响应头 {:?}", res.headers());
|
||||||
|
log::info!("url重定向地址 {}", redirect);
|
||||||
|
// 替换协议前缀
|
||||||
|
if redirect.starts_with("http://") {
|
||||||
|
url = redirect.replacen("http://", "ws://", 1);
|
||||||
|
} else if redirect.starts_with("https://") {
|
||||||
|
url = redirect.replacen("https://", "wss://", 1);
|
||||||
|
} else {
|
||||||
|
url = redirect.to_string();
|
||||||
|
}
|
||||||
|
println!("Location:{}", url);
|
||||||
|
log::info!("修改后的重定向地址: {}", url);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
log::info!("ws协议握手 {:?}", response);
|
||||||
|
ws.send(Message::Binary(data)).await?;
|
||||||
|
let (mut ws_write, ws_read) = ws.split();
|
||||||
|
let (sender, mut receiver) = channel::<Vec<u8>>(100);
|
||||||
|
let route_key = RouteKey::new(ConnectProtocol::WS, index, WS_ADDR);
|
||||||
|
|
||||||
|
context
|
||||||
|
.packet_map
|
||||||
|
.write()
|
||||||
|
.insert(route_key, PacketSender::new(sender));
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Some(data) = receiver.recv().await {
|
||||||
|
if let Err(e) = ws_write.send(Message::Binary(data)).await {
|
||||||
|
log::warn!("websocket err {:?}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = ws_write.close().await;
|
||||||
|
});
|
||||||
|
if let Err(e) = ws_read_handle(ws_read, recv_handler, &context, route_key).await {
|
||||||
|
log::warn!("{:?}", e);
|
||||||
|
}
|
||||||
|
context.packet_map.write().remove(&route_key);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
async fn ws_read_handle<H>(
|
||||||
|
mut ws_read: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||||
|
recv_handler: H,
|
||||||
|
context: &ChannelContext,
|
||||||
|
route_key: RouteKey,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
H: RecvChannelHandler,
|
||||||
|
{
|
||||||
|
let mut extend = [0; BUFFER_SIZE];
|
||||||
|
while let Some(msg) = ws_read.next().await {
|
||||||
|
let msg = msg.context("Error during WebSocket ")?;
|
||||||
|
match msg {
|
||||||
|
Message::Text(txt) => log::info!("Received text message: {}", txt),
|
||||||
|
Message::Binary(mut data) => {
|
||||||
|
recv_handler.handle(&mut data, &mut extend, route_key, context);
|
||||||
|
}
|
||||||
|
Message::Ping(_) | Message::Pong(_) => (),
|
||||||
|
Message::Close(_) => break,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod rs_aes_cbc;
|
||||||
|
pub use rs_aes_cbc::*;
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::io;
|
|
||||||
|
|
||||||
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyIvInit};
|
||||||
|
use anyhow::anyhow;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
|
||||||
use crate::cipher::Finger;
|
use crate::cipher::Finger;
|
||||||
@@ -50,22 +49,17 @@ impl AesCbcCipher {
|
|||||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if !net_packet.is_encrypt() {
|
if !net_packet.is_encrypt() {
|
||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(anyhow!("not encrypt"));
|
||||||
}
|
}
|
||||||
if net_packet.payload().len() < 16 {
|
if net_packet.payload().len() < 16 {
|
||||||
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("aes_cbc data err"));
|
||||||
}
|
}
|
||||||
let mut iv = [0; 16];
|
let mut iv = [0; 16];
|
||||||
iv[0..4].copy_from_slice(&net_packet.source().octets());
|
iv[0..12].copy_from_slice(&net_packet.head_tag());
|
||||||
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();
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
iv[12..16].copy_from_slice(&finger.hash[0..4]);
|
iv[12..16].copy_from_slice(&finger.hash[0..4]);
|
||||||
}
|
}
|
||||||
@@ -75,7 +69,7 @@ impl AesCbcCipher {
|
|||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let finger = finger.calculate_finger(&iv[..12], secret_body.en_body());
|
let finger = finger.calculate_finger(&iv[..12], secret_body.en_body());
|
||||||
if &finger != secret_body.finger() {
|
if &finger != secret_body.finger() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
return Err(anyhow!("aes_cbc finger err"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let rs = match &self.cipher {
|
let rs = match &self.cipher {
|
||||||
@@ -92,10 +86,7 @@ impl AesCbcCipher {
|
|||||||
net_packet.set_data_len(HEAD_LEN + len - 4)?;
|
net_packet.set_data_len(HEAD_LEN + len - 4)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("aes_cbc 解密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("解密失败:{}", e),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// net_packet 必须预留足够长度
|
/// net_packet 必须预留足够长度
|
||||||
@@ -103,15 +94,10 @@ impl AesCbcCipher {
|
|||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let data_len = net_packet.data_len();
|
let data_len = net_packet.data_len();
|
||||||
let mut iv = [0; 16];
|
let mut iv = [0; 16];
|
||||||
iv[0..4].copy_from_slice(&net_packet.source().octets());
|
iv[0..12].copy_from_slice(&net_packet.head_tag());
|
||||||
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();
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
iv[12..16].copy_from_slice(&finger.hash[0..4]);
|
iv[12..16].copy_from_slice(&finger.hash[0..4]);
|
||||||
net_packet.set_data_len(data_len + 16)?;
|
net_packet.set_data_len(data_len + 16)?;
|
||||||
@@ -146,10 +132,22 @@ impl AesCbcCipher {
|
|||||||
net_packet.set_encrypt_flag(true);
|
net_packet.set_encrypt_flag(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("aes_cbc 加密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("加密失败:{}", e),
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_aes_cbc() {
|
||||||
|
let d = AesCbcCipher::new_128([0; 16], Some(Finger::new("123")));
|
||||||
|
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
let d = AesCbcCipher::new_128([0; 16], None);
|
||||||
|
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
||||||
|
mod rs_aes_ecb;
|
||||||
|
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
||||||
|
pub use rs_aes_ecb::*;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
||||||
|
mod openssl_aes_ecb;
|
||||||
|
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
||||||
|
pub use openssl_aes_ecb::*;
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
use crate::cipher::Finger;
|
use std::ptr;
|
||||||
use crate::protocol::{NetPacket, HEAD_LEN};
|
|
||||||
|
use anyhow::anyhow;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use openssl_sys::EVP_CIPHER_CTX;
|
use openssl_sys::EVP_CIPHER_CTX;
|
||||||
use std::{io, ptr};
|
|
||||||
|
use crate::cipher::Finger;
|
||||||
|
use crate::protocol::{NetPacket, HEAD_LEN};
|
||||||
|
|
||||||
pub struct AesEcbCipher {
|
pub struct AesEcbCipher {
|
||||||
key: Vec<u8>,
|
key: Vec<u8>,
|
||||||
@@ -100,34 +103,28 @@ impl AesEcbCipher {
|
|||||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if !net_packet.is_encrypt() {
|
if !net_packet.is_encrypt() {
|
||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(anyhow!("not encrypt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 len = net_packet.payload().len();
|
let len = net_packet.payload().len();
|
||||||
if len < 12 {
|
if len < 12 {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data len err"));
|
return Err(anyhow!("data len err"));
|
||||||
}
|
}
|
||||||
let secret_body = &net_packet.payload()[..len - 12];
|
let secret_body = &net_packet.payload()[..len - 12];
|
||||||
let finger = finger.calculate_finger(&nonce_raw, secret_body);
|
let finger = finger.calculate_finger(&nonce_raw, secret_body);
|
||||||
if &finger != &net_packet.payload()[len - 12..] {
|
if &finger != &net_packet.payload()[len - 12..] {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
return Err(anyhow!("finger err"));
|
||||||
}
|
}
|
||||||
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
||||||
}
|
}
|
||||||
if net_packet.payload().len() < 16 {
|
if net_packet.payload().len() < 16 {
|
||||||
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
let input = net_packet.payload();
|
let input = net_packet.payload();
|
||||||
let mut out = [0u8; 1024 * 5];
|
let mut out = [0u8; 1024 * 5];
|
||||||
@@ -147,22 +144,22 @@ impl AesEcbCipher {
|
|||||||
//校验头部
|
//校验头部
|
||||||
let src_net_packet = NetPacket::new(text)?;
|
let src_net_packet = NetPacket::new(text)?;
|
||||||
if src_net_packet.source() != net_packet.source() {
|
if src_net_packet.source() != net_packet.source() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.destination() != net_packet.destination() {
|
if src_net_packet.destination() != net_packet.destination() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.protocol() != net_packet.protocol() {
|
if src_net_packet.protocol() != net_packet.protocol() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
|
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.is_gateway() != net_packet.is_gateway() {
|
if src_net_packet.is_gateway() != net_packet.is_gateway() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.source_ttl() != net_packet.source_ttl() {
|
if src_net_packet.source_ttl() != net_packet.source_ttl() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
net_packet.set_encrypt_flag(false);
|
net_packet.set_encrypt_flag(false);
|
||||||
@@ -175,7 +172,7 @@ impl AesEcbCipher {
|
|||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let input = net_packet.buffer();
|
let input = net_packet.buffer();
|
||||||
let mut out = [0u8; 1024 * 5];
|
let mut out = [0u8; 1024 * 5];
|
||||||
let mut out_len = 0;
|
let mut out_len = 0;
|
||||||
@@ -191,7 +188,7 @@ impl AesEcbCipher {
|
|||||||
}
|
}
|
||||||
let out_len = out_len as usize;
|
let out_len = out_len as usize;
|
||||||
if out_len == 0 {
|
if out_len == 0 {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "ciphertext len err"));
|
return Err(anyhow!("ciphertext len err"));
|
||||||
}
|
}
|
||||||
//密文
|
//密文
|
||||||
let ciphertext = &out[..out_len];
|
let ciphertext = &out[..out_len];
|
||||||
@@ -199,13 +196,7 @@ impl AesEcbCipher {
|
|||||||
net_packet.payload_mut().copy_from_slice(ciphertext);
|
net_packet.payload_mut().copy_from_slice(ciphertext);
|
||||||
net_packet.set_encrypt_flag(true);
|
net_packet.set_encrypt_flag(true);
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 finger = finger.calculate_finger(&nonce_raw, ciphertext);
|
let finger = finger.calculate_finger(&nonce_raw, ciphertext);
|
||||||
let src_data_len = net_packet.data_len();
|
let src_data_len = net_packet.data_len();
|
||||||
//设置实际长度
|
//设置实际长度
|
||||||
@@ -221,6 +212,8 @@ impl AesEcbCipher {
|
|||||||
fn test_openssl_aes_ecb() {
|
fn test_openssl_aes_ecb() {
|
||||||
let d = AesEcbCipher::new_128([0; 16], Some(Finger::new("123")));
|
let d = AesEcbCipher::new_128([0; 16], Some(Finger::new("123")));
|
||||||
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
|
let mut p = NetPacket::new_encrypt([0; 100]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
d.encrypt_ipv4(&mut p).unwrap();
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
d.decrypt_ipv4(&mut p).unwrap();
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyInit};
|
||||||
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use crate::cipher::Finger;
|
use crate::cipher::Finger;
|
||||||
use crate::protocol::{NetPacket, HEAD_LEN};
|
use crate::protocol::{NetPacket, HEAD_LEN};
|
||||||
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, BlockEncryptMut, KeyInit};
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
type Aes128EcbEnc = ecb::Encryptor<aes::Aes128>;
|
type Aes128EcbEnc = ecb::Encryptor<aes::Aes128>;
|
||||||
type Aes128EcbDec = ecb::Decryptor<aes::Aes128>;
|
type Aes128EcbDec = ecb::Decryptor<aes::Aes128>;
|
||||||
@@ -46,34 +47,28 @@ impl AesEcbCipher {
|
|||||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if !net_packet.is_encrypt() {
|
if !net_packet.is_encrypt() {
|
||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(anyhow!("not encrypt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 len = net_packet.payload().len();
|
let len = net_packet.payload().len();
|
||||||
if len < 12 {
|
if len < 12 {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "payload len <12"));
|
return Err(anyhow!("payload len <12"));
|
||||||
}
|
}
|
||||||
let secret_body = &net_packet.payload()[..len - 12];
|
let secret_body = &net_packet.payload()[..len - 12];
|
||||||
let finger = finger.calculate_finger(&nonce_raw, secret_body);
|
let finger = finger.calculate_finger(&nonce_raw, secret_body);
|
||||||
if &finger != &net_packet.payload()[len - 12..] {
|
if &finger != &net_packet.payload()[len - 12..] {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
return Err(anyhow!("finger err"));
|
||||||
}
|
}
|
||||||
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
||||||
}
|
}
|
||||||
if net_packet.payload().len() < 16 {
|
if net_packet.payload().len() < 16 {
|
||||||
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
log::error!("数据异常,长度{}小于{}", net_packet.payload().len(), 16);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
let mut out = [0u8; 1024 * 5];
|
let mut out = [0u8; 1024 * 5];
|
||||||
let rs = match self.key {
|
let rs = match self.key {
|
||||||
@@ -87,32 +82,29 @@ impl AesEcbCipher {
|
|||||||
//校验头部
|
//校验头部
|
||||||
let src_net_packet = NetPacket::new(buf)?;
|
let src_net_packet = NetPacket::new(buf)?;
|
||||||
if src_net_packet.source() != net_packet.source() {
|
if src_net_packet.source() != net_packet.source() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.destination() != net_packet.destination() {
|
if src_net_packet.destination() != net_packet.destination() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.protocol() != net_packet.protocol() {
|
if src_net_packet.protocol() != net_packet.protocol() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
|
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.is_gateway() != net_packet.is_gateway() {
|
if src_net_packet.is_gateway() != net_packet.is_gateway() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.source_ttl() != net_packet.source_ttl() {
|
if src_net_packet.source_ttl() != net_packet.source_ttl() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
net_packet.set_data_len(buf.len())?;
|
net_packet.set_data_len(buf.len())?;
|
||||||
net_packet.set_payload(src_net_packet.payload())?;
|
net_packet.set_payload(src_net_packet.payload())?;
|
||||||
net_packet.set_encrypt_flag(false);
|
net_packet.set_encrypt_flag(false);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("aes_ecb解密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("aes_ecb解密失败:{}", e),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// net_packet 必须预留足够长度
|
/// net_packet 必须预留足够长度
|
||||||
@@ -120,7 +112,7 @@ impl AesEcbCipher {
|
|||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut out = [0u8; 1024 * 5];
|
let mut out = [0u8; 1024 * 5];
|
||||||
let rs = match self.key {
|
let rs = match self.key {
|
||||||
AesEcbEnum::AES128ECB(key) => Aes128EcbEnc::new(&key.into())
|
AesEcbEnum::AES128ECB(key) => Aes128EcbEnc::new(&key.into())
|
||||||
@@ -136,13 +128,7 @@ impl AesEcbCipher {
|
|||||||
net_packet.set_encrypt_flag(true);
|
net_packet.set_encrypt_flag(true);
|
||||||
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 finger = finger.calculate_finger(&nonce_raw, buf);
|
let finger = finger.calculate_finger(&nonce_raw, buf);
|
||||||
let src_data_len = net_packet.data_len();
|
let src_data_len = net_packet.data_len();
|
||||||
//设置实际长度
|
//设置实际长度
|
||||||
@@ -152,10 +138,7 @@ impl AesEcbCipher {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("aes_ecb加密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("aes_ecb加密失败:{}", e),
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
use std::io;
|
|
||||||
|
|
||||||
use aes_gcm::aead::consts::{U12, U16};
|
use aes_gcm::aead::consts::{U12, U16};
|
||||||
use aes_gcm::aead::generic_array::GenericArray;
|
use aes_gcm::aead::generic_array::GenericArray;
|
||||||
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit, Nonce, Tag};
|
use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit, Nonce, Tag};
|
||||||
|
use anyhow::anyhow;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
|
||||||
use crate::cipher::finger::Finger;
|
use crate::cipher::finger::Finger;
|
||||||
@@ -39,22 +38,16 @@ impl AesGcmCipher {
|
|||||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if !net_packet.is_encrypt() {
|
if !net_packet.is_encrypt() {
|
||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(anyhow!("not encrypt"));
|
||||||
}
|
}
|
||||||
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
|
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
|
||||||
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
|
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
|
||||||
|
|
||||||
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
@@ -62,7 +55,7 @@ impl AesGcmCipher {
|
|||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
||||||
if &finger != secret_body.finger() {
|
if &finger != secret_body.finger() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
return Err(anyhow!("finger err"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(tag);
|
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(tag);
|
||||||
@@ -75,10 +68,7 @@ impl AesGcmCipher {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(e) = rs {
|
if let Err(e) = rs {
|
||||||
return Err(io::Error::new(
|
return Err(anyhow!("解密失败:{}", e));
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("解密失败:{}", e),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
net_packet.set_encrypt_flag(false);
|
net_packet.set_encrypt_flag(false);
|
||||||
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
|
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
|
||||||
@@ -89,17 +79,11 @@ impl AesGcmCipher {
|
|||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if net_packet.reserve() < AES_GCM_ENCRYPTION_RESERVED {
|
if net_packet.reserve() < AES_GCM_ENCRYPTION_RESERVED {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "too short"));
|
return Err(anyhow!("too short"));
|
||||||
}
|
}
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 nonce: &GenericArray<u8, U12> = Nonce::from_slice(&nonce_raw);
|
||||||
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
|
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
|
||||||
net_packet.set_data_len(data_len)?;
|
net_packet.set_data_len(data_len)?;
|
||||||
@@ -123,10 +107,26 @@ impl AesGcmCipher {
|
|||||||
net_packet.set_encrypt_flag(true);
|
net_packet.set_encrypt_flag(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("加密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("加密失败:{}", e),
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_aes_gcm() {
|
||||||
|
let d = AesGcmCipher::new_256([0; 32], Some(Finger::new("123")));
|
||||||
|
let mut p =
|
||||||
|
NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
|
||||||
|
let d = AesGcmCipher::new_256([0; 32], None);
|
||||||
|
let mut p =
|
||||||
|
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#[cfg(feature = "ring-cipher")]
|
||||||
|
mod ring_aes_gcm_cipher;
|
||||||
|
#[cfg(feature = "ring-cipher")]
|
||||||
|
pub use ring_aes_gcm_cipher::*;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "ring-cipher"))]
|
||||||
|
mod aes_gcm_cipher;
|
||||||
|
#[cfg(not(feature = "ring-cipher"))]
|
||||||
|
pub use aes_gcm_cipher::*;
|
||||||
+31
-33
@@ -1,9 +1,9 @@
|
|||||||
use crate::cipher::Finger;
|
use anyhow::anyhow;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use ring::aead;
|
use ring::aead;
|
||||||
use ring::aead::{LessSafeKey, UnboundKey};
|
use ring::aead::{LessSafeKey, UnboundKey};
|
||||||
use std::io;
|
|
||||||
|
|
||||||
|
use crate::cipher::Finger;
|
||||||
use crate::protocol::body::{SecretBody, AES_GCM_ENCRYPTION_RESERVED};
|
use crate::protocol::body::{SecretBody, AES_GCM_ENCRYPTION_RESERVED};
|
||||||
use crate::protocol::NetPacket;
|
use crate::protocol::NetPacket;
|
||||||
|
|
||||||
@@ -53,28 +53,22 @@ impl AesGcmCipher {
|
|||||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if !net_packet.is_encrypt() {
|
if !net_packet.is_encrypt() {
|
||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(anyhow!("not encrypt"));
|
||||||
}
|
}
|
||||||
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
|
if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED {
|
||||||
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
|
log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 nonce = aead::Nonce::assume_unique_for_key(nonce_raw);
|
||||||
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body());
|
||||||
if &finger != secret_body.finger() {
|
if &finger != secret_body.finger() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "ring aes finger err"));
|
return Err(anyhow!("ring aes finger err"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,10 +81,7 @@ impl AesGcmCipher {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(e) = rs {
|
if let Err(e) = rs {
|
||||||
return Err(io::Error::new(
|
return Err(anyhow!("解密失败:{}", e));
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("解密失败:{}", e),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
net_packet.set_encrypt_flag(false);
|
net_packet.set_encrypt_flag(false);
|
||||||
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
|
net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?;
|
||||||
@@ -102,14 +93,8 @@ impl AesGcmCipher {
|
|||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 nonce = aead::Nonce::assume_unique_for_key(nonce_raw);
|
||||||
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
|
let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED;
|
||||||
net_packet.set_data_len(data_len)?;
|
net_packet.set_data_len(data_len)?;
|
||||||
@@ -128,10 +113,7 @@ impl AesGcmCipher {
|
|||||||
Ok(tag) => {
|
Ok(tag) => {
|
||||||
let tag = tag.as_ref();
|
let tag = tag.as_ref();
|
||||||
if tag.len() != 16 {
|
if tag.len() != 16 {
|
||||||
return Err(io::Error::new(
|
return Err(anyhow!("加密tag长度错误:{}", tag.len()));
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("加密tag长度错误:{}", tag.len()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
secret_body.set_tag(tag)?;
|
secret_body.set_tag(tag)?;
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
@@ -141,10 +123,26 @@ impl AesGcmCipher {
|
|||||||
net_packet.set_encrypt_flag(true);
|
net_packet.set_encrypt_flag(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("加密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("加密失败:{}", e),
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_aes_gcm() {
|
||||||
|
let d = AesGcmCipher::new_256([0; 32], Some(Finger::new("123")));
|
||||||
|
let mut p =
|
||||||
|
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
|
||||||
|
let d = AesGcmCipher::new_256([0; 32], None);
|
||||||
|
let mut p =
|
||||||
|
NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod rs_chacha20;
|
||||||
|
pub use rs_chacha20::*;
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
use aes::cipher::Iv;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use chacha20::cipher::{Key, KeyIvInit, StreamCipher};
|
||||||
|
use chacha20::ChaCha20;
|
||||||
|
|
||||||
|
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
|
||||||
|
use crate::cipher::Finger;
|
||||||
|
use crate::protocol::body::{
|
||||||
|
IVSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED,
|
||||||
|
};
|
||||||
|
use crate::protocol::NetPacket;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ChaCha20Cipher {
|
||||||
|
key: [u8; 32],
|
||||||
|
pub(crate) finger: Option<Finger>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Cipher {
|
||||||
|
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
|
||||||
|
Self { key, finger }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Cipher {
|
||||||
|
pub fn key(&self) -> &[u8] {
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Cipher {
|
||||||
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if !net_packet.is_encrypt() {
|
||||||
|
//未加密的数据直接丢弃
|
||||||
|
return Err(anyhow!("not encrypt"));
|
||||||
|
}
|
||||||
|
let mut head_tag = net_packet.head_tag();
|
||||||
|
|
||||||
|
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let finger = finger.calculate_finger(&head_tag, secret_body.data());
|
||||||
|
if &finger != secret_body.finger() {
|
||||||
|
return Err(anyhow!("ChaCha20 finger err"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gen_nonce(&mut head_tag, secret_body.random_buf());
|
||||||
|
ChaCha20::new(
|
||||||
|
Key::<ChaCha20>::from_slice(&self.key),
|
||||||
|
Iv::<ChaCha20>::from_slice(&head_tag),
|
||||||
|
)
|
||||||
|
.apply_keystream(secret_body.data_mut());
|
||||||
|
let len = secret_body.data().len();
|
||||||
|
net_packet.set_encrypt_flag(false);
|
||||||
|
net_packet.set_payload_len(len)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let data_len = net_packet.data_len();
|
||||||
|
let head_tag = net_packet.head_tag();
|
||||||
|
if let Some(_) = &self.finger {
|
||||||
|
net_packet.set_data_len(data_len + RANDOM_RESERVED + FINGER_RESERVED)?;
|
||||||
|
} else {
|
||||||
|
net_packet.set_data_len(data_len + RANDOM_RESERVED)?;
|
||||||
|
}
|
||||||
|
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
|
let mut nonce = head_tag;
|
||||||
|
secret_body.set_random(&gen_random_nonce(&mut nonce));
|
||||||
|
|
||||||
|
ChaCha20::new(
|
||||||
|
Key::<ChaCha20>::from_slice(&self.key),
|
||||||
|
Iv::<ChaCha20>::from_slice(&nonce),
|
||||||
|
)
|
||||||
|
.apply_keystream(secret_body.data_mut());
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let finger = finger.calculate_finger(&head_tag, secret_body.data());
|
||||||
|
let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), true)?;
|
||||||
|
secret_body.set_finger(&finger)?;
|
||||||
|
}
|
||||||
|
net_packet.set_encrypt_flag(true);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_chacha20() {
|
||||||
|
let d = ChaCha20Cipher::new_256([0; 32], Some(Finger::new("123")));
|
||||||
|
let mut p =
|
||||||
|
NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
|
||||||
|
let d = ChaCha20Cipher::new_256([0; 32], None);
|
||||||
|
let mut p =
|
||||||
|
NetPacket::new_encrypt([2; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#[cfg(feature = "ring-cipher")]
|
||||||
|
mod ring_chacha20_poly1305;
|
||||||
|
#[cfg(feature = "ring-cipher")]
|
||||||
|
pub use ring_chacha20_poly1305::*;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "ring-cipher"))]
|
||||||
|
mod rs_chacha20_poly1305;
|
||||||
|
#[cfg(not(feature = "ring-cipher"))]
|
||||||
|
pub use rs_chacha20_poly1305::*;
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
|
||||||
|
use ring::aead;
|
||||||
|
use ring::aead::{LessSafeKey, UnboundKey};
|
||||||
|
|
||||||
|
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
|
||||||
|
use crate::cipher::Finger;
|
||||||
|
use crate::protocol::body::{
|
||||||
|
AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED,
|
||||||
|
};
|
||||||
|
use crate::protocol::NetPacket;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ChaCha20Poly1305Cipher {
|
||||||
|
key: Vec<u8>,
|
||||||
|
pub(crate) cipher: LessSafeKey,
|
||||||
|
pub(crate) finger: Option<Finger>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Poly1305Cipher {
|
||||||
|
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
|
||||||
|
let cipher = LessSafeKey::new(UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap());
|
||||||
|
Self {
|
||||||
|
key: key.to_vec(),
|
||||||
|
cipher,
|
||||||
|
finger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Poly1305Cipher {
|
||||||
|
pub fn key(&self) -> &[u8] {
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Poly1305Cipher {
|
||||||
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if !net_packet.is_encrypt() {
|
||||||
|
//未加密的数据直接丢弃
|
||||||
|
return Err(anyhow!("not encrypt"));
|
||||||
|
}
|
||||||
|
if net_packet.payload().len() < TAG_RESERVED {
|
||||||
|
log::error!("数据异常,长度小于{}", TAG_RESERVED);
|
||||||
|
return Err(anyhow!("data err"));
|
||||||
|
}
|
||||||
|
let mut head_tag = net_packet.head_tag();
|
||||||
|
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
|
||||||
|
if &finger != secret_body.finger() {
|
||||||
|
return Err(anyhow!("ring CHACHA20_POLY1305 finger err"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gen_nonce(&mut head_tag, secret_body.random_buf());
|
||||||
|
let nonce = aead::Nonce::assume_unique_for_key(head_tag);
|
||||||
|
let rs = self
|
||||||
|
.cipher
|
||||||
|
.open_in_place(nonce, aead::Aad::empty(), secret_body.data_tag_mut());
|
||||||
|
if let Err(e) = rs {
|
||||||
|
return Err(anyhow!("ring CHACHA20_POLY1305 解密失败:{}", e));
|
||||||
|
}
|
||||||
|
let len = secret_body.data().len();
|
||||||
|
net_packet.set_encrypt_flag(false);
|
||||||
|
net_packet.set_payload_len(len)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
/// net_packet 必须预留足够长度
|
||||||
|
/// data_len是有效载荷的长度
|
||||||
|
/// 返回加密后载荷的长度
|
||||||
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let head_tag = net_packet.head_tag();
|
||||||
|
let data_len = net_packet.data_len();
|
||||||
|
if self.finger.is_some() {
|
||||||
|
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?;
|
||||||
|
} else {
|
||||||
|
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?;
|
||||||
|
}
|
||||||
|
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
|
let mut nonce = head_tag;
|
||||||
|
secret_body.set_random(&gen_random_nonce(&mut nonce));
|
||||||
|
let nonce = aead::Nonce::assume_unique_for_key(nonce);
|
||||||
|
let rs = self.cipher.seal_in_place_separate_tag(
|
||||||
|
nonce,
|
||||||
|
aead::Aad::empty(),
|
||||||
|
secret_body.data_mut(),
|
||||||
|
);
|
||||||
|
match rs {
|
||||||
|
Ok(tag) => {
|
||||||
|
let tag = tag.as_ref();
|
||||||
|
if tag.len() != 16 {
|
||||||
|
return Err(anyhow!("加密tag长度错误:{}", tag.len()));
|
||||||
|
}
|
||||||
|
secret_body.set_tag(tag)?;
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
|
||||||
|
secret_body.set_finger(&finger)?;
|
||||||
|
}
|
||||||
|
net_packet.set_encrypt_flag(true);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(anyhow!("ring CHACHA20_POLY1305 加密失败:{}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ring_chacha20_poly1305() {
|
||||||
|
let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123")));
|
||||||
|
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
let d = ChaCha20Poly1305Cipher::new_256([0; 32], None);
|
||||||
|
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
use crate::cipher::finger::{gen_nonce, gen_random_nonce};
|
||||||
|
use crate::cipher::Finger;
|
||||||
|
use crate::protocol::body::{
|
||||||
|
AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED,
|
||||||
|
};
|
||||||
|
use crate::protocol::NetPacket;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use chacha20poly1305::aead::{Nonce, Tag};
|
||||||
|
use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ChaCha20Poly1305Cipher {
|
||||||
|
key: Vec<u8>,
|
||||||
|
pub(crate) cipher: ChaCha20Poly1305,
|
||||||
|
pub(crate) finger: Option<Finger>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Poly1305Cipher {
|
||||||
|
pub fn new_256(key: [u8; 32], finger: Option<Finger>) -> Self {
|
||||||
|
let key: &Key = &key.into();
|
||||||
|
let cipher = ChaCha20Poly1305::new(key);
|
||||||
|
Self {
|
||||||
|
key: key.to_vec(),
|
||||||
|
cipher,
|
||||||
|
finger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Poly1305Cipher {
|
||||||
|
pub fn key(&self) -> &[u8] {
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaCha20Poly1305Cipher {
|
||||||
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if !net_packet.is_encrypt() {
|
||||||
|
//未加密的数据直接丢弃
|
||||||
|
return Err(anyhow!("not encrypt"));
|
||||||
|
}
|
||||||
|
if net_packet.payload().len() < TAG_RESERVED {
|
||||||
|
log::error!("数据异常,长度小于{}", TAG_RESERVED);
|
||||||
|
return Err(anyhow!("data err"));
|
||||||
|
}
|
||||||
|
let mut head_tag = net_packet.head_tag();
|
||||||
|
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
|
||||||
|
if &finger != secret_body.finger() {
|
||||||
|
return Err(anyhow!("rs CHACHA20_POLY1305 finger err"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gen_nonce(&mut head_tag, secret_body.random_buf());
|
||||||
|
let nonce: Nonce<ChaCha20Poly1305> = head_tag.into();
|
||||||
|
let tag: Tag<ChaCha20Poly1305> =
|
||||||
|
Tag::<ChaCha20Poly1305>::from_slice(secret_body.tag()).clone();
|
||||||
|
if let Err(e) =
|
||||||
|
self.cipher
|
||||||
|
.decrypt_in_place_detached(&nonce, &[], secret_body.data_mut(), &tag)
|
||||||
|
{
|
||||||
|
return Err(anyhow!("rs CHACHA20_POLY1305 decrypt_ipv4 {:?}", e));
|
||||||
|
}
|
||||||
|
let len = secret_body.data().len();
|
||||||
|
net_packet.set_encrypt_flag(false);
|
||||||
|
net_packet.set_payload_len(len)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// net_packet 必须预留足够长度
|
||||||
|
/// data_len是有效载荷的长度
|
||||||
|
/// 返回加密后载荷的长度
|
||||||
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let head_tag = net_packet.head_tag();
|
||||||
|
let data_len = net_packet.data_len();
|
||||||
|
if self.finger.is_some() {
|
||||||
|
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?;
|
||||||
|
} else {
|
||||||
|
net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?;
|
||||||
|
}
|
||||||
|
let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?;
|
||||||
|
let mut nonce = head_tag;
|
||||||
|
secret_body.set_random(&gen_random_nonce(&mut nonce));
|
||||||
|
let nonce = nonce.into();
|
||||||
|
let rs = self
|
||||||
|
.cipher
|
||||||
|
.encrypt_in_place_detached(&nonce, &[], secret_body.data_mut());
|
||||||
|
match rs {
|
||||||
|
Ok(tag) => {
|
||||||
|
let tag: &[u8] = tag.as_ref();
|
||||||
|
if tag.len() != 16 {
|
||||||
|
return Err(anyhow!("加密tag长度错误:{}", tag.len(),));
|
||||||
|
}
|
||||||
|
secret_body.set_tag(tag)?;
|
||||||
|
if let Some(finger) = &self.finger {
|
||||||
|
let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut());
|
||||||
|
secret_body.set_finger(&finger)?;
|
||||||
|
}
|
||||||
|
net_packet.set_encrypt_flag(true);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(anyhow!("rs CHACHA20_POLY1305 加密失败:{}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rs_chacha20_poly1305() {
|
||||||
|
let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123")));
|
||||||
|
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
let d = ChaCha20Poly1305Cipher::new_256([0; 32], None);
|
||||||
|
let mut p = NetPacket::new_encrypt([0; 73]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src);
|
||||||
|
}
|
||||||
+122
-142
@@ -1,51 +1,42 @@
|
|||||||
#[cfg(feature = "aes_ecb")]
|
|
||||||
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
|
||||||
use crate::cipher::aes_ecb::AesEcbCipher;
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
#[cfg(cipher)]
|
||||||
|
use sha2::Digest;
|
||||||
|
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
use crate::cipher::aes_cbc::AesCbcCipher;
|
use crate::cipher::aes_cbc::AesCbcCipher;
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
|
||||||
#[cfg(not(feature = "ring-cipher"))]
|
|
||||||
use crate::cipher::aes_gcm_cipher::AesGcmCipher;
|
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
use crate::cipher::aes_ecb::AesEcbCipher;
|
||||||
use crate::cipher::openssl_aes_ecb::AesEcbCipher;
|
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
#[cfg(feature = "ring-cipher")]
|
use crate::cipher::aes_gcm::AesGcmCipher;
|
||||||
use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher;
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
use crate::cipher::chacha20::ChaCha20Cipher;
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
use crate::cipher::chacha20_poly1305::ChaCha20Poly1305Cipher;
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
use crate::cipher::sm4_cbc::Sm4CbcCipher;
|
use crate::cipher::sm4_cbc::Sm4CbcCipher;
|
||||||
#[cfg(any(
|
use crate::cipher::xor::XORCipher;
|
||||||
feature = "aes_gcm",
|
#[cfg(cipher)]
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
use crate::cipher::Finger;
|
use crate::cipher::Finger;
|
||||||
use crate::protocol::NetPacket;
|
use crate::protocol::NetPacket;
|
||||||
#[cfg(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
use sha2::Digest;
|
|
||||||
use std::io;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum CipherModel {
|
pub enum CipherModel {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
AesGcm,
|
AesGcm,
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Chacha20Poly1305,
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Chacha20,
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
AesCbc,
|
AesCbc,
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
AesEcb,
|
AesEcb,
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
Sm4Cbc,
|
Sm4Cbc,
|
||||||
|
Xor,
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,61 +45,55 @@ impl Display for CipherModel {
|
|||||||
let str = match self {
|
let str = match self {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
CipherModel::AesGcm => "aes_gcm".to_string(),
|
CipherModel::AesGcm => "aes_gcm".to_string(),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
CipherModel::Chacha20Poly1305 => "chacha20_poly1305".to_string(),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
CipherModel::Chacha20 => "chacha20".to_string(),
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
CipherModel::AesCbc => "aes_cbc".to_string(),
|
CipherModel::AesCbc => "aes_cbc".to_string(),
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
CipherModel::AesEcb => "aes_ecb".to_string(),
|
CipherModel::AesEcb => "aes_ecb".to_string(),
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
CipherModel::Sm4Cbc => "sm4_cbc".to_string(),
|
CipherModel::Sm4Cbc => "sm4_cbc".to_string(),
|
||||||
|
CipherModel::Xor => "xor".to_string(),
|
||||||
CipherModel::None => "none".to_string(),
|
CipherModel::None => "none".to_string(),
|
||||||
};
|
};
|
||||||
write!(f, "{}", str)
|
write!(f, "{}", str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for CipherModel {
|
impl FromStr for CipherModel {
|
||||||
type Err = String;
|
type Err = String;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
#[cfg(not(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
return Err(format!("not match '{}', no encrypt", s));
|
|
||||||
#[cfg(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
match s.to_lowercase().trim() {
|
match s.to_lowercase().trim() {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
"aes_gcm" => Ok(CipherModel::AesGcm),
|
"aes_gcm" => Ok(CipherModel::AesGcm),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
"chacha20_poly1305" => Ok(CipherModel::Chacha20Poly1305),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
"chacha20" => Ok(CipherModel::Chacha20),
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
"aes_cbc" => Ok(CipherModel::AesCbc),
|
"aes_cbc" => Ok(CipherModel::AesCbc),
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
"aes_ecb" => Ok(CipherModel::AesEcb),
|
"aes_ecb" => Ok(CipherModel::AesEcb),
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
"sm4_cbc" => Ok(CipherModel::Sm4Cbc),
|
"sm4_cbc" => Ok(CipherModel::Sm4Cbc),
|
||||||
|
"xor" => Ok(CipherModel::Xor),
|
||||||
_ => {
|
_ => {
|
||||||
let mut enums = String::new();
|
let mut enums = String::new();
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
enums.push_str("/aes_gcm");
|
enums.push_str("/aes_gcm");
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
enums.push_str("/chacha20_poly1305/chacha20");
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
enums.push_str("/aes_cbc");
|
enums.push_str("/aes_cbc");
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
enums.push_str("/aes_ecb");
|
enums.push_str("/aes_ecb");
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
enums.push_str("/sm4_cbc");
|
enums.push_str("/sm4_cbc");
|
||||||
let str = if enums.is_empty() {
|
enums.push_str("/xor");
|
||||||
"no encrypt"
|
Err(format!("not match '{}', enum:{}", s, &enums[1..]))
|
||||||
} else {
|
|
||||||
&enums[1..]
|
|
||||||
};
|
|
||||||
Err(format!("not match '{}', enum:{}", s, str))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,199 +103,176 @@ impl FromStr for CipherModel {
|
|||||||
pub enum Cipher {
|
pub enum Cipher {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
AesGcm((AesGcmCipher, Vec<u8>)),
|
AesGcm((AesGcmCipher, Vec<u8>)),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Chacha20Poly1305(ChaCha20Poly1305Cipher),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Chacha20(ChaCha20Cipher),
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
AesCbc(AesCbcCipher),
|
AesCbc(AesCbcCipher),
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
AesEcb(AesEcbCipher),
|
AesEcb(AesEcbCipher),
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
Sm4Cbc(Sm4CbcCipher),
|
Sm4Cbc(Sm4CbcCipher),
|
||||||
|
Xor(XORCipher),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cipher {
|
impl Cipher {
|
||||||
#[cfg(not(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
pub fn new_password(
|
|
||||||
_model: CipherModel,
|
|
||||||
_password: Option<String>,
|
|
||||||
_token: Option<String>,
|
|
||||||
) -> Self {
|
|
||||||
Cipher::None
|
|
||||||
}
|
|
||||||
#[cfg(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
pub fn new_password(
|
pub fn new_password(
|
||||||
model: CipherModel,
|
model: CipherModel,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
token: Option<String>,
|
token: Option<String>,
|
||||||
) -> Self {
|
) -> anyhow::Result<Self> {
|
||||||
let finger = token.map(|token| Finger::new(&token));
|
|
||||||
if let Some(password) = password {
|
if let Some(password) = password {
|
||||||
let mut hasher = sha2::Sha256::new();
|
#[cfg(cipher)]
|
||||||
hasher.update(password.as_bytes());
|
let key: [u8; 32] = {
|
||||||
let key: [u8; 32] = hasher.finalize().into();
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(password.as_bytes());
|
||||||
|
hasher.finalize().into()
|
||||||
|
};
|
||||||
match model {
|
match model {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
CipherModel::AesGcm => {
|
CipherModel::AesGcm => {
|
||||||
|
let finger = token.map(|token| Finger::new(&token));
|
||||||
if password.len() < 8 {
|
if password.len() < 8 {
|
||||||
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
Cipher::AesGcm((aes, key[..16].to_vec()))
|
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
|
||||||
} else {
|
} else {
|
||||||
let aes = AesGcmCipher::new_256(key, finger);
|
let aes = AesGcmCipher::new_256(key, finger);
|
||||||
Cipher::AesGcm((aes, key.to_vec()))
|
Ok(Cipher::AesGcm((aes, key.to_vec())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
CipherModel::Chacha20Poly1305 => {
|
||||||
|
let finger = token.map(|token| Finger::new(&token));
|
||||||
|
let chacha = ChaCha20Poly1305Cipher::new_256(key, finger);
|
||||||
|
Ok(Cipher::Chacha20Poly1305(chacha))
|
||||||
|
}
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
CipherModel::Chacha20 => {
|
||||||
|
let finger = token.map(|token| Finger::new(&token));
|
||||||
|
let chacha = ChaCha20Cipher::new_256(key, finger);
|
||||||
|
Ok(Cipher::Chacha20(chacha))
|
||||||
|
}
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
CipherModel::AesCbc => {
|
CipherModel::AesCbc => {
|
||||||
|
let finger = token.map(|token| Finger::new(&token));
|
||||||
if password.len() < 8 {
|
if password.len() < 8 {
|
||||||
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
Cipher::AesCbc(aes)
|
Ok(Cipher::AesCbc(aes))
|
||||||
} else {
|
} else {
|
||||||
let aes = AesCbcCipher::new_256(key, finger);
|
let aes = AesCbcCipher::new_256(key, finger);
|
||||||
Cipher::AesCbc(aes)
|
Ok(Cipher::AesCbc(aes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
CipherModel::AesEcb => {
|
CipherModel::AesEcb => {
|
||||||
|
let finger = token.map(|token| Finger::new(&token));
|
||||||
if password.len() < 8 {
|
if password.len() < 8 {
|
||||||
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
Cipher::AesEcb(aes)
|
Ok(Cipher::AesEcb(aes))
|
||||||
} else {
|
} else {
|
||||||
let aes = AesEcbCipher::new_256(key, finger);
|
let aes = AesEcbCipher::new_256(key, finger);
|
||||||
Cipher::AesEcb(aes)
|
Ok(Cipher::AesEcb(aes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
CipherModel::Sm4Cbc => {
|
CipherModel::Sm4Cbc => {
|
||||||
|
let finger = token.map(|token| Finger::new(&token));
|
||||||
let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
Cipher::Sm4Cbc(aes)
|
Ok(Cipher::Sm4Cbc(aes))
|
||||||
}
|
}
|
||||||
CipherModel::None => Cipher::None,
|
CipherModel::Xor => {
|
||||||
|
if token.is_some() {
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"'finger' and 'xor' cannot be used simultaneously"
|
||||||
|
))?
|
||||||
|
}
|
||||||
|
Ok(Cipher::Xor(XORCipher::new_256(
|
||||||
|
crate::cipher::xor::simple_hash(&password),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
CipherModel::None => Ok(Cipher::None),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Cipher::None
|
Ok(Cipher::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
||||||
feature = "aes_gcm",
|
pub fn new_key(_key: [u8; 32], _token: String) -> anyhow::Result<Self> {
|
||||||
feature = "server_encrypt",
|
Err(anyhow!("key error"))
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
pub fn new_key(_key: [u8; 32], _token: String) -> io::Result<Self> {
|
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "key error"))
|
|
||||||
}
|
}
|
||||||
#[cfg(any(
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
feature = "aes_gcm",
|
pub fn new_key(key: [u8; 32], token: String) -> anyhow::Result<Self> {
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> {
|
|
||||||
let finger = Some(Finger::new(&token));
|
let finger = Some(Finger::new(&token));
|
||||||
match key.len() {
|
match key.len() {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
|
||||||
16 => {
|
16 => {
|
||||||
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
|
||||||
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
|
Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
|
||||||
32 => {
|
32 => {
|
||||||
let aes = AesGcmCipher::new_256(key, finger);
|
let aes = AesGcmCipher::new_256(key, finger);
|
||||||
Ok(Cipher::AesGcm((aes, key.to_vec())))
|
Ok(Cipher::AesGcm((aes, key.to_vec())))
|
||||||
}
|
}
|
||||||
_ => Err(io::Error::new(io::ErrorKind::Other, "key error")),
|
_ => Err(anyhow!("key error")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet),
|
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet),
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet),
|
Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305.decrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20(chacha20) => chacha20.decrypt_ipv4(net_packet),
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet),
|
Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet),
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.decrypt_ipv4(net_packet),
|
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.decrypt_ipv4(net_packet),
|
||||||
|
Cipher::Xor(xor) => xor.decrypt_ipv4(net_packet),
|
||||||
Cipher::None => {
|
Cipher::None => {
|
||||||
if net_packet.is_encrypt() {
|
if net_packet.is_encrypt() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not key"));
|
return Err(anyhow!("not key"));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
|
||||||
&self,
|
|
||||||
_net_packet: &mut NetPacket<B>,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[cfg(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet),
|
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305.encrypt_ipv4(net_packet),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20(chacha20) => chacha20.encrypt_ipv4(net_packet),
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet),
|
Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet),
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet),
|
Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet),
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.encrypt_ipv4(net_packet),
|
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.encrypt_ipv4(net_packet),
|
||||||
|
Cipher::Xor(xor) => xor.encrypt_ipv4(net_packet),
|
||||||
Cipher::None => Ok(()),
|
Cipher::None => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(any(
|
#[cfg(not(cipher))]
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
)))]
|
|
||||||
pub fn check_finger<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn check_finger<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
_net_packet: &NetPacket<B>,
|
_net_packet: &NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(any(
|
#[cfg(cipher)]
|
||||||
feature = "aes_gcm",
|
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> anyhow::Result<()> {
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
|
|
||||||
match self {
|
match self {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesGcm((aes_gcm, _)) => aes_gcm
|
Cipher::AesGcm((aes_gcm, _)) => aes_gcm
|
||||||
@@ -318,6 +280,18 @@ impl Cipher {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|f| f.check_finger(net_packet))
|
.map(|f| f.check_finger(net_packet))
|
||||||
.unwrap_or(Ok(())),
|
.unwrap_or(Ok(())),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20Poly1305(chacha20poly1305) => chacha20poly1305
|
||||||
|
.finger
|
||||||
|
.as_ref()
|
||||||
|
.map(|f| f.check_finger(net_packet))
|
||||||
|
.unwrap_or(Ok(())),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20(chacha20) => chacha20
|
||||||
|
.finger
|
||||||
|
.as_ref()
|
||||||
|
.map(|f| f.check_finger(net_packet))
|
||||||
|
.unwrap_or(Ok(())),
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
Cipher::AesCbc(aes_cbc) => aes_cbc
|
Cipher::AesCbc(aes_cbc) => aes_cbc
|
||||||
.finger
|
.finger
|
||||||
@@ -336,6 +310,7 @@ impl Cipher {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|f| f.check_finger(net_packet))
|
.map(|f| f.check_finger(net_packet))
|
||||||
.unwrap_or(Ok(())),
|
.unwrap_or(Ok(())),
|
||||||
|
Cipher::Xor(_) => Ok(()),
|
||||||
Cipher::None => Ok(()),
|
Cipher::None => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -343,12 +318,17 @@ impl Cipher {
|
|||||||
match self {
|
match self {
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
Cipher::AesGcm((_, key)) => Some(key),
|
Cipher::AesGcm((_, key)) => Some(key),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20Poly1305(chacha20poly1305) => Some(chacha20poly1305.key()),
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
Cipher::Chacha20(chacha20) => Some(chacha20.key()),
|
||||||
#[cfg(feature = "aes_cbc")]
|
#[cfg(feature = "aes_cbc")]
|
||||||
Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()),
|
Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()),
|
||||||
#[cfg(feature = "aes_ecb")]
|
#[cfg(feature = "aes_ecb")]
|
||||||
Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()),
|
Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()),
|
||||||
#[cfg(feature = "sm4_cbc")]
|
#[cfg(feature = "sm4_cbc")]
|
||||||
Cipher::Sm4Cbc(sm4_cbc) => Some(sm4_cbc.key()),
|
Cipher::Sm4Cbc(sm4_cbc) => Some(sm4_cbc.key()),
|
||||||
|
Cipher::Xor(xor) => Some(xor.key()),
|
||||||
Cipher::None => None,
|
Cipher::None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::io;
|
use anyhow::anyhow;
|
||||||
|
use rand::RngCore;
|
||||||
|
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
|
|
||||||
@@ -16,15 +17,15 @@ impl Finger {
|
|||||||
let hash: [u8; 32] = hasher.finalize().into();
|
let hash: [u8; 32] = hasher.finalize().into();
|
||||||
Finger { hash }
|
Finger { hash }
|
||||||
}
|
}
|
||||||
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
|
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> anyhow::Result<()> {
|
||||||
if !net_packet.is_encrypt() {
|
if !net_packet.is_encrypt() {
|
||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(anyhow!("not encrypt"));
|
||||||
}
|
}
|
||||||
let payload_len = net_packet.payload().len();
|
let payload_len = net_packet.payload().len();
|
||||||
if payload_len < 12 {
|
if payload_len < 12 {
|
||||||
log::error!("数据异常,长度小于{}", 12);
|
log::error!("数据异常,长度小于{}", 12);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
let mut nonce_raw = [0; 12];
|
let mut nonce_raw = [0; 12];
|
||||||
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
|
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
|
||||||
@@ -36,7 +37,7 @@ impl Finger {
|
|||||||
let payload = net_packet.payload();
|
let payload = net_packet.payload();
|
||||||
let finger = self.calculate_finger(&nonce_raw, &payload[..payload_len - 12]);
|
let finger = self.calculate_finger(&nonce_raw, &payload[..payload_len - 12]);
|
||||||
if &finger[..] != &payload[payload_len - 12..] {
|
if &finger[..] != &payload[payload_len - 12..] {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
return Err(anyhow!("finger err"));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -49,3 +50,27 @@ impl Finger {
|
|||||||
return key[20..].try_into().unwrap();
|
return key[20..].try_into().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||||
|
pub fn head_tag(&self) -> [u8; 12] {
|
||||||
|
let mut tag = [0; 12];
|
||||||
|
tag[0..4].copy_from_slice(&self.buffer()[4..8]);
|
||||||
|
tag[4..8].copy_from_slice(&self.buffer()[8..12]);
|
||||||
|
tag[8] = self.protocol().into();
|
||||||
|
tag[9] = self.transport_protocol();
|
||||||
|
tag[10] = self.is_gateway() as u8;
|
||||||
|
tag[11] = self.source_ttl();
|
||||||
|
tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn gen_nonce(tag: &mut [u8], random: &[u8]) {
|
||||||
|
tag[8] = random[0] ^ tag[8];
|
||||||
|
tag[9] = random[1] ^ tag[9];
|
||||||
|
tag[10] = random[2] ^ tag[10];
|
||||||
|
tag[11] = random[3] ^ tag[11];
|
||||||
|
}
|
||||||
|
pub fn gen_random_nonce(tag: &mut [u8; 12]) -> [u8; 4] {
|
||||||
|
let mut random = [0; 4];
|
||||||
|
rand::thread_rng().fill_bytes(&mut random);
|
||||||
|
gen_nonce(tag, &random);
|
||||||
|
random
|
||||||
|
}
|
||||||
|
|||||||
+22
-30
@@ -1,40 +1,32 @@
|
|||||||
#[cfg(feature = "aes_cbc")]
|
|
||||||
mod aes_cbc;
|
|
||||||
#[cfg(feature = "aes_ecb")]
|
|
||||||
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
|
||||||
mod aes_ecb;
|
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
|
||||||
#[cfg(not(feature = "ring-cipher"))]
|
|
||||||
mod aes_gcm_cipher;
|
|
||||||
mod cipher;
|
mod cipher;
|
||||||
#[cfg(any(
|
#[cfg(cipher)]
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
mod finger;
|
mod finger;
|
||||||
#[cfg(feature = "aes_ecb")]
|
|
||||||
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
|
|
||||||
mod openssl_aes_ecb;
|
|
||||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
|
||||||
#[cfg(feature = "ring-cipher")]
|
|
||||||
mod ring_aes_gcm_cipher;
|
|
||||||
|
|
||||||
#[cfg(feature = "sm4_cbc")]
|
|
||||||
mod sm4_cbc;
|
|
||||||
pub use cipher::Cipher;
|
pub use cipher::Cipher;
|
||||||
pub use cipher::CipherModel;
|
pub use cipher::CipherModel;
|
||||||
#[cfg(any(
|
#[cfg(cipher)]
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
pub use finger::Finger;
|
pub use finger::Finger;
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
mod rsa_cipher;
|
mod rsa_cipher;
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
pub use rsa_cipher::RsaCipher;
|
pub use rsa_cipher::RsaCipher;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||||
|
mod aes_gcm;
|
||||||
|
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
mod chacha20;
|
||||||
|
#[cfg(feature = "chacha20_poly1305")]
|
||||||
|
mod chacha20_poly1305;
|
||||||
|
|
||||||
|
#[cfg(feature = "aes_ecb")]
|
||||||
|
mod aes_ecb;
|
||||||
|
|
||||||
|
#[cfg(feature = "aes_cbc")]
|
||||||
|
mod aes_cbc;
|
||||||
|
|
||||||
|
#[cfg(feature = "sm4_cbc")]
|
||||||
|
mod sm4_cbc;
|
||||||
|
|
||||||
|
mod xor;
|
||||||
|
pub use xor::simple_hash;
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod rs_sm4_cbc;
|
||||||
|
pub use rs_sm4_cbc::*;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::cipher::Finger;
|
use crate::cipher::Finger;
|
||||||
use crate::protocol::{NetPacket, HEAD_LEN};
|
use crate::protocol::{NetPacket, HEAD_LEN};
|
||||||
|
use anyhow::anyhow;
|
||||||
use libsm::sm4::cipher_mode::CipherMode;
|
use libsm::sm4::cipher_mode::CipherMode;
|
||||||
use libsm::sm4::Sm4CipherMode;
|
use libsm::sm4::Sm4CipherMode;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use std::io;
|
|
||||||
|
|
||||||
pub struct Sm4CbcCipher {
|
pub struct Sm4CbcCipher {
|
||||||
key: [u8; 16],
|
key: [u8; 16],
|
||||||
@@ -41,28 +41,22 @@ impl Sm4CbcCipher {
|
|||||||
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if !net_packet.is_encrypt() {
|
if !net_packet.is_encrypt() {
|
||||||
//未加密的数据直接丢弃
|
//未加密的数据直接丢弃
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not encrypt"));
|
return Err(anyhow!("not encrypt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 len = net_packet.payload().len();
|
let len = net_packet.payload().len();
|
||||||
if len < 12 {
|
if len < 12 {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "payload len <12"));
|
return Err(anyhow!("payload len <12"));
|
||||||
}
|
}
|
||||||
let secret_body = &net_packet.payload()[..len - 12];
|
let secret_body = &net_packet.payload()[..len - 12];
|
||||||
let finger = finger.calculate_finger(&nonce_raw, secret_body);
|
let finger = finger.calculate_finger(&nonce_raw, secret_body);
|
||||||
if &finger != &net_packet.payload()[len - 12..] {
|
if &finger != &net_packet.payload()[len - 12..] {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "finger err"));
|
return Err(anyhow!("finger err"));
|
||||||
}
|
}
|
||||||
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
net_packet.set_data_len(net_packet.data_len() - finger.len())?;
|
||||||
}
|
}
|
||||||
@@ -70,7 +64,7 @@ impl Sm4CbcCipher {
|
|||||||
let len = payload.len();
|
let len = payload.len();
|
||||||
if len < 16 || len > 1024 * 4 {
|
if len < 16 || len > 1024 * 4 {
|
||||||
log::error!("数据异常,长度{}小于16或大于4096", len);
|
log::error!("数据异常,长度{}小于16或大于4096", len);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
let mut out = [0u8; 1024 * 4];
|
let mut out = [0u8; 1024 * 4];
|
||||||
let data = &payload[..len - 16];
|
let data = &payload[..len - 16];
|
||||||
@@ -79,32 +73,29 @@ impl Sm4CbcCipher {
|
|||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
let src_net_packet = NetPacket::new(&out[..len])?;
|
let src_net_packet = NetPacket::new(&out[..len])?;
|
||||||
if src_net_packet.source() != net_packet.source() {
|
if src_net_packet.source() != net_packet.source() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.destination() != net_packet.destination() {
|
if src_net_packet.destination() != net_packet.destination() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.protocol() != net_packet.protocol() {
|
if src_net_packet.protocol() != net_packet.protocol() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
|
if src_net_packet.transport_protocol() != net_packet.transport_protocol() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.is_gateway() != net_packet.is_gateway() {
|
if src_net_packet.is_gateway() != net_packet.is_gateway() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
if src_net_packet.source_ttl() != net_packet.source_ttl() {
|
if src_net_packet.source_ttl() != net_packet.source_ttl() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
net_packet.set_data_len(len)?;
|
net_packet.set_data_len(len)?;
|
||||||
net_packet.set_payload(src_net_packet.payload())?;
|
net_packet.set_payload(src_net_packet.payload())?;
|
||||||
net_packet.set_encrypt_flag(false);
|
net_packet.set_encrypt_flag(false);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("sm4_cbc解密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("sm4_cbc解密失败:{}", e),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// net_packet 必须预留足够长度
|
/// net_packet 必须预留足够长度
|
||||||
@@ -112,7 +103,7 @@ impl Sm4CbcCipher {
|
|||||||
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
&self,
|
&self,
|
||||||
net_packet: &mut NetPacket<B>,
|
net_packet: &mut NetPacket<B>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut out = [0u8; 1024 * 4];
|
let mut out = [0u8; 1024 * 4];
|
||||||
let mut iv = [0u8; 16];
|
let mut iv = [0u8; 16];
|
||||||
rand::thread_rng().fill_bytes(&mut iv);
|
rand::thread_rng().fill_bytes(&mut iv);
|
||||||
@@ -121,7 +112,7 @@ impl Sm4CbcCipher {
|
|||||||
"数据异常,长度{}大于1024 * 4 - 32",
|
"数据异常,长度{}大于1024 * 4 - 32",
|
||||||
net_packet.buffer().len()
|
net_packet.buffer().len()
|
||||||
);
|
);
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "data err"));
|
return Err(anyhow!("data err"));
|
||||||
}
|
}
|
||||||
match self.cipher.encrypt(net_packet.buffer(), &iv, &mut out) {
|
match self.cipher.encrypt(net_packet.buffer(), &iv, &mut out) {
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
@@ -129,13 +120,7 @@ impl Sm4CbcCipher {
|
|||||||
net_packet.payload_mut()[..len].copy_from_slice(&out[..len]);
|
net_packet.payload_mut()[..len].copy_from_slice(&out[..len]);
|
||||||
net_packet.payload_mut()[len..].copy_from_slice(&iv);
|
net_packet.payload_mut()[len..].copy_from_slice(&iv);
|
||||||
if let Some(finger) = &self.finger {
|
if let Some(finger) = &self.finger {
|
||||||
let mut nonce_raw = [0; 12];
|
let nonce_raw = net_packet.head_tag();
|
||||||
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 finger = finger.calculate_finger(&nonce_raw, net_packet.payload());
|
let finger = finger.calculate_finger(&nonce_raw, net_packet.payload());
|
||||||
let src_data_len = net_packet.data_len();
|
let src_data_len = net_packet.data_len();
|
||||||
//设置实际长度
|
//设置实际长度
|
||||||
@@ -146,10 +131,7 @@ impl Sm4CbcCipher {
|
|||||||
net_packet.set_encrypt_flag(true);
|
net_packet.set_encrypt_flag(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => Err(io::Error::new(
|
Err(e) => Err(anyhow!("sm4_cbc加密失败:{}", e)),
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("sm4_cbc加密失败:{}", e),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod xor;
|
||||||
|
pub use xor::*;
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
|
||||||
|
use crate::protocol::NetPacket;
|
||||||
|
|
||||||
|
pub fn simple_hash(input: &str) -> [u8; 32] {
|
||||||
|
let mut result = [0u8; 32];
|
||||||
|
let bytes = input.as_bytes();
|
||||||
|
for (index, v) in result.iter_mut().enumerate() {
|
||||||
|
*v = bytes[index % bytes.len()];
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut state = 0u8;
|
||||||
|
|
||||||
|
for (i, &byte) in bytes.iter().enumerate() {
|
||||||
|
let combined = byte.wrapping_add(state).rotate_left((i % 8) as u32);
|
||||||
|
result[i % 32] ^= combined;
|
||||||
|
state = state.wrapping_add(byte).rotate_left(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..32 {
|
||||||
|
result[i] = result[i]
|
||||||
|
.rotate_left((result[(i + 1) % 32] % 8) as u32)
|
||||||
|
.wrapping_add(state);
|
||||||
|
state = state.wrapping_add(result[i]).rotate_left(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct XORCipher {
|
||||||
|
key: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XORCipher {
|
||||||
|
pub fn new_256(key: [u8; 32]) -> Self {
|
||||||
|
Self { key }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XORCipher {
|
||||||
|
pub fn key(&self) -> &[u8] {
|
||||||
|
&self.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XORCipher {
|
||||||
|
pub fn decrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if !net_packet.is_encrypt() {
|
||||||
|
//未加密的数据直接丢弃
|
||||||
|
return Err(anyhow!("not encrypt"));
|
||||||
|
}
|
||||||
|
let key = &self.key;
|
||||||
|
for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() {
|
||||||
|
*byte ^= key[i & 31];
|
||||||
|
}
|
||||||
|
net_packet.set_encrypt_flag(false);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn encrypt_ipv4<B: AsRef<[u8]> + AsMut<[u8]>>(
|
||||||
|
&self,
|
||||||
|
net_packet: &mut NetPacket<B>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
net_packet.set_encrypt_flag(true);
|
||||||
|
let key = &self.key;
|
||||||
|
for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() {
|
||||||
|
*byte ^= key[i & 31];
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_xor() {
|
||||||
|
let d = XORCipher::new_256(simple_hash("password"));
|
||||||
|
let mut p = NetPacket::new_encrypt([0; 1000]).unwrap();
|
||||||
|
let src = p.buffer().to_vec();
|
||||||
|
d.encrypt_ipv4(&mut p).unwrap();
|
||||||
|
d.decrypt_ipv4(&mut p).unwrap();
|
||||||
|
assert_eq!(p.buffer(), &src)
|
||||||
|
}
|
||||||
@@ -135,6 +135,7 @@ impl Compressor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "zstd_compress")]
|
||||||
fn test_lz4() {
|
fn test_lz4() {
|
||||||
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
|
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
|
||||||
let lz4 = Compressor::Lz4;
|
let lz4 = Compressor::Lz4;
|
||||||
@@ -166,7 +167,7 @@ fn test_lz4() {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ExtensionTailPacket::Unknown => {
|
_ => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,6 +175,7 @@ fn test_lz4() {
|
|||||||
assert_eq!(in_packet.payload(), src_out_packet.payload())
|
assert_eq!(in_packet.payload(), src_out_packet.payload())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "zstd_compress")]
|
||||||
fn test_zstd() {
|
fn test_zstd() {
|
||||||
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
|
use crate::protocol::extension::{CompressionAlgorithm, ExtensionTailPacket};
|
||||||
let zstd = Compressor::Zstd(22);
|
let zstd = Compressor::Zstd(22);
|
||||||
@@ -209,7 +211,7 @@ fn test_zstd() {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ExtensionTailPacket::Unknown => {
|
_ => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+194
-92
@@ -1,21 +1,22 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
use tun::device::IFace;
|
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::idle::Idle;
|
use crate::channel::idle::Idle;
|
||||||
use crate::channel::punch::{NatInfo, Punch};
|
use crate::channel::punch::{NatInfo, Punch};
|
||||||
|
use crate::channel::sender::IpPacketSender;
|
||||||
use crate::channel::{init_channel, init_context, Route, RouteKey};
|
use crate::channel::{init_channel, init_context, Route, RouteKey};
|
||||||
use crate::cipher::Cipher;
|
use crate::cipher::Cipher;
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
use crate::cipher::RsaCipher;
|
use crate::cipher::RsaCipher;
|
||||||
|
use crate::compression::Compressor;
|
||||||
use crate::core::Config;
|
use crate::core::Config;
|
||||||
use crate::external_route::{AllowExternalRoute, ExternalRoute};
|
use crate::external_route::{AllowExternalRoute, ExternalRoute};
|
||||||
use crate::handle::handshaker::Handshake;
|
use crate::handle::handshaker::Handshake;
|
||||||
@@ -23,31 +24,88 @@ use crate::handle::maintain::PunchReceiver;
|
|||||||
use crate::handle::recv_data::RecvDataHandler;
|
use crate::handle::recv_data::RecvDataHandler;
|
||||||
use crate::handle::{maintain, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
|
use crate::handle::{maintain, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
use crate::nat::NatTest;
|
use crate::nat::NatTest;
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
use crate::tun_tap_device::tun_create_helper::{DeviceAdapter, TunDeviceHelper};
|
use crate::tun_tap_device::tun_create_helper::{DeviceAdapter, TunDeviceHelper};
|
||||||
use crate::util::{
|
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||||
Scheduler, SingleU64Adder, StopManager, U64Adder, WatchSingleU64Adder, WatchU64Adder,
|
use crate::util::limit::TrafficMeterMultiAddress;
|
||||||
};
|
use crate::util::{Scheduler, StopManager};
|
||||||
use crate::{nat, VntCallback};
|
use crate::{nat, VntCallback};
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
use crate::{tun_tap_device, DeviceInfo};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Vnt {
|
pub struct Vnt {
|
||||||
|
inner: Arc<VntInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vnt {
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
||||||
|
let inner = Arc::new(VntInner::new(config, callback)?);
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "integrated_tun"))]
|
||||||
|
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
||||||
|
config: Config,
|
||||||
|
callback: Call,
|
||||||
|
device: Device,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let inner = Arc::new(VntInner::new_device(config, callback, device)?);
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Vnt {
|
||||||
|
type Target = VntInner;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VntInner {
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
config: Config,
|
config: Config,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
context: Arc<Mutex<Option<ChannelContext>>>,
|
context: Arc<Mutex<Option<ChannelContext>>>,
|
||||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||||
down_count_watcher: WatchU64Adder,
|
|
||||||
up_count_watcher: WatchSingleU64Adder,
|
|
||||||
client_secret_hash: Option<[u8; 16]>,
|
client_secret_hash: Option<[u8; 16]>,
|
||||||
|
compressor: Compressor,
|
||||||
|
client_cipher: Cipher,
|
||||||
|
server_cipher: Cipher,
|
||||||
|
external_route: ExternalRoute,
|
||||||
|
up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
|
down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vnt {
|
impl VntInner {
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
||||||
log::info!("config.toml:{:?}", config);
|
VntInner::new_device0(config, callback, DeviceAdapter::default())
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "integrated_tun"))]
|
||||||
|
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
||||||
|
config: Config,
|
||||||
|
callback: Call,
|
||||||
|
device: Device,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
VntInner::new_device0(config, callback, device)
|
||||||
|
}
|
||||||
|
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
|
||||||
|
config: Config,
|
||||||
|
callback: Call,
|
||||||
|
device: Device,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
log::info!("config: {:?}", config);
|
||||||
|
let (up_traffic_meter, down_traffic_meter) = if config.enable_traffic {
|
||||||
|
(
|
||||||
|
Some(TrafficMeterMultiAddress::default()),
|
||||||
|
Some(TrafficMeterMultiAddress::default()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
|
||||||
//服务端非对称加密
|
//服务端非对称加密
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
let rsa_cipher: Arc<Mutex<Option<RsaCipher>>> = Arc::new(Mutex::new(None));
|
let rsa_cipher: Arc<Mutex<Option<RsaCipher>>> = Arc::new(Mutex::new(None));
|
||||||
@@ -66,14 +124,21 @@ impl Vnt {
|
|||||||
};
|
};
|
||||||
//客户端对称加密
|
//客户端对称加密
|
||||||
let client_cipher =
|
let client_cipher =
|
||||||
Cipher::new_password(config.cipher_model, config.password.clone(), finger);
|
Cipher::new_password(config.cipher_model, config.password.clone(), finger)?;
|
||||||
//当前设备信息
|
//当前设备信息
|
||||||
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new0(
|
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new0(
|
||||||
config.server_address,
|
config.server_address,
|
||||||
)));
|
)));
|
||||||
//设备列表
|
//设备列表
|
||||||
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> =
|
let device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>> =
|
||||||
Arc::new(Mutex::new((0, Vec::with_capacity(16))));
|
Arc::new(Mutex::new((0, HashMap::with_capacity(16))));
|
||||||
|
let local_ipv4 = if let Some(local_ipv4) = config.local_ipv4 {
|
||||||
|
Some(local_ipv4)
|
||||||
|
} else {
|
||||||
|
nat::local_ipv4()
|
||||||
|
};
|
||||||
|
let default_interface = config.local_interface.clone();
|
||||||
|
|
||||||
//基础信息
|
//基础信息
|
||||||
let config_info = BaseConfigInfo::new(
|
let config_info = BaseConfigInfo::new(
|
||||||
config.name.clone(),
|
config.name.clone(),
|
||||||
@@ -84,6 +149,15 @@ impl Vnt {
|
|||||||
config.device_id.clone(),
|
config.device_id.clone(),
|
||||||
config.server_address_str.clone(),
|
config.server_address_str.clone(),
|
||||||
config.name_servers.clone(),
|
config.name_servers.clone(),
|
||||||
|
config.mtu.unwrap_or(1420),
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
config.tap,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
config.device_name.clone(),
|
||||||
|
config.allow_wire_guard,
|
||||||
|
default_interface.clone(),
|
||||||
);
|
);
|
||||||
// 服务停止管理器
|
// 服务停止管理器
|
||||||
let stop_manager = {
|
let stop_manager = {
|
||||||
@@ -111,11 +185,13 @@ impl Vnt {
|
|||||||
ports,
|
ports,
|
||||||
config.use_channel_type,
|
config.use_channel_type,
|
||||||
config.first_latency,
|
config.first_latency,
|
||||||
config.tcp,
|
config.protocol,
|
||||||
config.packet_loss_rate,
|
config.packet_loss_rate,
|
||||||
config.packet_delay,
|
config.packet_delay,
|
||||||
|
default_interface,
|
||||||
|
up_traffic_meter.clone(),
|
||||||
|
down_traffic_meter.clone(),
|
||||||
)?;
|
)?;
|
||||||
let local_ipv4 = nat::local_ipv4();
|
|
||||||
let local_ipv6 = nat::local_ipv6();
|
let local_ipv6 = nat::local_ipv6();
|
||||||
let udp_ports = context.main_local_udp_port()?;
|
let udp_ports = context.main_local_udp_port()?;
|
||||||
let tcp_port = tcp_listener.local_addr()?.port();
|
let tcp_port = tcp_listener.local_addr()?.port();
|
||||||
@@ -127,25 +203,16 @@ impl Vnt {
|
|||||||
local_ipv6,
|
local_ipv6,
|
||||||
udp_ports,
|
udp_ports,
|
||||||
tcp_port,
|
tcp_port,
|
||||||
|
config.local_ipv4.is_none(),
|
||||||
|
config.punch_model,
|
||||||
);
|
);
|
||||||
|
|
||||||
// pc上先创建虚拟网卡
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
let device = {
|
|
||||||
log::info!("开始创建tun");
|
|
||||||
let device = tun_tap_device::create_device(&config)?;
|
|
||||||
log::info!("创建tun成功");
|
|
||||||
let tun_info = DeviceInfo::new(device.name()?, device.version()?);
|
|
||||||
log::info!("tun信息{:?}", tun_info);
|
|
||||||
callback.create_tun(tun_info);
|
|
||||||
device
|
|
||||||
};
|
|
||||||
// 定时器
|
// 定时器
|
||||||
let scheduler = Scheduler::new(stop_manager.clone())?;
|
let scheduler = Scheduler::new(stop_manager.clone())?;
|
||||||
let external_route = ExternalRoute::new(config.in_ips.clone());
|
let external_route = ExternalRoute::new(config.in_ips.clone());
|
||||||
let out_external_route = AllowExternalRoute::new(config.out_ips.clone());
|
let out_external_route = AllowExternalRoute::new(config.out_ips.clone());
|
||||||
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy {
|
let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy {
|
||||||
Some(crate::ip_proxy::init_proxy(
|
Some(crate::ip_proxy::init_proxy(
|
||||||
context.clone(),
|
context.clone(),
|
||||||
@@ -159,33 +226,26 @@ impl Vnt {
|
|||||||
let (punch_sender, punch_receiver) = maintain::punch_channel();
|
let (punch_sender, punch_receiver) = maintain::punch_channel();
|
||||||
let peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>> =
|
let peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>> =
|
||||||
Arc::new(RwLock::new(HashMap::with_capacity(16)));
|
Arc::new(RwLock::new(HashMap::with_capacity(16)));
|
||||||
let down_counter =
|
|
||||||
U64Adder::with_capacity(config.ports.as_ref().map(|v| v.len()).unwrap_or_default() + 8);
|
|
||||||
let down_count_watcher = down_counter.watch();
|
|
||||||
let handshake = Handshake::new(
|
let handshake = Handshake::new(
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
rsa_cipher.clone(),
|
rsa_cipher.clone(),
|
||||||
);
|
);
|
||||||
let up_counter = SingleU64Adder::new();
|
#[cfg(feature = "integrated_tun")]
|
||||||
let up_count_watcher = up_counter.watch();
|
let tun_device_helper = {
|
||||||
let tun_helper = TunDeviceHelper::new(
|
TunDeviceHelper::new(
|
||||||
stop_manager.clone(),
|
stop_manager.clone(),
|
||||||
context.clone(),
|
context.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
external_route.clone(),
|
external_route.clone(),
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
proxy_map.clone(),
|
proxy_map.clone(),
|
||||||
client_cipher.clone(),
|
client_cipher.clone(),
|
||||||
server_cipher.clone(),
|
server_cipher.clone(),
|
||||||
config.parallel,
|
device_map.clone(),
|
||||||
up_counter,
|
config.compressor,
|
||||||
device_list.clone(),
|
device.clone().into_device_adapter(),
|
||||||
config.compressor,
|
)
|
||||||
);
|
};
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
let device_adapter = DeviceAdapter::new(device.clone());
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
let device_adapter = DeviceAdapter::new(tun_helper);
|
|
||||||
|
|
||||||
let handler = RecvDataHandler::new(
|
let handler = RecvDataHandler::new(
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
@@ -193,8 +253,8 @@ impl Vnt {
|
|||||||
server_cipher.clone(),
|
server_cipher.clone(),
|
||||||
client_cipher.clone(),
|
client_cipher.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
device_adapter,
|
device,
|
||||||
device_list.clone(),
|
device_map.clone(),
|
||||||
config_info.clone(),
|
config_info.clone(),
|
||||||
nat_test.clone(),
|
nat_test.clone(),
|
||||||
callback.clone(),
|
callback.clone(),
|
||||||
@@ -203,33 +263,34 @@ impl Vnt {
|
|||||||
external_route.clone(),
|
external_route.clone(),
|
||||||
out_external_route,
|
out_external_route,
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
proxy_map.clone(),
|
proxy_map.clone(),
|
||||||
down_counter,
|
|
||||||
handshake.clone(),
|
handshake.clone(),
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
tun_device_helper,
|
||||||
);
|
);
|
||||||
|
|
||||||
//初始化网络数据通道
|
//初始化网络数据通道
|
||||||
let (udp_socket_sender, tcp_socket_sender) =
|
let (udp_socket_sender, connect_util) =
|
||||||
init_channel(tcp_listener, context.clone(), stop_manager.clone(), handler)?;
|
init_channel(tcp_listener, context.clone(), stop_manager.clone(), handler)?;
|
||||||
// 打洞逻辑
|
// 打洞逻辑
|
||||||
let punch = Punch::new(
|
let punch = Punch::new(
|
||||||
context.clone(),
|
context.clone(),
|
||||||
config.punch_model,
|
config.punch_model,
|
||||||
config.tcp,
|
connect_util.clone(),
|
||||||
tcp_socket_sender.clone(),
|
|
||||||
external_route.clone(),
|
|
||||||
nat_test.clone(),
|
nat_test.clone(),
|
||||||
|
current_device.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
// #[cfg(not(target_os = "android"))]
|
||||||
tun_helper.start(device)?;
|
// tun_helper.start(device)?;
|
||||||
|
|
||||||
maintain::idle_gateway(
|
maintain::idle_gateway(
|
||||||
&scheduler,
|
&scheduler,
|
||||||
context.clone(),
|
context.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
config_info.clone(),
|
config_info.clone(),
|
||||||
tcp_socket_sender.clone(),
|
connect_util.clone(),
|
||||||
callback.clone(),
|
callback.clone(),
|
||||||
0,
|
0,
|
||||||
handshake,
|
handshake,
|
||||||
@@ -237,9 +298,7 @@ impl Vnt {
|
|||||||
{
|
{
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
let nat_test = nat_test.clone();
|
let nat_test = nat_test.clone();
|
||||||
let device_list = device_list.clone();
|
let device_map = device_map.clone();
|
||||||
let down_count_watcher = down_count_watcher.clone();
|
|
||||||
let up_count_watcher = up_count_watcher.clone();
|
|
||||||
let config_info = config_info.clone();
|
let config_info = config_info.clone();
|
||||||
let current_device = current_device.clone();
|
let current_device = current_device.clone();
|
||||||
if !config.use_channel_type.is_only_relay() {
|
if !config.use_channel_type.is_only_relay() {
|
||||||
@@ -251,13 +310,15 @@ impl Vnt {
|
|||||||
udp_socket_sender,
|
udp_socket_sender,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let client_cipher = client_cipher.clone();
|
||||||
|
let server_cipher = server_cipher.clone();
|
||||||
//延迟启动
|
//延迟启动
|
||||||
scheduler.timeout(Duration::from_secs(3), move |scheduler| {
|
scheduler.timeout(Duration::from_secs(1), move |scheduler| {
|
||||||
start(
|
start(
|
||||||
scheduler,
|
scheduler,
|
||||||
context,
|
context,
|
||||||
nat_test,
|
nat_test,
|
||||||
device_list,
|
device_map,
|
||||||
current_device,
|
current_device,
|
||||||
client_cipher,
|
client_cipher,
|
||||||
server_cipher,
|
server_cipher,
|
||||||
@@ -265,23 +326,25 @@ impl Vnt {
|
|||||||
config_info,
|
config_info,
|
||||||
punch,
|
punch,
|
||||||
callback,
|
callback,
|
||||||
down_count_watcher,
|
|
||||||
up_count_watcher,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let compressor = config.compressor;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
stop_manager,
|
stop_manager,
|
||||||
config,
|
config,
|
||||||
current_device,
|
current_device,
|
||||||
nat_test,
|
nat_test,
|
||||||
device_list,
|
device_map,
|
||||||
context: Arc::new(Mutex::new(Some(context))),
|
context: Arc::new(Mutex::new(Some(context))),
|
||||||
peer_nat_info_map,
|
peer_nat_info_map,
|
||||||
down_count_watcher,
|
|
||||||
up_count_watcher,
|
|
||||||
client_secret_hash: config_info.client_secret_hash,
|
client_secret_hash: config_info.client_secret_hash,
|
||||||
|
compressor,
|
||||||
|
client_cipher,
|
||||||
|
server_cipher,
|
||||||
|
external_route,
|
||||||
|
up_traffic_meter,
|
||||||
|
down_traffic_meter,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,7 +353,7 @@ pub fn start<Call: VntCallback>(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
@@ -298,15 +361,13 @@ pub fn start<Call: VntCallback>(
|
|||||||
config_info: BaseConfigInfo,
|
config_info: BaseConfigInfo,
|
||||||
punch: Punch,
|
punch: Punch,
|
||||||
callback: Call,
|
callback: Call,
|
||||||
down_count_watcher: WatchU64Adder,
|
|
||||||
up_count_watcher: WatchSingleU64Adder,
|
|
||||||
) {
|
) {
|
||||||
// 定时心跳
|
// 定时心跳
|
||||||
maintain::heartbeat(
|
maintain::heartbeat(
|
||||||
&scheduler,
|
&scheduler,
|
||||||
context.clone(),
|
context.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
device_list.clone(),
|
device_map.clone(),
|
||||||
client_cipher.clone(),
|
client_cipher.clone(),
|
||||||
server_cipher.clone(),
|
server_cipher.clone(),
|
||||||
);
|
);
|
||||||
@@ -326,7 +387,7 @@ pub fn start<Call: VntCallback>(
|
|||||||
&scheduler,
|
&scheduler,
|
||||||
context.clone(),
|
context.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
device_list.clone(),
|
device_map.clone(),
|
||||||
client_cipher.clone(),
|
client_cipher.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -337,7 +398,6 @@ pub fn start<Call: VntCallback>(
|
|||||||
&scheduler,
|
&scheduler,
|
||||||
context.clone(),
|
context.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
server_cipher.clone(),
|
|
||||||
nat_test.clone(),
|
nat_test.clone(),
|
||||||
config_info.clone(),
|
config_info.clone(),
|
||||||
);
|
);
|
||||||
@@ -346,23 +406,17 @@ pub fn start<Call: VntCallback>(
|
|||||||
&scheduler,
|
&scheduler,
|
||||||
context.clone(),
|
context.clone(),
|
||||||
nat_test.clone(),
|
nat_test.clone(),
|
||||||
device_list.clone(),
|
device_map.clone(),
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
client_cipher.clone(),
|
client_cipher.clone(),
|
||||||
punch_receiver,
|
punch_receiver,
|
||||||
punch,
|
punch,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
maintain::up_status(
|
maintain::up_status(scheduler, context.clone(), current_device.clone())
|
||||||
scheduler,
|
|
||||||
context.clone(),
|
|
||||||
current_device.clone(),
|
|
||||||
down_count_watcher,
|
|
||||||
up_count_watcher,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vnt {
|
impl VntInner {
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.config.name
|
&self.config.name
|
||||||
}
|
}
|
||||||
@@ -378,6 +432,9 @@ impl Vnt {
|
|||||||
pub fn current_device(&self) -> CurrentDeviceInfo {
|
pub fn current_device(&self) -> CurrentDeviceInfo {
|
||||||
self.current_device.load()
|
self.current_device.load()
|
||||||
}
|
}
|
||||||
|
pub fn current_device_info(&self) -> Arc<AtomicCell<CurrentDeviceInfo>> {
|
||||||
|
self.current_device.clone()
|
||||||
|
}
|
||||||
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
|
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
|
||||||
self.peer_nat_info_map.read().get(ip).cloned()
|
self.peer_nat_info_map.read().get(ip).cloned()
|
||||||
}
|
}
|
||||||
@@ -388,10 +445,10 @@ impl Vnt {
|
|||||||
self.nat_test.nat_info()
|
self.nat_test.nat_info()
|
||||||
}
|
}
|
||||||
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
|
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
|
||||||
let device_list_lock = self.device_list.lock();
|
let device_list_lock = self.device_map.lock();
|
||||||
let (_epoch, device_list) = device_list_lock.clone();
|
let (_epoch, device_list) = device_list_lock.clone();
|
||||||
drop(device_list_lock);
|
drop(device_list_lock);
|
||||||
device_list
|
device_list.into_values().collect()
|
||||||
}
|
}
|
||||||
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
|
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
|
||||||
self.context.lock().as_ref()?.route_table.route_one(ip)
|
self.context.lock().as_ref()?.route_table.route_one(ip)
|
||||||
@@ -414,16 +471,39 @@ impl Vnt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn up_stream(&self) -> u64 {
|
pub fn up_stream(&self) -> u64 {
|
||||||
self.up_count_watcher.get()
|
self.up_traffic_meter.as_ref().map_or(0, |v| v.total())
|
||||||
|
}
|
||||||
|
pub fn up_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
|
||||||
|
self.up_traffic_meter.as_ref().map(|v| v.get_all())
|
||||||
|
}
|
||||||
|
pub fn up_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
|
||||||
|
self.up_traffic_meter.as_ref().map(|v| v.get_all_history())
|
||||||
}
|
}
|
||||||
pub fn down_stream(&self) -> u64 {
|
pub fn down_stream(&self) -> u64 {
|
||||||
self.down_count_watcher.get()
|
self.down_traffic_meter.as_ref().map_or(0, |v| v.total())
|
||||||
|
}
|
||||||
|
pub fn down_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
|
||||||
|
self.down_traffic_meter.as_ref().map(|v| v.get_all())
|
||||||
|
}
|
||||||
|
pub fn down_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
|
||||||
|
self.down_traffic_meter
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| v.get_all_history())
|
||||||
}
|
}
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
//退出协助回收资源
|
//退出协助回收资源
|
||||||
let _ = self.context.lock().take();
|
let _ = self.context.lock().take();
|
||||||
self.stop_manager.stop()
|
self.stop_manager.stop()
|
||||||
}
|
}
|
||||||
|
pub fn is_stopped(&self) -> bool {
|
||||||
|
self.stop_manager.is_stopped()
|
||||||
|
}
|
||||||
|
pub fn add_stop_listener<F>(&self, name: String, f: F) -> anyhow::Result<crate::util::Worker>
|
||||||
|
where
|
||||||
|
F: FnOnce() + Send + 'static,
|
||||||
|
{
|
||||||
|
self.stop_manager.add_listener(name, f)
|
||||||
|
}
|
||||||
pub fn wait(&self) {
|
pub fn wait(&self) {
|
||||||
self.stop_manager.wait()
|
self.stop_manager.wait()
|
||||||
}
|
}
|
||||||
@@ -433,4 +513,26 @@ impl Vnt {
|
|||||||
pub fn config(&self) -> &Config {
|
pub fn config(&self) -> &Config {
|
||||||
&self.config
|
&self.config
|
||||||
}
|
}
|
||||||
|
pub fn ipv4_packet_sender(&self) -> Option<IpPacketSender> {
|
||||||
|
if let Some(c) = self.context.lock().as_ref() {
|
||||||
|
Some(IpPacketSender::new(
|
||||||
|
c.clone(),
|
||||||
|
self.current_device.clone(),
|
||||||
|
self.compressor.clone(),
|
||||||
|
self.client_cipher.clone(),
|
||||||
|
self.server_cipher.clone(),
|
||||||
|
self.external_route.clone(),
|
||||||
|
self.device_map.clone(),
|
||||||
|
self.config.allow_wire_guard,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VntInner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-39
@@ -5,7 +5,8 @@ use std::str::FromStr;
|
|||||||
pub use conn::Vnt;
|
pub use conn::Vnt;
|
||||||
|
|
||||||
use crate::channel::punch::PunchModel;
|
use crate::channel::punch::PunchModel;
|
||||||
use crate::channel::UseChannelType;
|
use crate::channel::socket::LocalInterface;
|
||||||
|
use crate::channel::{ConnectProtocol, UseChannelType};
|
||||||
use crate::cipher::CipherModel;
|
use crate::cipher::CipherModel;
|
||||||
use crate::compression::Compressor;
|
use crate::compression::Compressor;
|
||||||
use crate::util::{address_choose, dns_query_all};
|
use crate::util::{address_choose, dns_query_all};
|
||||||
@@ -14,6 +15,7 @@ mod conn;
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub tap: bool,
|
pub tap: bool,
|
||||||
pub token: String,
|
pub token: String,
|
||||||
@@ -27,18 +29,19 @@ pub struct Config {
|
|||||||
pub out_ips: Vec<(u32, u32)>,
|
pub out_ips: Vec<(u32, u32)>,
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
pub mtu: Option<u32>,
|
pub mtu: Option<u32>,
|
||||||
pub tcp: bool,
|
pub protocol: ConnectProtocol,
|
||||||
pub ip: Option<Ipv4Addr>,
|
pub ip: Option<Ipv4Addr>,
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
pub no_proxy: bool,
|
pub no_proxy: bool,
|
||||||
pub server_encrypt: bool,
|
pub server_encrypt: bool,
|
||||||
pub parallel: usize,
|
|
||||||
pub cipher_model: CipherModel,
|
pub cipher_model: CipherModel,
|
||||||
pub finger: bool,
|
pub finger: bool,
|
||||||
pub punch_model: PunchModel,
|
pub punch_model: PunchModel,
|
||||||
pub ports: Option<Vec<u16>>,
|
pub ports: Option<Vec<u16>>,
|
||||||
pub first_latency: bool,
|
pub first_latency: bool,
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
pub device_name: Option<String>,
|
pub device_name: Option<String>,
|
||||||
pub use_channel_type: UseChannelType,
|
pub use_channel_type: UseChannelType,
|
||||||
//控制丢包率
|
//控制丢包率
|
||||||
@@ -48,11 +51,17 @@ pub struct Config {
|
|||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
|
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
|
||||||
pub compressor: Compressor,
|
pub compressor: Compressor,
|
||||||
|
pub enable_traffic: bool,
|
||||||
|
pub allow_wire_guard: bool,
|
||||||
|
pub local_ipv4: Option<Ipv4Addr>,
|
||||||
|
pub local_interface: LocalInterface,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
#[cfg(target_os = "windows")] tap: bool,
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
tap: bool,
|
||||||
token: String,
|
token: String,
|
||||||
device_id: String,
|
device_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
@@ -63,23 +72,29 @@ impl Config {
|
|||||||
out_ips: Vec<(u32, u32)>,
|
out_ips: Vec<(u32, u32)>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
mtu: Option<u32>,
|
mtu: Option<u32>,
|
||||||
tcp: bool,
|
|
||||||
ip: Option<Ipv4Addr>,
|
ip: Option<Ipv4Addr>,
|
||||||
#[cfg(feature = "ip_proxy")] no_proxy: bool,
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
no_proxy: bool,
|
||||||
server_encrypt: bool,
|
server_encrypt: bool,
|
||||||
parallel: usize,
|
|
||||||
cipher_model: CipherModel,
|
cipher_model: CipherModel,
|
||||||
finger: bool,
|
finger: bool,
|
||||||
punch_model: PunchModel,
|
punch_model: PunchModel,
|
||||||
ports: Option<Vec<u16>>,
|
ports: Option<Vec<u16>>,
|
||||||
first_latency: bool,
|
first_latency: bool,
|
||||||
#[cfg(not(target_os = "android"))] device_name: Option<String>,
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
device_name: Option<String>,
|
||||||
use_channel_type: UseChannelType,
|
use_channel_type: UseChannelType,
|
||||||
packet_loss_rate: Option<f64>,
|
packet_loss_rate: Option<f64>,
|
||||||
packet_delay: u32,
|
packet_delay: u32,
|
||||||
// 例如 [udp:127.0.0.1:80->10.26.0.10:8080,tcp:127.0.0.1:80->10.26.0.10:8080]
|
// 例如 [udp:127.0.0.1:80->10.26.0.10:8080,tcp:127.0.0.1:80->10.26.0.10:8080]
|
||||||
#[cfg(feature = "port_mapping")] port_mapping_list: Vec<String>,
|
#[cfg(feature = "port_mapping")] port_mapping_list: Vec<String>,
|
||||||
compressor: Compressor,
|
compressor: Compressor,
|
||||||
|
enable_traffic: bool,
|
||||||
|
// 允许传递wg流量
|
||||||
|
allow_wire_guard: bool,
|
||||||
|
local_dev: Option<String>,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
for x in stun_server.iter_mut() {
|
for x in stun_server.iter_mut() {
|
||||||
if !x.contains(":") {
|
if !x.contains(":") {
|
||||||
@@ -102,8 +117,52 @@ impl Config {
|
|||||||
if name.is_empty() || name.len() > 128 {
|
if name.is_empty() || name.len() > 128 {
|
||||||
return Err(anyhow!("name too long"));
|
return Err(anyhow!("name too long"));
|
||||||
}
|
}
|
||||||
let server_address =
|
let mut server_address_str = server_address_str.to_lowercase();
|
||||||
address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?;
|
let mut _query_dns = true;
|
||||||
|
let mut protocol = ConnectProtocol::UDP;
|
||||||
|
if server_address_str.starts_with("ws://") {
|
||||||
|
#[cfg(not(feature = "ws"))]
|
||||||
|
Err(anyhow!("Ws not supported"))?;
|
||||||
|
protocol = ConnectProtocol::WS;
|
||||||
|
_query_dns = false;
|
||||||
|
}
|
||||||
|
if server_address_str.starts_with("wss://") {
|
||||||
|
#[cfg(not(feature = "wss"))]
|
||||||
|
Err(anyhow!("Wss not supported"))?;
|
||||||
|
protocol = ConnectProtocol::WSS;
|
||||||
|
_query_dns = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut server_address = "0.0.0.0:0".parse().unwrap();
|
||||||
|
if _query_dns {
|
||||||
|
if let Some(s) = server_address_str.strip_prefix("udp://") {
|
||||||
|
server_address_str = s.to_string();
|
||||||
|
} else if let Some(s) = server_address_str.strip_prefix("tcp://") {
|
||||||
|
server_address_str = s.to_string();
|
||||||
|
protocol = ConnectProtocol::TCP;
|
||||||
|
}
|
||||||
|
let address_result = dns_query_all(
|
||||||
|
&server_address_str,
|
||||||
|
name_servers.clone(),
|
||||||
|
&LocalInterface::default(),
|
||||||
|
);
|
||||||
|
match address_result {
|
||||||
|
Ok(address) => match address_choose(address) {
|
||||||
|
Ok(resolved_address) => {
|
||||||
|
server_address = resolved_address;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to choose address: {}", e);
|
||||||
|
println!("Failed to choose address: {}", e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("DNS query failed: {}", e);
|
||||||
|
println!("DNS query failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;
|
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;
|
||||||
|
|
||||||
@@ -111,7 +170,15 @@ impl Config {
|
|||||||
*dest = *mask & *dest;
|
*dest = *mask & *dest;
|
||||||
}
|
}
|
||||||
in_ips.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1));
|
in_ips.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1));
|
||||||
|
let (local_interface, local_ipv4) = if let Some(local_dev) = local_dev {
|
||||||
|
let (default_interface, ip) = crate::channel::socket::get_interface(local_dev)?;
|
||||||
|
log::info!("default_interface = {:?} local_ip= {ip}", default_interface);
|
||||||
|
(default_interface, Some(ip))
|
||||||
|
} else {
|
||||||
|
(LocalInterface::default(), None)
|
||||||
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
tap,
|
tap,
|
||||||
token,
|
token,
|
||||||
@@ -125,17 +192,18 @@ impl Config {
|
|||||||
out_ips,
|
out_ips,
|
||||||
password,
|
password,
|
||||||
mtu,
|
mtu,
|
||||||
tcp,
|
protocol,
|
||||||
ip,
|
ip,
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
no_proxy,
|
no_proxy,
|
||||||
server_encrypt,
|
server_encrypt,
|
||||||
parallel,
|
|
||||||
cipher_model,
|
cipher_model,
|
||||||
finger,
|
finger,
|
||||||
punch_model,
|
punch_model,
|
||||||
ports,
|
ports,
|
||||||
first_latency,
|
first_latency,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
device_name,
|
device_name,
|
||||||
use_channel_type,
|
use_channel_type,
|
||||||
@@ -144,36 +212,36 @@ impl Config {
|
|||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
port_mapping_list,
|
port_mapping_list,
|
||||||
compressor,
|
compressor,
|
||||||
|
enable_traffic,
|
||||||
|
allow_wire_guard,
|
||||||
|
local_ipv4,
|
||||||
|
local_interface,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
#[cfg(any(
|
|
||||||
feature = "aes_gcm",
|
|
||||||
feature = "server_encrypt",
|
|
||||||
feature = "aes_cbc",
|
|
||||||
feature = "aes_ecb",
|
|
||||||
feature = "sm4_cbc"
|
|
||||||
))]
|
|
||||||
pub fn password_hash(&self) -> Option<[u8; 16]> {
|
pub fn password_hash(&self) -> Option<[u8; 16]> {
|
||||||
self.password.as_ref().map(|v| {
|
if let Some(p) = self.password.as_ref() {
|
||||||
use sha2::Digest;
|
match self.cipher_model {
|
||||||
let mut hasher = sha2::Sha256::new();
|
CipherModel::Xor => {
|
||||||
hasher.update(self.cipher_model.to_string().as_bytes());
|
let key = crate::cipher::simple_hash(&format!("Xor{}{}", p, self.token));
|
||||||
hasher.update(v.as_bytes());
|
Some(key[16..].try_into().unwrap())
|
||||||
hasher.update(self.token.as_bytes());
|
}
|
||||||
let key: [u8; 32] = hasher.finalize().into();
|
CipherModel::None => None,
|
||||||
key[16..].try_into().unwrap()
|
#[cfg(cipher)]
|
||||||
})
|
_ => {
|
||||||
}
|
use sha2::Digest;
|
||||||
#[cfg(not(any(
|
let mut hasher = sha2::Sha256::new();
|
||||||
feature = "aes_gcm",
|
hasher.update(self.cipher_model.to_string().as_bytes());
|
||||||
feature = "server_encrypt",
|
hasher.update(p.as_bytes());
|
||||||
feature = "aes_cbc",
|
hasher.update(self.token.as_bytes());
|
||||||
feature = "aes_ecb",
|
let key: [u8; 32] = hasher.finalize().into();
|
||||||
feature = "sm4_cbc"
|
Some(key[16..].try_into().unwrap())
|
||||||
)))]
|
}
|
||||||
pub fn password_hash(&self) -> Option<[u8; 16]> {
|
}
|
||||||
None
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,6 +172,8 @@ pub enum ErrorType {
|
|||||||
IpAlreadyExists,
|
IpAlreadyExists,
|
||||||
InvalidIp,
|
InvalidIp,
|
||||||
LocalIpExists,
|
LocalIpExists,
|
||||||
|
FailedToCrateDevice,
|
||||||
|
Warn,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,14 +186,23 @@ impl Into<u8> for ErrorType {
|
|||||||
ErrorType::IpAlreadyExists => 4,
|
ErrorType::IpAlreadyExists => 4,
|
||||||
ErrorType::InvalidIp => 5,
|
ErrorType::InvalidIp => 5,
|
||||||
ErrorType::LocalIpExists => 6,
|
ErrorType::LocalIpExists => 6,
|
||||||
|
ErrorType::FailedToCrateDevice => 101,
|
||||||
|
ErrorType::Warn => 102,
|
||||||
ErrorType::Unknown => 255,
|
ErrorType::Unknown => 255,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[derive(Clone, Debug)]
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DeviceConfig {
|
pub struct DeviceConfig {
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub tap: bool,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
pub device_name: Option<String>,
|
||||||
|
//虚拟网卡mtu值
|
||||||
|
pub mtu: u32,
|
||||||
//本机虚拟IP
|
//本机虚拟IP
|
||||||
pub virtual_ip: Ipv4Addr,
|
pub virtual_ip: Ipv4Addr,
|
||||||
//子网掩码
|
//子网掩码
|
||||||
@@ -204,9 +215,15 @@ pub struct DeviceConfig {
|
|||||||
pub external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
|
pub external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
impl DeviceConfig {
|
impl DeviceConfig {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
tap: bool,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
device_name: Option<String>,
|
||||||
|
mtu: u32,
|
||||||
virtual_ip: Ipv4Addr,
|
virtual_ip: Ipv4Addr,
|
||||||
virtual_netmask: Ipv4Addr,
|
virtual_netmask: Ipv4Addr,
|
||||||
virtual_gateway: Ipv4Addr,
|
virtual_gateway: Ipv4Addr,
|
||||||
@@ -214,6 +231,13 @@ impl DeviceConfig {
|
|||||||
external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
|
external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
tap,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
device_name,
|
||||||
|
mtu,
|
||||||
virtual_ip,
|
virtual_ip,
|
||||||
virtual_netmask,
|
virtual_netmask,
|
||||||
virtual_gateway,
|
virtual_gateway,
|
||||||
@@ -223,7 +247,6 @@ impl DeviceConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
impl Display for DeviceConfig {
|
impl Display for DeviceConfig {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(&format!(
|
f.write_str(&format!(
|
||||||
@@ -272,6 +295,7 @@ pub trait VntCallback: Clone + Send + Sync + 'static {
|
|||||||
|
|
||||||
/// 创建网卡的信息
|
/// 创建网卡的信息
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
fn create_tun(&self, _info: DeviceInfo) {}
|
fn create_tun(&self, _info: DeviceInfo) {}
|
||||||
/// 连接
|
/// 连接
|
||||||
fn connect(&self, _info: ConnectInfo) {}
|
fn connect(&self, _info: ConnectInfo) {}
|
||||||
@@ -283,8 +307,11 @@ pub trait VntCallback: Clone + Send + Sync + 'static {
|
|||||||
fn register(&self, _info: RegisterInfo) -> bool {
|
fn register(&self, _info: RegisterInfo) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "integrated_tun"))]
|
||||||
|
fn create_device(&self, _info: DeviceConfig) {}
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
fn generate_tun(&self, _info: DeviceConfig) -> u32 {
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
fn generate_tun(&self, _info: DeviceConfig) -> usize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
fn peer_client_list(&self, _info: Vec<PeerClientInfo>) {}
|
fn peer_client_list(&self, _info: Vec<PeerClientInfo>) {}
|
||||||
|
|||||||
@@ -19,13 +19,6 @@ use crate::proto::message::SecretHandshakeRequest;
|
|||||||
use crate::protocol::body::RSA_ENCRYPTION_RESERVED;
|
use crate::protocol::body::RSA_ENCRYPTION_RESERVED;
|
||||||
use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL};
|
use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL};
|
||||||
|
|
||||||
pub enum HandshakeEnum {
|
|
||||||
NotSecret,
|
|
||||||
KeyError,
|
|
||||||
Timeout,
|
|
||||||
ServerError(String),
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Handshake {
|
pub struct Handshake {
|
||||||
time: Arc<AtomicCell<Instant>>,
|
time: Arc<AtomicCell<Instant>>,
|
||||||
@@ -37,7 +30,11 @@ impl Handshake {
|
|||||||
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Handshake {
|
Handshake {
|
||||||
time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
|
time: Arc::new(AtomicCell::new(
|
||||||
|
Instant::now()
|
||||||
|
.checked_sub(Duration::from_secs(60))
|
||||||
|
.unwrap_or(Instant::now()),
|
||||||
|
)),
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
rsa_cipher,
|
rsa_cipher,
|
||||||
}
|
}
|
||||||
@@ -50,7 +47,7 @@ impl Handshake {
|
|||||||
}
|
}
|
||||||
let request_packet = self.handshake_request_packet(secret)?;
|
let request_packet = self.handshake_request_packet(secret)?;
|
||||||
log::info!("发送握手请求,secret={},{:?}", secret, addr);
|
log::info!("发送握手请求,secret={},{:?}", secret, addr);
|
||||||
context.send_default(request_packet.buffer(), addr)?;
|
context.send_default(&request_packet, addr)?;
|
||||||
self.time.store(Instant::now());
|
self.time.store(Instant::now());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,68 +5,50 @@ use crossbeam_utils::atomic::AtomicCell;
|
|||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::punch::NatType;
|
use crate::channel::punch::NatType;
|
||||||
use crate::cipher::Cipher;
|
|
||||||
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo};
|
use crate::handle::{BaseConfigInfo, CurrentDeviceInfo};
|
||||||
use crate::nat::NatTest;
|
use crate::nat::NatTest;
|
||||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
|
||||||
use crate::protocol::{control_packet, NetPacket, Protocol, MAX_TTL};
|
|
||||||
use crate::util::Scheduler;
|
use crate::util::Scheduler;
|
||||||
|
|
||||||
pub fn addr_request(
|
pub fn addr_request(
|
||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
server_cipher: Cipher,
|
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
_config: BaseConfigInfo,
|
_config: BaseConfigInfo,
|
||||||
) {
|
) {
|
||||||
pub_address_request(
|
pub_address_request(scheduler, context, current_device_info.clone(), nat_test, 0);
|
||||||
scheduler,
|
|
||||||
context,
|
|
||||||
current_device_info.clone(),
|
|
||||||
server_cipher,
|
|
||||||
nat_test,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pub_address_request(
|
fn pub_address_request(
|
||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
server_cipher: Cipher,
|
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
count: usize,
|
count: usize,
|
||||||
) {
|
) {
|
||||||
let channel_num = context.channel_num();
|
let channel_num = context.channel_num();
|
||||||
let index = count % channel_num;
|
let index = count % channel_num;
|
||||||
let mut time = if index == channel_num - 1 { 19 } else { 1 };
|
if let Err(e) = addr_request0(&context, ¤t_device_info, &nat_test, index) {
|
||||||
if let Err(e) = addr_request0(
|
|
||||||
&context,
|
|
||||||
¤t_device_info,
|
|
||||||
&server_cipher,
|
|
||||||
&nat_test,
|
|
||||||
index,
|
|
||||||
) {
|
|
||||||
log::warn!("{:?}", e);
|
log::warn!("{:?}", e);
|
||||||
}
|
}
|
||||||
let nat_info = nat_test.nat_info();
|
let nat_info = nat_test.nat_info();
|
||||||
if nat_info.nat_type == NatType::Symmetric {
|
let time = if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
|
||||||
//对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改)
|
//对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改)
|
||||||
if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
|
if nat_info.nat_type == NatType::Symmetric {
|
||||||
time = 600;
|
600
|
||||||
|
} else {
|
||||||
|
if index == channel_num - 1 {
|
||||||
|
19
|
||||||
|
} else {
|
||||||
|
9
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
let rs = scheduler.timeout(Duration::from_secs(time), move |s| {
|
let rs = scheduler.timeout(Duration::from_secs(time), move |s| {
|
||||||
pub_address_request(
|
pub_address_request(s, context, current_device_info, nat_test, index + 1)
|
||||||
s,
|
|
||||||
context,
|
|
||||||
current_device_info,
|
|
||||||
server_cipher,
|
|
||||||
nat_test,
|
|
||||||
index + 1,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
if !rs {
|
if !rs {
|
||||||
log::info!("定时任务停止");
|
log::info!("定时任务停止");
|
||||||
@@ -76,7 +58,6 @@ fn pub_address_request(
|
|||||||
fn addr_request0(
|
fn addr_request0(
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||||
server_cipher: &Cipher,
|
|
||||||
nat_test: &NatTest,
|
nat_test: &NatTest,
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
@@ -84,24 +65,7 @@ fn addr_request0(
|
|||||||
if current_dev.status.offline() {
|
if current_dev.status.offline() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let (data, addr) = nat_test.send_data()?;
|
||||||
if current_dev.connect_server.is_ipv4() && !context.is_main_tcp() {
|
context.send_main_udp(index, &data, addr)?;
|
||||||
// 如果连接的是ipv4服务,则探测公网端口
|
|
||||||
let gateway_ip = current_dev.virtual_gateway;
|
|
||||||
let src_ip = current_dev.virtual_ip;
|
|
||||||
let mut packet = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED]).unwrap();
|
|
||||||
packet.set_default_version();
|
|
||||||
packet.set_gateway_flag(true);
|
|
||||||
packet.set_protocol(Protocol::Control);
|
|
||||||
packet.set_transport_protocol(control_packet::Protocol::AddrRequest.into());
|
|
||||||
packet.first_set_ttl(MAX_TTL);
|
|
||||||
packet.set_source(src_ip);
|
|
||||||
packet.set_destination(gateway_ip);
|
|
||||||
server_cipher.encrypt_ipv4(&mut packet)?;
|
|
||||||
context.send_main_udp(index, packet.buffer(), current_dev.connect_server)?;
|
|
||||||
} else {
|
|
||||||
let (data, addr) = nat_test.send_data()?;
|
|
||||||
context.send_main_udp(index, &data, addr)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::io;
|
use std::collections::HashMap;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -20,14 +20,14 @@ pub fn heartbeat(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
) {
|
) {
|
||||||
heartbeat0(
|
heartbeat0(
|
||||||
&context,
|
&context,
|
||||||
¤t_device_info.load(),
|
¤t_device_info.load(),
|
||||||
&device_list,
|
&device_map,
|
||||||
&client_cipher,
|
&client_cipher,
|
||||||
&server_cipher,
|
&server_cipher,
|
||||||
);
|
);
|
||||||
@@ -37,7 +37,7 @@ pub fn heartbeat(
|
|||||||
s,
|
s,
|
||||||
context,
|
context,
|
||||||
current_device_info,
|
current_device_info,
|
||||||
device_list,
|
device_map,
|
||||||
client_cipher,
|
client_cipher,
|
||||||
server_cipher,
|
server_cipher,
|
||||||
)
|
)
|
||||||
@@ -50,18 +50,18 @@ pub fn heartbeat(
|
|||||||
fn heartbeat0(
|
fn heartbeat0(
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
|
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
|
||||||
client_cipher: &Cipher,
|
client_cipher: &Cipher,
|
||||||
server_cipher: &Cipher,
|
server_cipher: &Cipher,
|
||||||
) {
|
) {
|
||||||
let gateway_ip = current_device.virtual_gateway;
|
let gateway_ip = current_device.virtual_gateway;
|
||||||
let src_ip = current_device.virtual_ip;
|
let src_ip = current_device.virtual_ip;
|
||||||
|
let channel_num = context.channel_num();
|
||||||
// 可能服务器ip发生变化,导致发送失败
|
// 可能服务器ip发生变化,导致发送失败
|
||||||
let mut is_send_gateway = false;
|
let mut is_send_gateway = false;
|
||||||
match heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip) {
|
match heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip) {
|
||||||
Ok(net_packet) => {
|
Ok(net_packet) => {
|
||||||
if let Err(e) = context.send_default(net_packet.buffer(), current_device.connect_server)
|
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
|
||||||
{
|
|
||||||
log::warn!("heartbeat err={:?}", e)
|
log::warn!("heartbeat err={:?}", e)
|
||||||
} else {
|
} else {
|
||||||
is_send_gateway = true
|
is_send_gateway = true
|
||||||
@@ -77,7 +77,7 @@ fn heartbeat0(
|
|||||||
if is_send_gateway {
|
if is_send_gateway {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip)
|
heartbeat_packet_server(device_map, server_cipher, src_ip, gateway_ip)
|
||||||
} else {
|
} else {
|
||||||
heartbeat_packet_client(client_cipher, src_ip, dest_ip)
|
heartbeat_packet_client(client_cipher, src_ip, dest_ip)
|
||||||
};
|
};
|
||||||
@@ -88,15 +88,24 @@ fn heartbeat0(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for route in routes {
|
for (index, route) in routes.iter().enumerate() {
|
||||||
if let Err(e) = context.send_by_key(net_packet.buffer(), route.route_key()) {
|
let limit = if context.first_latency() {
|
||||||
|
channel_num + 1
|
||||||
|
} else {
|
||||||
|
channel_num
|
||||||
|
};
|
||||||
|
if index >= limit {
|
||||||
|
// 多余的通道不再发送心跳包,让它自动过期
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Err(e) = context.send_by_key(&net_packet, route.route_key()) {
|
||||||
log::warn!("heartbeat err={:?}", e)
|
log::warn!("heartbeat err={:?}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let peer_list = { device_list.lock().1.clone() };
|
let peer_list = { device_map.lock().1.clone() };
|
||||||
for peer in &peer_list {
|
for peer in peer_list.values() {
|
||||||
if !peer.status.is_online() {
|
if !peer.status.is_online() || peer.wireguard {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if current_device.is_gateway(&peer.virtual_ip) {
|
if current_device.is_gateway(&peer.virtual_ip) {
|
||||||
@@ -114,8 +123,7 @@ fn heartbeat0(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(e) = context.send_default(net_packet.buffer(), current_device.connect_server)
|
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
|
||||||
{
|
|
||||||
log::error!("heartbeat_packet send_default err={:?}", e);
|
log::error!("heartbeat_packet send_default err={:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,11 +135,11 @@ pub fn client_relay(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
) {
|
) {
|
||||||
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
|
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
|
||||||
client_relay_(s, context, current_device, device_list, client_cipher)
|
client_relay_(s, context, current_device, device_map, client_cipher)
|
||||||
});
|
});
|
||||||
if !rs {
|
if !rs {
|
||||||
log::info!("定时任务停止");
|
log::info!("定时任务停止");
|
||||||
@@ -143,19 +151,19 @@ fn client_relay_(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
) {
|
) {
|
||||||
if let Err(e) = client_relay0(
|
if let Err(e) = client_relay0(
|
||||||
&context,
|
&context,
|
||||||
¤t_device.load(),
|
¤t_device.load(),
|
||||||
&device_list,
|
&device_map,
|
||||||
&client_cipher,
|
&client_cipher,
|
||||||
) {
|
) {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
}
|
}
|
||||||
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
|
let rs = scheduler.timeout(Duration::from_secs(30), move |s| {
|
||||||
client_relay_(s, context, current_device, device_list, client_cipher)
|
client_relay_(s, context, current_device, device_map, client_cipher)
|
||||||
});
|
});
|
||||||
if !rs {
|
if !rs {
|
||||||
log::info!("定时任务停止");
|
log::info!("定时任务停止");
|
||||||
@@ -165,17 +173,20 @@ fn client_relay_(
|
|||||||
fn client_relay0(
|
fn client_relay0(
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
|
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
|
||||||
client_cipher: &Cipher,
|
client_cipher: &Cipher,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// 离线了不再探测
|
// 离线了不再探测
|
||||||
if current_device.status.offline() {
|
if current_device.status.offline() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let peer_list = { device_list.lock().1.clone() };
|
let peer_list = { device_map.lock().1.clone() };
|
||||||
let mut routes = context.route_table.route_table_p2p();
|
let mut routes = context.route_table.route_table_p2p();
|
||||||
for peer in &peer_list {
|
for peer in peer_list.values() {
|
||||||
if !peer.status.is_online() || peer.virtual_ip == current_device.virtual_ip {
|
if peer.wireguard
|
||||||
|
|| !peer.status.is_online()
|
||||||
|
|| peer.virtual_ip == current_device.virtual_ip
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if context
|
if context
|
||||||
@@ -196,7 +207,7 @@ fn client_relay0(
|
|||||||
if current_device.is_gateway(ip) {
|
if current_device.is_gateway(ip) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Err(e) = context.send_by_key(client_packet.buffer(), route.route_key()) {
|
if let Err(e) = context.send_by_key(&client_packet, route.route_key()) {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
}
|
}
|
||||||
if index >= 2 {
|
if index >= 2 {
|
||||||
@@ -211,7 +222,7 @@ fn client_relay0(
|
|||||||
fn heartbeat_packet(
|
fn heartbeat_packet(
|
||||||
src: Ipv4Addr,
|
src: Ipv4Addr,
|
||||||
dest: Ipv4Addr,
|
dest: Ipv4Addr,
|
||||||
) -> io::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
|
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
|
||||||
let mut net_packet = NetPacket::new_encrypt([0u8; 12 + 4 + ENCRYPTION_RESERVED])?;
|
let mut net_packet = NetPacket::new_encrypt([0u8; 12 + 4 + ENCRYPTION_RESERVED])?;
|
||||||
net_packet.set_default_version();
|
net_packet.set_default_version();
|
||||||
net_packet.set_protocol(Protocol::Control);
|
net_packet.set_protocol(Protocol::Control);
|
||||||
@@ -228,21 +239,21 @@ fn heartbeat_packet_client(
|
|||||||
client_cipher: &Cipher,
|
client_cipher: &Cipher,
|
||||||
src: Ipv4Addr,
|
src: Ipv4Addr,
|
||||||
dest: Ipv4Addr,
|
dest: Ipv4Addr,
|
||||||
) -> io::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
|
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
|
||||||
let mut net_packet = heartbeat_packet(src, dest)?;
|
let mut net_packet = heartbeat_packet(src, dest)?;
|
||||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
Ok(net_packet)
|
Ok(net_packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn heartbeat_packet_server(
|
fn heartbeat_packet_server(
|
||||||
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
|
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
|
||||||
server_cipher: &Cipher,
|
server_cipher: &Cipher,
|
||||||
src: Ipv4Addr,
|
src: Ipv4Addr,
|
||||||
dest: Ipv4Addr,
|
dest: Ipv4Addr,
|
||||||
) -> io::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
|
) -> anyhow::Result<NetPacket<[u8; 12 + 4 + ENCRYPTION_RESERVED]>> {
|
||||||
let mut net_packet = heartbeat_packet(src, dest)?;
|
let mut net_packet = heartbeat_packet(src, dest)?;
|
||||||
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||||
ping.set_epoch(device_list.lock().0);
|
ping.set_epoch(device_map.lock().0);
|
||||||
net_packet.set_gateway_flag(true);
|
net_packet.set_gateway_flag(true);
|
||||||
server_cipher.encrypt_ipv4(&mut net_packet)?;
|
server_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
Ok(net_packet)
|
Ok(net_packet)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use mio::net::TcpStream;
|
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::idle::{Idle, IdleType};
|
use crate::channel::idle::{Idle, IdleType};
|
||||||
use crate::channel::sender::AcceptSocketSender;
|
use crate::channel::sender::ConnectUtil;
|
||||||
|
use crate::channel::socket::LocalInterface;
|
||||||
|
use crate::channel::ConnectProtocol;
|
||||||
use crate::handle::callback::{ConnectInfo, ErrorType};
|
use crate::handle::callback::{ConnectInfo, ErrorType};
|
||||||
use crate::handle::handshaker::Handshake;
|
use crate::handle::handshaker::Handshake;
|
||||||
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
|
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
|
||||||
@@ -36,7 +36,7 @@ pub fn idle_gateway<Call: VntCallback>(
|
|||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
config: BaseConfigInfo,
|
config: BaseConfigInfo,
|
||||||
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
connect_util: ConnectUtil,
|
||||||
call: Call,
|
call: Call,
|
||||||
mut connect_count: usize,
|
mut connect_count: usize,
|
||||||
handshake: Handshake,
|
handshake: Handshake,
|
||||||
@@ -45,18 +45,18 @@ pub fn idle_gateway<Call: VntCallback>(
|
|||||||
&context,
|
&context,
|
||||||
¤t_device_info,
|
¤t_device_info,
|
||||||
&config,
|
&config,
|
||||||
&tcp_socket_sender,
|
&connect_util,
|
||||||
&call,
|
&call,
|
||||||
&mut connect_count,
|
&mut connect_count,
|
||||||
&handshake,
|
&handshake,
|
||||||
);
|
);
|
||||||
let rs = scheduler.timeout(Duration::from_secs(5), move |s| {
|
let rs = scheduler.timeout(Duration::from_secs(8), move |s| {
|
||||||
idle_gateway(
|
idle_gateway(
|
||||||
s,
|
s,
|
||||||
context,
|
context,
|
||||||
current_device_info,
|
current_device_info,
|
||||||
config,
|
config,
|
||||||
tcp_socket_sender,
|
connect_util,
|
||||||
call,
|
call,
|
||||||
connect_count,
|
connect_count,
|
||||||
handshake,
|
handshake,
|
||||||
@@ -71,7 +71,7 @@ fn idle_gateway0<Call: VntCallback>(
|
|||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||||
config: &BaseConfigInfo,
|
config: &BaseConfigInfo,
|
||||||
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
connect_util: &ConnectUtil,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
connect_count: &mut usize,
|
connect_count: &mut usize,
|
||||||
handshake: &Handshake,
|
handshake: &Handshake,
|
||||||
@@ -80,7 +80,7 @@ fn idle_gateway0<Call: VntCallback>(
|
|||||||
context,
|
context,
|
||||||
current_device,
|
current_device,
|
||||||
config,
|
config,
|
||||||
tcp_socket_sender,
|
connect_util,
|
||||||
call,
|
call,
|
||||||
connect_count,
|
connect_count,
|
||||||
handshake,
|
handshake,
|
||||||
@@ -120,7 +120,7 @@ fn check_gateway_channel<Call: VntCallback>(
|
|||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device_info: &AtomicCell<CurrentDeviceInfo>,
|
current_device_info: &AtomicCell<CurrentDeviceInfo>,
|
||||||
config: &BaseConfigInfo,
|
config: &BaseConfigInfo,
|
||||||
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
connect_util: &ConnectUtil,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
count: &mut usize,
|
count: &mut usize,
|
||||||
handshake: &Handshake,
|
handshake: &Handshake,
|
||||||
@@ -128,28 +128,30 @@ fn check_gateway_channel<Call: VntCallback>(
|
|||||||
let mut current_device = current_device_info.load();
|
let mut current_device = current_device_info.load();
|
||||||
if current_device.status.offline() {
|
if current_device.status.offline() {
|
||||||
*count += 1;
|
*count += 1;
|
||||||
// 探测服务器地址
|
let connect_protocol = context.main_protocol();
|
||||||
current_device = domain_request0(current_device_info, config);
|
if connect_protocol.is_transport() {
|
||||||
|
// 传输层的协议需要探测服务器地址
|
||||||
|
current_device =
|
||||||
|
domain_request0(current_device_info, config, context.default_interface());
|
||||||
|
}
|
||||||
//需要重连
|
//需要重连
|
||||||
call.connect(ConnectInfo::new(*count, current_device.connect_server));
|
call.connect(ConnectInfo::new(*count, current_device.connect_server));
|
||||||
log::info!("发送握手请求,{:?}", config);
|
log::info!("发送握手请求,{:?}", config);
|
||||||
if let Err(e) = handshake.send(context, config.server_secret, current_device.connect_server)
|
if let Err(e) = handshake.send(context, config.server_secret, current_device.connect_server)
|
||||||
{
|
{
|
||||||
log::warn!("{:?}", e);
|
log::warn!("{:?}", e);
|
||||||
if context.is_main_tcp() {
|
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
|
||||||
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
|
match connect_protocol {
|
||||||
//tcp需要重连
|
ConnectProtocol::UDP => {}
|
||||||
let tcp_stream = std::net::TcpStream::connect_timeout(
|
ConnectProtocol::TCP => {
|
||||||
¤t_device.connect_server,
|
connect_util.try_connect_tcp(
|
||||||
Duration::from_secs(5),
|
request_packet.into_buffer(),
|
||||||
)?;
|
current_device.connect_server,
|
||||||
tcp_stream.set_nonblocking(true)?;
|
);
|
||||||
if let Err(e) = tcp_socket_sender.try_add_socket((
|
}
|
||||||
TcpStream::from_std(tcp_stream),
|
ConnectProtocol::WS | ConnectProtocol::WSS => {
|
||||||
current_device.connect_server,
|
connect_util
|
||||||
Some(request_packet.into_buffer()),
|
.try_connect_ws(request_packet.into_buffer(), config.server_addr.clone());
|
||||||
)) {
|
|
||||||
log::warn!("{:?}", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,11 +162,16 @@ fn check_gateway_channel<Call: VntCallback>(
|
|||||||
pub fn domain_request0(
|
pub fn domain_request0(
|
||||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||||
config: &BaseConfigInfo,
|
config: &BaseConfigInfo,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
) -> CurrentDeviceInfo {
|
) -> CurrentDeviceInfo {
|
||||||
let mut current_dev = current_device.load();
|
let mut current_dev = current_device.load();
|
||||||
|
|
||||||
// 探测服务端地址变化
|
// 探测服务端地址变化
|
||||||
match dns_query_all(&config.server_addr, config.name_servers.clone()) {
|
match dns_query_all(
|
||||||
|
&config.server_addr,
|
||||||
|
config.name_servers.clone(),
|
||||||
|
default_interface,
|
||||||
|
) {
|
||||||
Ok(addrs) => {
|
Ok(addrs) => {
|
||||||
log::info!(
|
log::info!(
|
||||||
"domain {} dns {:?} addr {:?}",
|
"domain {} dns {:?} addr {:?}",
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::ops::{Div, Mul};
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{io, thread};
|
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
@@ -88,7 +90,7 @@ pub fn punch(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
receiver: PunchReceiver,
|
receiver: PunchReceiver,
|
||||||
@@ -100,7 +102,7 @@ pub fn punch(
|
|||||||
scheduler,
|
scheduler,
|
||||||
context,
|
context,
|
||||||
nat_test,
|
nat_test,
|
||||||
device_list,
|
device_map,
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
client_cipher.clone(),
|
client_cipher.clone(),
|
||||||
0,
|
0,
|
||||||
@@ -147,7 +149,7 @@ fn punch_start(
|
|||||||
*v += 1;
|
*v += 1;
|
||||||
*v
|
*v
|
||||||
} else {
|
} else {
|
||||||
guard.insert(peer_ip, 1);
|
guard.insert(peer_ip, 0);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -157,7 +159,7 @@ fn punch_start(
|
|||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info, count < 2) {
|
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info, count < 2, count) {
|
||||||
log::warn!("{:?}", e)
|
log::warn!("{:?}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,19 +170,19 @@ fn punch_request(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
count: usize,
|
count: usize,
|
||||||
punch_record: Arc<Mutex<HashMap<Ipv4Addr, usize>>>,
|
punch_record: Arc<Mutex<HashMap<Ipv4Addr, usize>>>,
|
||||||
mut last_punch_record: HashMap<Ipv4Addr, usize>,
|
mut last_punch_record: HashMap<Ipv4Addr, PunchRecordItem>,
|
||||||
) {
|
) {
|
||||||
let curr = current_device.load();
|
let curr = current_device.load();
|
||||||
let secs = if curr.status.online() {
|
let secs = if curr.status.online() {
|
||||||
if let Err(e) = punch0(
|
if let Err(e) = punch0(
|
||||||
&context,
|
&context,
|
||||||
&nat_test,
|
&nat_test,
|
||||||
&device_list,
|
&device_map,
|
||||||
curr,
|
curr,
|
||||||
&client_cipher,
|
&client_cipher,
|
||||||
&punch_record,
|
&punch_record,
|
||||||
@@ -189,7 +191,7 @@ fn punch_request(
|
|||||||
) {
|
) {
|
||||||
log::warn!("{:?}", e)
|
log::warn!("{:?}", e)
|
||||||
}
|
}
|
||||||
let sleep_time = [5, 6, 7];
|
let sleep_time = [6, 7];
|
||||||
Duration::from_secs(sleep_time[count % sleep_time.len()])
|
Duration::from_secs(sleep_time[count % sleep_time.len()])
|
||||||
} else {
|
} else {
|
||||||
Duration::from_secs(5)
|
Duration::from_secs(5)
|
||||||
@@ -199,7 +201,7 @@ fn punch_request(
|
|||||||
s,
|
s,
|
||||||
context,
|
context,
|
||||||
nat_test,
|
nat_test,
|
||||||
device_list,
|
device_map,
|
||||||
current_device,
|
current_device,
|
||||||
client_cipher,
|
client_cipher,
|
||||||
count + 1,
|
count + 1,
|
||||||
@@ -211,18 +213,23 @@ fn punch_request(
|
|||||||
log::info!("定时任务停止");
|
log::info!("定时任务停止");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
struct PunchRecordItem {
|
||||||
|
pub punch_record: usize,
|
||||||
|
pub last_p2p_num: usize,
|
||||||
|
}
|
||||||
|
|
||||||
/// 随机对需要打洞的客户端发起打洞请求
|
/// 随机对需要打洞的客户端发起打洞请求
|
||||||
fn punch0(
|
fn punch0(
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
nat_test: &NatTest,
|
nat_test: &NatTest,
|
||||||
device_list: &Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: &Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
current_device: CurrentDeviceInfo,
|
current_device: CurrentDeviceInfo,
|
||||||
client_cipher: &Cipher,
|
client_cipher: &Cipher,
|
||||||
punch_record: &Mutex<HashMap<Ipv4Addr, usize>>,
|
punch_record: &Mutex<HashMap<Ipv4Addr, usize>>,
|
||||||
last_punch_record: &mut HashMap<Ipv4Addr, usize>,
|
last_punch_record: &mut HashMap<Ipv4Addr, PunchRecordItem>,
|
||||||
total_count: usize,
|
total_count: usize,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let nat_info = nat_test.nat_info();
|
let nat_info = nat_test.nat_info();
|
||||||
if total_count < 10
|
if total_count < 10
|
||||||
&& (nat_info.public_ips.is_empty()
|
&& (nat_info.public_ips.is_empty()
|
||||||
@@ -231,33 +238,39 @@ fn punch0(
|
|||||||
|| nat_info.public_ports.iter().filter(|&&v| v == 0).count()
|
|| nat_info.public_ports.iter().filter(|&&v| v == 0).count()
|
||||||
> nat_info.public_ports.len() / 2)
|
> nat_info.public_ports.len() / 2)
|
||||||
{
|
{
|
||||||
log::info!("公网地址为空,暂时放弃打洞,第{}轮", total_count);
|
log::info!("未获取到公网地址,暂时放弃打洞,第{}轮", total_count);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let current_ip = current_device.virtual_ip;
|
let current_ip = current_device.virtual_ip;
|
||||||
let mut list: Vec<PeerDeviceInfo> = device_list
|
let mut list: Vec<PeerDeviceInfo> = device_map
|
||||||
.lock()
|
.lock()
|
||||||
.1
|
.1
|
||||||
.iter()
|
.values()
|
||||||
.filter(|info| info.status.is_online() && info.virtual_ip > current_ip)
|
.filter(|info| !info.wireguard && info.virtual_ip > current_ip)
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
list.shuffle(&mut rand::thread_rng());
|
list.shuffle(&mut rand::thread_rng());
|
||||||
for info in list {
|
for info in list {
|
||||||
let punch_count = punch_record
|
if info.status.is_offline() {
|
||||||
|
// 客户端掉线了要重置打洞记录
|
||||||
|
punch_record.lock().remove(&info.virtual_ip);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut punch_count = punch_record
|
||||||
.lock()
|
.lock()
|
||||||
.get(&info.virtual_ip)
|
.get(&info.virtual_ip)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0)
|
||||||
|
.mul(2)
|
||||||
|
.div(3);
|
||||||
let p2p_num = context.route_table.p2p_num(&info.virtual_ip);
|
let p2p_num = context.route_table.p2p_num(&info.virtual_ip);
|
||||||
let mut max_punch_interval = 70;
|
let mut max_punch_interval = 50;
|
||||||
if p2p_num > 0 {
|
if p2p_num > 0 {
|
||||||
if punch_count == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if p2p_num >= context.channel_num() {
|
if p2p_num >= context.channel_num() {
|
||||||
//通道数满足要求,不再打洞
|
//通道数满足要求,不再打洞
|
||||||
punch_record.lock().remove(&info.virtual_ip);
|
if punch_count != 0 {
|
||||||
|
punch_record.lock().remove(&info.virtual_ip);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//有p2p通道,但是通道数量不够,则继续打洞
|
//有p2p通道,但是通道数量不够,则继续打洞
|
||||||
@@ -265,13 +278,18 @@ fn punch0(
|
|||||||
max_punch_interval = 300;
|
max_punch_interval = 300;
|
||||||
}
|
}
|
||||||
// 能发起打洞的前提是自己空闲,这里会间隔5秒以上发起一次打洞,所以假定上一轮打洞已结束
|
// 能发起打洞的前提是自己空闲,这里会间隔5秒以上发起一次打洞,所以假定上一轮打洞已结束
|
||||||
let last_punch = last_punch_record
|
let last_punch = last_punch_record.entry(info.virtual_ip).or_default();
|
||||||
.get(&info.virtual_ip)
|
if last_punch.last_p2p_num > p2p_num {
|
||||||
.cloned()
|
// 打的洞掉线了,需要重置重新打
|
||||||
.unwrap_or(0);
|
punch_record.lock().remove(&info.virtual_ip);
|
||||||
|
punch_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 梯度增加打洞时间间隔
|
// 梯度增加打洞时间间隔
|
||||||
if total_count > last_punch + punch_count.min(max_punch_interval) {
|
if total_count > last_punch.punch_record + punch_count.min(max_punch_interval) {
|
||||||
last_punch_record.insert(info.virtual_ip, total_count);
|
// 记录打洞周期,抑制下一次打洞,从而递减打洞频率
|
||||||
|
last_punch.punch_record = total_count;
|
||||||
|
last_punch.last_p2p_num = p2p_num;
|
||||||
let packet = punch_packet(
|
let packet = punch_packet(
|
||||||
client_cipher,
|
client_cipher,
|
||||||
current_device.virtual_ip(),
|
current_device.virtual_ip(),
|
||||||
@@ -285,7 +303,7 @@ fn punch0(
|
|||||||
punch_count,
|
punch_count,
|
||||||
total_count,
|
total_count,
|
||||||
);
|
);
|
||||||
context.send_default(packet.buffer(), current_device.connect_server)?;
|
context.send_default(&packet, current_device.connect_server)?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +315,7 @@ fn punch_packet(
|
|||||||
virtual_ip: Ipv4Addr,
|
virtual_ip: Ipv4Addr,
|
||||||
nat_info: &NatInfo,
|
nat_info: &NatInfo,
|
||||||
dest: Ipv4Addr,
|
dest: Ipv4Addr,
|
||||||
) -> io::Result<NetPacket<Vec<u8>>> {
|
) -> anyhow::Result<NetPacket<Vec<u8>>> {
|
||||||
let mut punch_reply = PunchInfo::new();
|
let mut punch_reply = PunchInfo::new();
|
||||||
punch_reply.reply = false;
|
punch_reply.reply = false;
|
||||||
punch_reply.public_ip_list = nat_info
|
punch_reply.public_ip_list = nat_info
|
||||||
@@ -308,6 +326,7 @@ fn punch_packet(
|
|||||||
punch_reply.public_port = nat_info.public_ports.get(0).map_or(0, |v| *v as u32);
|
punch_reply.public_port = nat_info.public_ports.get(0).map_or(0, |v| *v as u32);
|
||||||
punch_reply.public_ports = nat_info.public_ports.iter().map(|e| *e as u32).collect();
|
punch_reply.public_ports = nat_info.public_ports.iter().map(|e| *e as u32).collect();
|
||||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||||
|
punch_reply.public_tcp_port = nat_info.public_tcp_port as u32;
|
||||||
punch_reply.local_ip = u32::from(nat_info.local_ipv4().unwrap_or(Ipv4Addr::UNSPECIFIED));
|
punch_reply.local_ip = u32::from(nat_info.local_ipv4().unwrap_or(Ipv4Addr::UNSPECIFIED));
|
||||||
punch_reply.local_port = nat_info.udp_ports[0] as u32;
|
punch_reply.local_port = nat_info.udp_ports[0] as u32;
|
||||||
punch_reply.tcp_port = nat_info.tcp_port as u32;
|
punch_reply.tcp_port = nat_info.tcp_port as u32;
|
||||||
@@ -317,10 +336,11 @@ fn punch_packet(
|
|||||||
punch_reply.ipv6 = ipv6.octets().to_vec();
|
punch_reply.ipv6 = ipv6.octets().to_vec();
|
||||||
}
|
}
|
||||||
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
punch_reply.nat_type = protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||||
|
punch_reply.punch_model = protobuf::EnumOrUnknown::new(nat_info.punch_model.into());
|
||||||
log::info!("请求打洞={:?}", punch_reply);
|
log::info!("请求打洞={:?}", punch_reply);
|
||||||
let bytes = punch_reply
|
let bytes = punch_reply
|
||||||
.write_to_bytes()
|
.write_to_bytes()
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("punch_packet {:?}", e)))?;
|
.map_err(|e| anyhow!("punch_packet {:?}", e))?;
|
||||||
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
|
let mut net_packet = NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
|
||||||
net_packet.set_default_version();
|
net_packet.set_default_version();
|
||||||
net_packet.set_protocol(Protocol::OtherTurn);
|
net_packet.set_protocol(Protocol::OtherTurn);
|
||||||
|
|||||||
@@ -29,9 +29,13 @@ fn retrieve_nat_type0(
|
|||||||
.name("natTest".into())
|
.name("natTest".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
if nat_test.can_update() {
|
if nat_test.can_update() {
|
||||||
let local_ipv4 = nat::local_ipv4();
|
let local_ipv4 = if nat_test.update_local_ipv4 {
|
||||||
|
nat::local_ipv4()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let local_ipv6 = nat::local_ipv6();
|
let local_ipv6 = nat::local_ipv6();
|
||||||
match nat_test.re_test(local_ipv4, local_ipv6) {
|
match nat_test.re_test(local_ipv4, local_ipv6, context.default_interface()) {
|
||||||
Ok(nat_info) => {
|
Ok(nat_info) => {
|
||||||
log::info!("当前nat信息:{:?}", nat_info);
|
log::info!("当前nat信息:{:?}", nat_info);
|
||||||
if let Err(e) = context.switch(nat_info.nat_type, &udp_socket_sender) {
|
if let Err(e) = context.switch(nat_info.nat_type, &udp_socket_sender) {
|
||||||
@@ -42,6 +46,9 @@ fn retrieve_nat_type0(
|
|||||||
log::warn!("nat re_test {:?}", e);
|
log::warn!("nat re_test {:?}", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
nat_test.reset_upnp();
|
||||||
|
log::info!("刷新nat结束")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect("natTest");
|
.expect("natTest");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::handle::CurrentDeviceInfo;
|
|||||||
use crate::proto::message::{ClientStatusInfo, PunchNatType, RouteItem};
|
use crate::proto::message::{ClientStatusInfo, PunchNatType, RouteItem};
|
||||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||||
use crate::protocol::{service_packet, NetPacket, Protocol, HEAD_LEN, MAX_TTL};
|
use crate::protocol::{service_packet, NetPacket, Protocol, HEAD_LEN, MAX_TTL};
|
||||||
use crate::util::{Scheduler, WatchSingleU64Adder, WatchU64Adder};
|
use crate::util::Scheduler;
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -15,17 +15,9 @@ pub fn up_status(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
down_count_watcher: WatchU64Adder,
|
|
||||||
up_count_watcher: WatchSingleU64Adder,
|
|
||||||
) {
|
) {
|
||||||
let _ = scheduler.timeout(Duration::from_secs(60), move |x| {
|
let _ = scheduler.timeout(Duration::from_secs(60), move |x| {
|
||||||
up_status0(
|
up_status0(x, context, current_device_info)
|
||||||
x,
|
|
||||||
context,
|
|
||||||
current_device_info,
|
|
||||||
down_count_watcher,
|
|
||||||
up_count_watcher,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,25 +25,12 @@ fn up_status0(
|
|||||||
scheduler: &Scheduler,
|
scheduler: &Scheduler,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
down_count_watcher: WatchU64Adder,
|
|
||||||
up_count_watcher: WatchSingleU64Adder,
|
|
||||||
) {
|
) {
|
||||||
if let Err(e) = send_up_status_packet(
|
if let Err(e) = send_up_status_packet(&context, ¤t_device_info) {
|
||||||
&context,
|
|
||||||
¤t_device_info,
|
|
||||||
&down_count_watcher,
|
|
||||||
&up_count_watcher,
|
|
||||||
) {
|
|
||||||
log::warn!("{:?}", e)
|
log::warn!("{:?}", e)
|
||||||
}
|
}
|
||||||
let rs = scheduler.timeout(Duration::from_secs(10 * 60), move |x| {
|
let rs = scheduler.timeout(Duration::from_secs(10 * 60), move |x| {
|
||||||
up_status0(
|
up_status0(x, context, current_device_info)
|
||||||
x,
|
|
||||||
context,
|
|
||||||
current_device_info,
|
|
||||||
down_count_watcher,
|
|
||||||
up_count_watcher,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
if !rs {
|
if !rs {
|
||||||
log::info!("定时任务停止");
|
log::info!("定时任务停止");
|
||||||
@@ -61,8 +40,6 @@ fn up_status0(
|
|||||||
fn send_up_status_packet(
|
fn send_up_status_packet(
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device_info: &AtomicCell<CurrentDeviceInfo>,
|
current_device_info: &AtomicCell<CurrentDeviceInfo>,
|
||||||
down_count_watcher: &WatchU64Adder,
|
|
||||||
up_count_watcher: &WatchSingleU64Adder,
|
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let device_info = current_device_info.load();
|
let device_info = current_device_info.load();
|
||||||
if device_info.status.offline() {
|
if device_info.status.offline() {
|
||||||
@@ -79,8 +56,8 @@ fn send_up_status_packet(
|
|||||||
item.next_ip = ip.into();
|
item.next_ip = ip.into();
|
||||||
message.p2p_list.push(item);
|
message.p2p_list.push(item);
|
||||||
}
|
}
|
||||||
message.up_stream = up_count_watcher.get();
|
message.up_stream = context.up_traffic_meter.as_ref().map_or(0, |v| v.total());
|
||||||
message.down_stream = down_count_watcher.get();
|
message.down_stream = context.down_traffic_meter.as_ref().map_or(0, |v| v.total());
|
||||||
message.nat_type = protobuf::EnumOrUnknown::new(if context.is_cone() {
|
message.nat_type = protobuf::EnumOrUnknown::new(if context.is_cone() {
|
||||||
PunchNatType::Cone
|
PunchNatType::Cone
|
||||||
} else {
|
} else {
|
||||||
@@ -99,6 +76,6 @@ fn send_up_status_packet(
|
|||||||
net_packet.set_source(device_info.virtual_ip);
|
net_packet.set_source(device_info.virtual_ip);
|
||||||
net_packet.set_destination(device_info.virtual_gateway);
|
net_packet.set_destination(device_info.virtual_gateway);
|
||||||
net_packet.set_payload(&buf)?;
|
net_packet.set_payload(&buf)?;
|
||||||
context.send_default(net_packet.buffer(), device_info.connect_server)?;
|
context.send_default(&net_packet, device_info.connect_server)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-10
@@ -1,5 +1,6 @@
|
|||||||
|
use crate::channel::socket::LocalInterface;
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
pub mod callback;
|
pub mod callback;
|
||||||
mod extension;
|
mod extension;
|
||||||
@@ -7,6 +8,7 @@ pub mod handshaker;
|
|||||||
pub mod maintain;
|
pub mod maintain;
|
||||||
pub mod recv_data;
|
pub mod recv_data;
|
||||||
pub mod registrar;
|
pub mod registrar;
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
pub mod tun_tap;
|
pub mod tun_tap;
|
||||||
|
|
||||||
const SELF_IP: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 2);
|
const SELF_IP: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 2);
|
||||||
@@ -21,12 +23,6 @@ pub fn now_time() -> u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 是否在一个网段
|
|
||||||
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
|
|
||||||
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(virtual_netmask.octets())
|
|
||||||
== u32::from_be_bytes(virtual_network.octets())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct PeerDeviceInfo {
|
pub struct PeerDeviceInfo {
|
||||||
pub virtual_ip: Ipv4Addr,
|
pub virtual_ip: Ipv4Addr,
|
||||||
@@ -34,6 +30,7 @@ pub struct PeerDeviceInfo {
|
|||||||
pub status: PeerDeviceStatus,
|
pub status: PeerDeviceStatus,
|
||||||
pub client_secret: bool,
|
pub client_secret: bool,
|
||||||
pub client_secret_hash: Vec<u8>,
|
pub client_secret_hash: Vec<u8>,
|
||||||
|
pub wireguard: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PeerDeviceInfo {
|
impl PeerDeviceInfo {
|
||||||
@@ -43,6 +40,7 @@ impl PeerDeviceInfo {
|
|||||||
status: u8,
|
status: u8,
|
||||||
client_secret: bool,
|
client_secret: bool,
|
||||||
client_secret_hash: Vec<u8>,
|
client_secret_hash: Vec<u8>,
|
||||||
|
wireguard: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
virtual_ip,
|
virtual_ip,
|
||||||
@@ -50,6 +48,7 @@ impl PeerDeviceInfo {
|
|||||||
status: PeerDeviceStatus::from(status),
|
status: PeerDeviceStatus::from(status),
|
||||||
client_secret,
|
client_secret,
|
||||||
client_secret_hash,
|
client_secret_hash,
|
||||||
|
wireguard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,6 +63,15 @@ pub struct BaseConfigInfo {
|
|||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
pub server_addr: String,
|
pub server_addr: String,
|
||||||
pub name_servers: Vec<String>,
|
pub name_servers: Vec<String>,
|
||||||
|
pub mtu: u32,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub tap: bool,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
pub device_name: Option<String>,
|
||||||
|
pub allow_wire_guard: bool,
|
||||||
|
pub default_interface: LocalInterface,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BaseConfigInfo {
|
impl BaseConfigInfo {
|
||||||
@@ -76,6 +84,15 @@ impl BaseConfigInfo {
|
|||||||
device_id: String,
|
device_id: String,
|
||||||
server_addr: String,
|
server_addr: String,
|
||||||
name_servers: Vec<String>,
|
name_servers: Vec<String>,
|
||||||
|
mtu: u32,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
tap: bool,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
device_name: Option<String>,
|
||||||
|
allow_wire_guard: bool,
|
||||||
|
default_interface: LocalInterface,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
@@ -86,6 +103,15 @@ impl BaseConfigInfo {
|
|||||||
device_id,
|
device_id,
|
||||||
server_addr,
|
server_addr,
|
||||||
name_servers,
|
name_servers,
|
||||||
|
mtu,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
tap,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
device_name,
|
||||||
|
allow_wire_guard,
|
||||||
|
default_interface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,6 +126,9 @@ impl PeerDeviceStatus {
|
|||||||
pub fn is_online(&self) -> bool {
|
pub fn is_online(&self) -> bool {
|
||||||
self == &PeerDeviceStatus::Online
|
self == &PeerDeviceStatus::Online
|
||||||
}
|
}
|
||||||
|
pub fn is_offline(&self) -> bool {
|
||||||
|
self == &PeerDeviceStatus::Offline
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u8> for PeerDeviceStatus {
|
impl Into<u8> for PeerDeviceStatus {
|
||||||
@@ -194,10 +223,10 @@ impl CurrentDeviceInfo {
|
|||||||
virtual_gateway: Ipv4Addr,
|
virtual_gateway: Ipv4Addr,
|
||||||
) {
|
) {
|
||||||
let broadcast_ip = (!u32::from_be_bytes(virtual_netmask.octets()))
|
let broadcast_ip = (!u32::from_be_bytes(virtual_netmask.octets()))
|
||||||
| u32::from_be_bytes(virtual_gateway.octets());
|
| u32::from_be_bytes(virtual_ip.octets());
|
||||||
let broadcast_ip = Ipv4Addr::from(broadcast_ip);
|
let broadcast_ip = Ipv4Addr::from(broadcast_ip);
|
||||||
let virtual_network = u32::from_be_bytes(virtual_netmask.octets())
|
let virtual_network =
|
||||||
& u32::from_be_bytes(virtual_gateway.octets());
|
u32::from_be_bytes(virtual_netmask.octets()) & u32::from_be_bytes(virtual_ip.octets());
|
||||||
let virtual_network = Ipv4Addr::from(virtual_network);
|
let virtual_network = Ipv4Addr::from(virtual_network);
|
||||||
self.virtual_ip = virtual_ip;
|
self.virtual_ip = virtual_ip;
|
||||||
self.virtual_netmask = virtual_netmask;
|
self.virtual_netmask = virtual_netmask;
|
||||||
@@ -213,9 +242,24 @@ impl CurrentDeviceInfo {
|
|||||||
pub fn virtual_gateway(&self) -> Ipv4Addr {
|
pub fn virtual_gateway(&self) -> Ipv4Addr {
|
||||||
self.virtual_gateway
|
self.virtual_gateway
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
|
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
|
||||||
&self.virtual_gateway == ip || ip == &GATEWAY_IP
|
&self.virtual_gateway == ip || ip == &GATEWAY_IP
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn not_in_network(&self, ip: Ipv4Addr) -> bool {
|
||||||
|
u32::from(ip) & u32::from(self.virtual_netmask) != u32::from(self.virtual_network)
|
||||||
|
}
|
||||||
|
pub fn is_server_addr(&self, addr: SocketAddr) -> bool {
|
||||||
|
if self.connect_server == addr {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let f = |ip: IpAddr| match ip {
|
||||||
|
IpAddr::V4(v4) => Some(v4),
|
||||||
|
IpAddr::V6(v6) => v6.to_ipv4(),
|
||||||
|
};
|
||||||
|
addr.port() == self.connect_server.port() && f(addr.ip()) == f(self.connect_server.ip())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn change_status(
|
pub fn change_status(
|
||||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use parking_lot::RwLock;
|
use anyhow::anyhow;
|
||||||
use protobuf::Message;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use protobuf::Message;
|
||||||
|
|
||||||
use packet::icmp::{icmp, Kind};
|
use packet::icmp::{icmp, Kind};
|
||||||
use packet::ip::ipv4;
|
use packet::ip::ipv4;
|
||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
@@ -27,32 +28,33 @@ use crate::protocol::control_packet::ControlPacket;
|
|||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
control_packet, ip_turn_packet, other_turn_packet, NetPacket, Protocol, MAX_TTL,
|
control_packet, ip_turn_packet, other_turn_packet, NetPacket, Protocol, MAX_TTL,
|
||||||
};
|
};
|
||||||
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
use tun::device::IFace;
|
|
||||||
|
|
||||||
/// 处理来源于客户端的包
|
/// 处理来源于客户端的包
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ClientPacketHandler {
|
pub struct ClientPacketHandler<Device> {
|
||||||
device: DeviceAdapter,
|
device: Device,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
punch_sender: PunchSender,
|
punch_sender: PunchSender,
|
||||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
route: AllowExternalRoute,
|
route: AllowExternalRoute,
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
ip_proxy_map: Option<IpProxyMap>,
|
ip_proxy_map: Option<IpProxyMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacketHandler {
|
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: DeviceAdapter,
|
device: Device,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
punch_sender: PunchSender,
|
punch_sender: PunchSender,
|
||||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
route: AllowExternalRoute,
|
route: AllowExternalRoute,
|
||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
ip_proxy_map: Option<IpProxyMap>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
device,
|
device,
|
||||||
@@ -61,13 +63,14 @@ impl ClientPacketHandler {
|
|||||||
peer_nat_info_map,
|
peer_nat_info_map,
|
||||||
nat_test,
|
nat_test,
|
||||||
route,
|
route,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
ip_proxy_map,
|
ip_proxy_map,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketHandler for ClientPacketHandler {
|
impl<Device: DeviceWrite> PacketHandler for ClientPacketHandler<Device> {
|
||||||
fn handle(
|
fn handle(
|
||||||
&self,
|
&self,
|
||||||
mut net_packet: NetPacket<&mut [u8]>,
|
mut net_packet: NetPacket<&mut [u8]>,
|
||||||
@@ -109,14 +112,14 @@ impl PacketHandler for ClientPacketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacketHandler {
|
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||||
fn ip_turn(
|
fn ip_turn(
|
||||||
&self,
|
&self,
|
||||||
mut net_packet: NetPacket<&mut [u8]>,
|
mut net_packet: NetPacket<&mut [u8]>,
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let destination = net_packet.destination();
|
let destination = net_packet.destination();
|
||||||
let source = net_packet.source();
|
let source = net_packet.source();
|
||||||
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||||
@@ -137,7 +140,7 @@ impl ClientPacketHandler {
|
|||||||
net_packet.set_destination(source);
|
net_packet.set_destination(source);
|
||||||
//不管加不加密,和接收到的数据长度都一致
|
//不管加不加密,和接收到的数据长度都一致
|
||||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
context.send_by_key(net_packet.buffer(), route_key)?;
|
context.send_by_key(&net_packet, route_key)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,6 +185,7 @@ impl ClientPacketHandler {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
if let Some(ip_proxy_map) = &self.ip_proxy_map {
|
if let Some(ip_proxy_map) = &self.ip_proxy_map {
|
||||||
if ip_proxy_map.recv_handle(&mut ipv4, source, destination)? {
|
if ip_proxy_map.recv_handle(&mut ipv4, source, destination)? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -190,6 +194,9 @@ impl ClientPacketHandler {
|
|||||||
}
|
}
|
||||||
self.device.write(net_packet.payload())?;
|
self.device.write(net_packet.payload())?;
|
||||||
}
|
}
|
||||||
|
ip_turn_packet::Protocol::WGIpv4 => {
|
||||||
|
// WG客户端的数据不会直接发过来,不用处理
|
||||||
|
}
|
||||||
ip_turn_packet::Protocol::Ipv4Broadcast => {
|
ip_turn_packet::Protocol::Ipv4Broadcast => {
|
||||||
//客户端不帮忙转发广播包,所以不会出现这种类型的数据
|
//客户端不帮忙转发广播包,所以不会出现这种类型的数据
|
||||||
}
|
}
|
||||||
@@ -203,19 +210,19 @@ impl ClientPacketHandler {
|
|||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
mut net_packet: NetPacket<&mut [u8]>,
|
mut net_packet: NetPacket<&mut [u8]>,
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
||||||
let source = net_packet.source();
|
let source = net_packet.source();
|
||||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||||
ControlPacket::PingPacket(_) => {
|
ControlPacket::PingPacket(_) => {
|
||||||
|
let route = Route::from_default_rt(route_key, metric);
|
||||||
|
context.route_table.add_route_if_absent(source, route);
|
||||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||||
net_packet.set_source(current_device.virtual_ip);
|
net_packet.set_source(current_device.virtual_ip);
|
||||||
net_packet.set_destination(source);
|
net_packet.set_destination(source);
|
||||||
net_packet.first_set_ttl(MAX_TTL);
|
net_packet.first_set_ttl(MAX_TTL);
|
||||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
context.send_by_key(net_packet.buffer(), route_key)?;
|
context.send_by_key(&net_packet, route_key)?;
|
||||||
let route = Route::from_default_rt(route_key, metric);
|
|
||||||
context.route_table.add_route_if_absent(source, route);
|
|
||||||
}
|
}
|
||||||
ControlPacket::PongPacket(pong_packet) => {
|
ControlPacket::PongPacket(pong_packet) => {
|
||||||
let current_time = crate::handle::now_time() as u16;
|
let current_time = crate::handle::now_time() as u16;
|
||||||
@@ -234,7 +241,7 @@ impl ClientPacketHandler {
|
|||||||
//忽略掉来源于自己的包
|
//忽略掉来源于自己的包
|
||||||
if self
|
if self
|
||||||
.nat_test
|
.nat_test
|
||||||
.is_local_address(route_key.is_tcp(), route_key.addr)
|
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -245,7 +252,7 @@ impl ClientPacketHandler {
|
|||||||
net_packet.set_destination(source);
|
net_packet.set_destination(source);
|
||||||
net_packet.first_set_ttl(1);
|
net_packet.first_set_ttl(1);
|
||||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
context.send_by_key(net_packet.buffer(), route_key)?;
|
context.send_by_key(&net_packet, route_key)?;
|
||||||
// 收到PunchRequest就添加路由,会导致单向通信的问题,删掉试试
|
// 收到PunchRequest就添加路由,会导致单向通信的问题,删掉试试
|
||||||
// let route = Route::from_default_rt(route_key, 1);
|
// let route = Route::from_default_rt(route_key, 1);
|
||||||
// context.route_table.add_route_if_absent(source, route);
|
// context.route_table.add_route_if_absent(source, route);
|
||||||
@@ -257,11 +264,11 @@ impl ClientPacketHandler {
|
|||||||
}
|
}
|
||||||
if self
|
if self
|
||||||
.nat_test
|
.nat_test
|
||||||
.is_local_address(route_key.is_tcp(), route_key.addr)
|
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let route = Route::from_default_rt(route_key, 1);
|
let route = Route::from_default_rt(route_key, metric);
|
||||||
context.route_table.add_route_if_absent(source, route);
|
context.route_table.add_route_if_absent(source, route);
|
||||||
}
|
}
|
||||||
ControlPacket::AddrRequest => match route_key.addr.ip() {
|
ControlPacket::AddrRequest => match route_key.addr.ip() {
|
||||||
@@ -277,7 +284,7 @@ impl ClientPacketHandler {
|
|||||||
addr_packet.set_ipv4(ipv4);
|
addr_packet.set_ipv4(ipv4);
|
||||||
addr_packet.set_port(route_key.addr.port());
|
addr_packet.set_port(route_key.addr.port());
|
||||||
self.client_cipher.encrypt_ipv4(&mut packet)?;
|
self.client_cipher.encrypt_ipv4(&mut packet)?;
|
||||||
context.send_by_key(packet.buffer(), route_key)?;
|
context.send_by_key(&packet, route_key)?;
|
||||||
}
|
}
|
||||||
std::net::IpAddr::V6(_) => {}
|
std::net::IpAddr::V6(_) => {}
|
||||||
},
|
},
|
||||||
@@ -291,17 +298,15 @@ impl ClientPacketHandler {
|
|||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
net_packet: NetPacket<&mut [u8]>,
|
net_packet: NetPacket<&mut [u8]>,
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if context.use_channel_type().is_only_relay() {
|
if context.use_channel_type().is_only_relay() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let source = net_packet.source();
|
let source = net_packet.source();
|
||||||
match other_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
match other_turn_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||||
other_turn_packet::Protocol::Punch => {
|
other_turn_packet::Protocol::Punch => {
|
||||||
let mut punch_info =
|
let mut punch_info = PunchInfo::parse_from_bytes(net_packet.payload())
|
||||||
PunchInfo::parse_from_bytes(net_packet.payload()).map_err(|e| {
|
.map_err(|e| anyhow!("PunchInfo {:?}", e))?;
|
||||||
io::Error::new(io::ErrorKind::Other, format!("PunchInfo {:?}", e))
|
|
||||||
})?;
|
|
||||||
let public_ips = punch_info
|
let public_ips = punch_info
|
||||||
.public_ip_list
|
.public_ip_list
|
||||||
.iter()
|
.iter()
|
||||||
@@ -309,6 +314,7 @@ impl ClientPacketHandler {
|
|||||||
.collect();
|
.collect();
|
||||||
let local_ipv4 = Some(Ipv4Addr::from(punch_info.local_ip.to_be_bytes()));
|
let local_ipv4 = Some(Ipv4Addr::from(punch_info.local_ip.to_be_bytes()));
|
||||||
let tcp_port = punch_info.tcp_port as u16;
|
let tcp_port = punch_info.tcp_port as u16;
|
||||||
|
let public_tcp_port = punch_info.public_tcp_port as u16;
|
||||||
let ipv6 = if punch_info.ipv6.len() == 16 {
|
let ipv6 = if punch_info.ipv6.len() == 16 {
|
||||||
let ipv6: [u8; 16] = punch_info.ipv6.try_into().unwrap();
|
let ipv6: [u8; 16] = punch_info.ipv6.try_into().unwrap();
|
||||||
Some(Ipv6Addr::from(ipv6))
|
Some(Ipv6Addr::from(ipv6))
|
||||||
@@ -331,7 +337,9 @@ impl ClientPacketHandler {
|
|||||||
ipv6,
|
ipv6,
|
||||||
punch_info.udp_ports.iter().map(|e| *e as u16).collect(),
|
punch_info.udp_ports.iter().map(|e| *e as u16).collect(),
|
||||||
tcp_port,
|
tcp_port,
|
||||||
|
public_tcp_port,
|
||||||
punch_info.nat_type.enum_value_or_default().into(),
|
punch_info.nat_type.enum_value_or_default().into(),
|
||||||
|
punch_info.punch_model.enum_value_or_default().into(),
|
||||||
);
|
);
|
||||||
{
|
{
|
||||||
let peer_nat_info = peer_nat_info.clone();
|
let peer_nat_info = peer_nat_info.clone();
|
||||||
@@ -351,8 +359,11 @@ impl ClientPacketHandler {
|
|||||||
nat_info.public_ports.iter().map(|e| *e as u32).collect();
|
nat_info.public_ports.iter().map(|e| *e as u32).collect();
|
||||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||||
punch_reply.tcp_port = nat_info.tcp_port as u32;
|
punch_reply.tcp_port = nat_info.tcp_port as u32;
|
||||||
|
punch_reply.public_tcp_port = nat_info.public_tcp_port as u32;
|
||||||
punch_reply.nat_type =
|
punch_reply.nat_type =
|
||||||
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||||
|
punch_reply.punch_model =
|
||||||
|
protobuf::EnumOrUnknown::new(nat_info.punch_model.into());
|
||||||
punch_reply.local_ip =
|
punch_reply.local_ip =
|
||||||
u32::from(nat_info.local_ipv4().unwrap_or(Ipv4Addr::UNSPECIFIED));
|
u32::from(nat_info.local_ipv4().unwrap_or(Ipv4Addr::UNSPECIFIED));
|
||||||
punch_reply.local_port = nat_info.udp_ports[0] as u32;
|
punch_reply.local_port = nat_info.udp_ports[0] as u32;
|
||||||
@@ -361,9 +372,9 @@ impl ClientPacketHandler {
|
|||||||
punch_reply.ipv6 = ipv6.octets().to_vec();
|
punch_reply.ipv6 = ipv6.octets().to_vec();
|
||||||
punch_reply.ipv6_port = nat_info.udp_ports[0] as u32;
|
punch_reply.ipv6_port = nat_info.udp_ports[0] as u32;
|
||||||
}
|
}
|
||||||
let bytes = punch_reply.write_to_bytes().map_err(|e| {
|
let bytes = punch_reply
|
||||||
io::Error::new(io::ErrorKind::Other, format!("punch_reply {:?}", e))
|
.write_to_bytes()
|
||||||
})?;
|
.map_err(|e| anyhow!("punch_reply {:?}", e))?;
|
||||||
let mut punch_packet =
|
let mut punch_packet =
|
||||||
NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
|
NetPacket::new_encrypt(vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED])?;
|
||||||
punch_packet.set_default_version();
|
punch_packet.set_default_version();
|
||||||
@@ -375,7 +386,7 @@ impl ClientPacketHandler {
|
|||||||
punch_packet.set_payload(&bytes)?;
|
punch_packet.set_payload(&bytes)?;
|
||||||
self.client_cipher.encrypt_ipv4(&mut punch_packet)?;
|
self.client_cipher.encrypt_ipv4(&mut punch_packet)?;
|
||||||
if self.punch_sender.send(true, source, peer_nat_info) {
|
if self.punch_sender.send(true, source, peer_nat_info) {
|
||||||
context.send_by_key(punch_packet.buffer(), route_key)?;
|
context.send_by_key(&punch_packet, route_key)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.punch_sender.send(false, source, peer_nat_info);
|
self.punch_sender.send(false, source, peer_nat_info);
|
||||||
|
|||||||
@@ -24,34 +24,35 @@ use crate::handle::{BaseConfigInfo, CurrentDeviceInfo, PeerDeviceInfo, SELF_IP};
|
|||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
use crate::ip_proxy::IpProxyMap;
|
use crate::ip_proxy::IpProxyMap;
|
||||||
use crate::nat::NatTest;
|
use crate::nat::NatTest;
|
||||||
use crate::protocol::NetPacket;
|
use crate::protocol::{NetPacket, HEAD_LEN};
|
||||||
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||||
use crate::util::U64Adder;
|
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod server;
|
mod server;
|
||||||
mod turn;
|
mod turn;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RecvDataHandler<Call> {
|
pub struct RecvDataHandler<Call, Device> {
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
turn: TurnPacketHandler,
|
turn: TurnPacketHandler,
|
||||||
client: ClientPacketHandler,
|
client: ClientPacketHandler<Device>,
|
||||||
server: ServerPacketHandler<Call>,
|
server: ServerPacketHandler<Call, Device>,
|
||||||
counter: U64Adder,
|
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
|
impl<Call: VntCallback, Device: DeviceWrite> RecvChannelHandler for RecvDataHandler<Call, Device> {
|
||||||
fn handle(
|
fn handle(
|
||||||
&mut self,
|
&self,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
extend: &mut [u8],
|
extend: &mut [u8],
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
) {
|
) {
|
||||||
|
if buf.len() < HEAD_LEN {
|
||||||
|
return;
|
||||||
|
}
|
||||||
//判断stun响应包
|
//判断stun响应包
|
||||||
if !route_key.is_tcp() {
|
if route_key.protocol().is_udp() {
|
||||||
if let Ok(rs) = self
|
if let Ok(rs) = self
|
||||||
.nat_test
|
.nat_test
|
||||||
.recv_data(route_key.index(), route_key.addr, buf)
|
.recv_data(route_key.index(), route_key.addr, buf)
|
||||||
@@ -62,19 +63,24 @@ impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Err(e) = self.handle0(buf, extend, route_key, context) {
|
if let Err(e) = self.handle0(buf, extend, route_key, context) {
|
||||||
log::error!("[{}]-{:?}", thread::current().name().unwrap_or(""), e);
|
log::error!(
|
||||||
|
"[{}]-{:?}-{:?}",
|
||||||
|
thread::current().name().unwrap_or(""),
|
||||||
|
route_key.addr,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Call: VntCallback> RecvDataHandler<Call> {
|
impl<Call: VntCallback, Device: DeviceWrite> RecvDataHandler<Call, Device> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
device: DeviceAdapter,
|
device: Device,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
config_info: BaseConfigInfo,
|
config_info: BaseConfigInfo,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
callback: Call,
|
callback: Call,
|
||||||
@@ -82,9 +88,12 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
|||||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||||
external_route: ExternalRoute,
|
external_route: ExternalRoute,
|
||||||
route: AllowExternalRoute,
|
route: AllowExternalRoute,
|
||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
#[cfg(feature = "integrated_tun")]
|
||||||
counter: U64Adder,
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
ip_proxy_map: Option<IpProxyMap>,
|
||||||
handshake: Handshake,
|
handshake: Handshake,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let server = ServerPacketHandler::new(
|
let server = ServerPacketHandler::new(
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
@@ -92,12 +101,14 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
|||||||
server_cipher,
|
server_cipher,
|
||||||
current_device.clone(),
|
current_device.clone(),
|
||||||
device.clone(),
|
device.clone(),
|
||||||
device_list,
|
device_map,
|
||||||
config_info,
|
config_info,
|
||||||
nat_test.clone(),
|
nat_test.clone(),
|
||||||
callback,
|
callback,
|
||||||
external_route.clone(),
|
external_route.clone(),
|
||||||
handshake,
|
handshake,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
tun_device_helper,
|
||||||
);
|
);
|
||||||
let client = ClientPacketHandler::new(
|
let client = ClientPacketHandler::new(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
@@ -106,6 +117,7 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
|||||||
peer_nat_info_map,
|
peer_nat_info_map,
|
||||||
nat_test.clone(),
|
nat_test.clone(),
|
||||||
route,
|
route,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
ip_proxy_map,
|
ip_proxy_map,
|
||||||
);
|
);
|
||||||
@@ -115,23 +127,21 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
|||||||
turn,
|
turn,
|
||||||
client,
|
client,
|
||||||
server,
|
server,
|
||||||
counter,
|
|
||||||
nat_test,
|
nat_test,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn handle0(
|
fn handle0(
|
||||||
&mut self,
|
&self,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
extend: &mut [u8],
|
extend: &mut [u8],
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// 统计流量
|
|
||||||
self.counter.add(buf.len() as _);
|
|
||||||
let net_packet = NetPacket::new(buf)?;
|
let net_packet = NetPacket::new(buf)?;
|
||||||
|
|
||||||
let extend = NetPacket::unchecked(extend);
|
let extend = NetPacket::unchecked(extend);
|
||||||
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
|
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
|
||||||
log::warn!("丢弃过时包:{:?}", net_packet.head());
|
log::warn!("丢弃过时包:{:?} {}", net_packet.head(), route_key.addr);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let current_device = self.current_device.load();
|
let current_device = self.current_device.load();
|
||||||
@@ -143,6 +153,10 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
|||||||
|| dest.is_unspecified()
|
|| dest.is_unspecified()
|
||||||
|| dest == current_device.broadcast_ip
|
|| dest == current_device.broadcast_ip
|
||||||
{
|
{
|
||||||
|
// 统计流量
|
||||||
|
if let Some(down_traffic_meter) = &context.down_traffic_meter {
|
||||||
|
down_traffic_meter.add_traffic(net_packet.source(), net_packet.data_len())
|
||||||
|
}
|
||||||
//发给自己的包
|
//发给自己的包
|
||||||
if net_packet.is_gateway() {
|
if net_packet.is_gateway() {
|
||||||
//服务端-客户端包
|
//服务端-客户端包
|
||||||
|
|||||||
+141
-112
@@ -1,3 +1,5 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -5,12 +7,11 @@ use std::sync::Arc;
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::Mutex;
|
|
||||||
use protobuf::Message;
|
|
||||||
|
|
||||||
use packet::icmp::{icmp, Kind};
|
use packet::icmp::{icmp, Kind};
|
||||||
use packet::ip::ipv4;
|
use packet::ip::ipv4;
|
||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use protobuf::Message;
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::channel::{Route, RouteKey};
|
use crate::channel::{Route, RouteKey};
|
||||||
@@ -23,52 +24,50 @@ use crate::handle::callback::{ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo,
|
|||||||
use crate::handle::handshaker;
|
use crate::handle::handshaker;
|
||||||
use crate::handle::handshaker::Handshake;
|
use crate::handle::handshaker::Handshake;
|
||||||
use crate::handle::recv_data::PacketHandler;
|
use crate::handle::recv_data::PacketHandler;
|
||||||
use crate::handle::{
|
use crate::handle::{registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, GATEWAY_IP,
|
|
||||||
};
|
|
||||||
use crate::nat::NatTest;
|
use crate::nat::NatTest;
|
||||||
use crate::proto::message::{DeviceList, HandshakeResponse, RegistrationResponse};
|
use crate::proto::message::{DeviceList, HandshakeResponse, RegistrationResponse};
|
||||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||||
use crate::protocol::control_packet::ControlPacket;
|
use crate::protocol::control_packet::ControlPacket;
|
||||||
use crate::protocol::error_packet::InErrorPacket;
|
use crate::protocol::error_packet::InErrorPacket;
|
||||||
use crate::protocol::{ip_turn_packet, service_packet, NetPacket, Protocol, MAX_TTL};
|
use crate::protocol::{ip_turn_packet, service_packet, NetPacket, Protocol, MAX_TTL};
|
||||||
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||||
use crate::{proto, PeerClientInfo};
|
use crate::{proto, PeerClientInfo};
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
use tun::device::IFace;
|
|
||||||
|
|
||||||
/// 处理来源于服务端的包
|
/// 处理来源于服务端的包
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ServerPacketHandler<Call> {
|
pub struct ServerPacketHandler<Call, Device> {
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
device: DeviceAdapter,
|
device: Device,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
config_info: BaseConfigInfo,
|
config_info: BaseConfigInfo,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
callback: Call,
|
callback: Call,
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
up_key_time: Arc<AtomicCell<Instant>>,
|
up_key_time: Arc<AtomicCell<Instant>>,
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
route_record: Arc<Mutex<Vec<(Ipv4Addr, Ipv4Addr)>>>,
|
|
||||||
external_route: ExternalRoute,
|
external_route: ExternalRoute,
|
||||||
handshake: Handshake,
|
handshake: Handshake,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Call> ServerPacketHandler<Call> {
|
impl<Call, Device> ServerPacketHandler<Call, Device> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
device: DeviceAdapter,
|
device: Device,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
config_info: BaseConfigInfo,
|
config_info: BaseConfigInfo,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
callback: Call,
|
callback: Call,
|
||||||
external_route: ExternalRoute,
|
external_route: ExternalRoute,
|
||||||
handshake: Handshake,
|
handshake: Handshake,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
@@ -76,21 +75,25 @@ impl<Call> ServerPacketHandler<Call> {
|
|||||||
server_cipher,
|
server_cipher,
|
||||||
current_device,
|
current_device,
|
||||||
device,
|
device,
|
||||||
device_list,
|
device_map,
|
||||||
config_info,
|
config_info,
|
||||||
nat_test,
|
nat_test,
|
||||||
callback,
|
callback,
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
up_key_time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
|
up_key_time: Arc::new(AtomicCell::new(
|
||||||
#[cfg(not(target_os = "android"))]
|
Instant::now()
|
||||||
route_record: Arc::new(Mutex::default()),
|
.checked_sub(Duration::from_secs(60))
|
||||||
|
.unwrap_or(Instant::now()),
|
||||||
|
)),
|
||||||
external_route,
|
external_route,
|
||||||
handshake,
|
handshake,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
tun_device_helper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandler<Call, Device> {
|
||||||
fn handle(
|
fn handle(
|
||||||
&self,
|
&self,
|
||||||
mut net_packet: NetPacket<&mut [u8]>,
|
mut net_packet: NetPacket<&mut [u8]>,
|
||||||
@@ -99,6 +102,14 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
if !current_device.is_server_addr(route_key.addr) {
|
||||||
|
//拦截不是服务端的流量
|
||||||
|
log::warn!(
|
||||||
|
"route_key={:?},不是来源于服务端地址{}",
|
||||||
|
route_key,
|
||||||
|
current_device.connect_server
|
||||||
|
);
|
||||||
|
}
|
||||||
context
|
context
|
||||||
.route_table
|
.route_table
|
||||||
.update_read_time(&net_packet.source(), &route_key);
|
.update_read_time(&net_packet.source(), &route_key);
|
||||||
@@ -128,7 +139,7 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
self.config_info.token.clone(),
|
self.config_info.token.clone(),
|
||||||
key,
|
key,
|
||||||
)?;
|
)?;
|
||||||
context.send_by_key(packet.buffer(), route_key)?;
|
context.send_by_key(&packet, route_key)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,11 +147,11 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
} else if net_packet.protocol() == Protocol::Service
|
} else if net_packet.protocol() == Protocol::Service
|
||||||
&& net_packet.transport_protocol() == service_packet::Protocol::HandshakeResponse.into()
|
&& net_packet.transport_protocol() == service_packet::Protocol::HandshakeResponse.into()
|
||||||
{
|
{
|
||||||
let response =
|
let response = HandshakeResponse::parse_from_bytes(net_packet.payload())
|
||||||
HandshakeResponse::parse_from_bytes(net_packet.payload()).map_err(|e| {
|
.map_err(|e| anyhow!("HandshakeResponse {:?}", e))?;
|
||||||
io::Error::new(io::ErrorKind::Other, format!("HandshakeResponse {:?}", e))
|
|
||||||
})?;
|
|
||||||
log::info!("握手响应:{:?},{}", route_key, response);
|
log::info!("握手响应:{:?},{}", route_key, response);
|
||||||
|
//设置为默认通道
|
||||||
|
context.set_default_route_key(route_key);
|
||||||
//如果开启了加密,则发送加密握手请求
|
//如果开启了加密,则发送加密握手请求
|
||||||
#[cfg(feature = "server_encrypt")]
|
#[cfg(feature = "server_encrypt")]
|
||||||
if let Some(key) = self.server_cipher.key() {
|
if let Some(key) = self.server_cipher.key() {
|
||||||
@@ -154,7 +165,7 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
key,
|
key,
|
||||||
)?;
|
)?;
|
||||||
drop(guard);
|
drop(guard);
|
||||||
context.send_by_key(packet.buffer(), route_key)?;
|
context.send_by_key(&packet, route_key)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
log::warn!(
|
log::warn!(
|
||||||
@@ -189,7 +200,7 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
self.config_info.token.clone(),
|
self.config_info.token.clone(),
|
||||||
key,
|
key,
|
||||||
)?;
|
)?;
|
||||||
context.send_by_key(packet.buffer(), route_key)?;
|
context.send_by_key(&packet, route_key)?;
|
||||||
self.rsa_cipher.lock().replace(rsa_cipher);
|
self.rsa_cipher.lock().replace(rsa_cipher);
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -201,7 +212,7 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
let handshake_info = HandshakeInfo::new_no_secret(response.version);
|
let handshake_info = HandshakeInfo::new_no_secret(response.version);
|
||||||
if self.callback.handshake(handshake_info) {
|
if self.callback.handshake(handshake_info) {
|
||||||
//没有加密,则发送注册请求
|
//没有加密,则发送注册请求
|
||||||
self.register(current_device, context)?;
|
self.register(current_device, context, route_key)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -236,6 +247,11 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ip_turn_packet::Protocol::WGIpv4 => {
|
||||||
|
if self.config_info.allow_wire_guard {
|
||||||
|
self.device.write(net_packet.payload())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
ip_turn_packet::Protocol::Ipv4Broadcast => {}
|
ip_turn_packet::Protocol::Ipv4Broadcast => {}
|
||||||
ip_turn_packet::Protocol::Unknown(_) => {}
|
ip_turn_packet::Protocol::Unknown(_) => {}
|
||||||
}
|
}
|
||||||
@@ -247,14 +263,14 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Call: VntCallback> ServerPacketHandler<Call> {
|
impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
|
||||||
fn service(
|
fn service(
|
||||||
&self,
|
&self,
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
net_packet: NetPacket<&mut [u8]>,
|
net_packet: NetPacket<&mut [u8]>,
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||||
service_packet::Protocol::RegistrationResponse => {
|
service_packet::Protocol::RegistrationResponse => {
|
||||||
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())
|
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())
|
||||||
@@ -280,6 +296,10 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
let public_port = response.public_port as u16;
|
let public_port = response.public_port as u16;
|
||||||
self.nat_test
|
self.nat_test
|
||||||
.update_addr(route_key.index(), public_ip, public_port);
|
.update_addr(route_key.index(), public_ip, public_port);
|
||||||
|
if route_key.protocol().is_tcp() {
|
||||||
|
log::info!("更新公网tcp端口 {public_port}");
|
||||||
|
self.nat_test.update_tcp_port(public_port);
|
||||||
|
}
|
||||||
let old = current_device;
|
let old = current_device;
|
||||||
let mut cur = *current_device;
|
let mut cur = *current_device;
|
||||||
loop {
|
loop {
|
||||||
@@ -306,80 +326,81 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
if old.virtual_ip != Ipv4Addr::UNSPECIFIED {
|
if old.virtual_ip != Ipv4Addr::UNSPECIFIED {
|
||||||
log::info!("ip发生变化,old:{:?},response={:?}", old, response);
|
log::info!("ip发生变化,old:{:?},response={:?}", old, response);
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "android")]
|
let device_config = crate::handle::callback::DeviceConfig::new(
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
self.config_info.tap,
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "windows",
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "macos"
|
||||||
|
))]
|
||||||
|
self.config_info.device_name.clone(),
|
||||||
|
self.config_info.mtu,
|
||||||
|
virtual_ip,
|
||||||
|
virtual_netmask,
|
||||||
|
virtual_gateway,
|
||||||
|
virtual_network,
|
||||||
|
self.external_route.to_route(),
|
||||||
|
);
|
||||||
|
#[cfg(not(feature = "integrated_tun"))]
|
||||||
|
self.callback.create_device(device_config);
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
{
|
{
|
||||||
let device_config = crate::handle::callback::DeviceConfig::new(
|
self.tun_device_helper.stop();
|
||||||
virtual_ip,
|
#[cfg(any(
|
||||||
virtual_netmask,
|
target_os = "windows",
|
||||||
virtual_gateway,
|
target_os = "linux",
|
||||||
virtual_network,
|
target_os = "macos"
|
||||||
self.external_route.to_route(),
|
))]
|
||||||
);
|
match crate::tun_tap_device::create_device(
|
||||||
let device_fd = self.callback.generate_tun(device_config);
|
device_config,
|
||||||
if device_fd == 0 {
|
&self.callback,
|
||||||
self.callback.error(ErrorInfo::new_msg(
|
|
||||||
ErrorType::Unknown,
|
|
||||||
"device_fd == 0".into(),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
if let Err(e) = self.device.start(device_fd as _) {
|
|
||||||
self.callback.error(ErrorInfo::new_msg(
|
|
||||||
ErrorType::Unknown,
|
|
||||||
format!("{:?}", e),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
{
|
|
||||||
if let Err(e) = self.device.set_ip(virtual_ip, virtual_netmask) {
|
|
||||||
log::error!("LocalIpExists {:?}", e);
|
|
||||||
self.callback.error(ErrorInfo::new_msg(
|
|
||||||
ErrorType::LocalIpExists,
|
|
||||||
format!("set_ip {:?}", e),
|
|
||||||
));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let mut guard = self.route_record.lock();
|
|
||||||
for (dest, mask) in guard.drain(..) {
|
|
||||||
if let Err(e) = self.device.delete_route(dest, mask) {
|
|
||||||
log::warn!("删除路由失败 ={:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Err(e) =
|
|
||||||
self.device.add_route(virtual_network, virtual_netmask, 1)
|
|
||||||
{
|
|
||||||
log::warn!("添加默认路由失败 ={:?}", e);
|
|
||||||
} else {
|
|
||||||
guard.push((virtual_network, virtual_netmask));
|
|
||||||
}
|
|
||||||
if let Err(e) =
|
|
||||||
self.device
|
|
||||||
.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1)
|
|
||||||
{
|
|
||||||
log::warn!("添加广播路由失败 ={:?}", e);
|
|
||||||
} else {
|
|
||||||
guard.push((Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = self.device.add_route(
|
|
||||||
Ipv4Addr::from([224, 0, 0, 0]),
|
|
||||||
Ipv4Addr::from([240, 0, 0, 0]),
|
|
||||||
1,
|
|
||||||
) {
|
) {
|
||||||
log::warn!("添加组播路由失败 ={:?}", e);
|
Ok(device) => {
|
||||||
} else {
|
let tun_info = crate::handle::callback::DeviceInfo::new(
|
||||||
guard.push((
|
device.name().unwrap_or("unknown".into()),
|
||||||
Ipv4Addr::from([224, 0, 0, 0]),
|
"".into(),
|
||||||
Ipv4Addr::from([240, 0, 0, 0]),
|
);
|
||||||
));
|
log::info!("tun信息{:?}", tun_info);
|
||||||
|
self.callback.create_tun(tun_info);
|
||||||
|
self.tun_device_helper
|
||||||
|
.start(device, self.config_info.allow_wire_guard)?;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
self.callback.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
for (dest, mask) in self.external_route.to_route() {
|
{
|
||||||
if let Err(e) = self.device.add_route(dest, mask, 1) {
|
let device_config = crate::handle::callback::DeviceConfig::new(
|
||||||
log::warn!("添加路由失败 ={:?}", e);
|
self.config_info.mtu,
|
||||||
|
virtual_ip,
|
||||||
|
virtual_netmask,
|
||||||
|
virtual_gateway,
|
||||||
|
virtual_network,
|
||||||
|
self.external_route.to_route(),
|
||||||
|
);
|
||||||
|
let device_fd = self.callback.generate_tun(device_config);
|
||||||
|
if device_fd == 0 {
|
||||||
|
self.callback.error(ErrorInfo::new_msg(
|
||||||
|
ErrorType::FailedToCrateDevice,
|
||||||
|
"device_fd == 0".into(),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
guard.push((dest, mask));
|
let device =
|
||||||
|
unsafe { tun_rs::SyncDevice::from_fd(device_fd as _) };
|
||||||
|
if let Err(e) = self
|
||||||
|
.tun_device_helper
|
||||||
|
.start(Arc::new(device), self.config_info.allow_wire_guard)
|
||||||
|
{
|
||||||
|
self.callback.error(ErrorInfo::new_msg(
|
||||||
|
ErrorType::FailedToCrateDevice,
|
||||||
|
format!("{:?}", e),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,7 +420,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
service_packet::Protocol::SecretHandshakeResponse => {
|
service_packet::Protocol::SecretHandshakeResponse => {
|
||||||
log::info!("SecretHandshakeResponse");
|
log::info!("SecretHandshakeResponse");
|
||||||
//加密握手结束,发送注册数据
|
//加密握手结束,发送注册数据
|
||||||
self.register(current_device, context)?;
|
self.register(current_device, context, route_key)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
@@ -420,14 +441,18 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
info.device_status as u8,
|
info.device_status as u8,
|
||||||
info.client_secret,
|
info.client_secret,
|
||||||
info.client_secret_hash,
|
info.client_secret_hash,
|
||||||
|
info.wireguard,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
{
|
{
|
||||||
let mut dev = self.device_list.lock();
|
let mut dev = self.device_map.lock();
|
||||||
//这里可能会收到旧的消息,但是随着时间推移总会收到新的
|
//这里可能会收到旧的消息,但是随着时间推移总会收到新的
|
||||||
dev.0 = epoch;
|
dev.0 = epoch;
|
||||||
dev.1 = ip_list.clone();
|
dev.1.clear();
|
||||||
|
for info in ip_list.clone() {
|
||||||
|
dev.1.insert(info.virtual_ip, info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.callback.peer_client_list(
|
self.callback.peer_client_list(
|
||||||
ip_list
|
ip_list
|
||||||
@@ -440,11 +465,14 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
&self,
|
&self,
|
||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
) -> io::Result<()> {
|
route_key: RouteKey,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
if current_device.status.online() {
|
if current_device.status.online() {
|
||||||
log::info!("已连接的不需要注册,{:?}", self.config_info);
|
log::info!("已连接的不需要注册,{:?}", self.config_info);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
//设置为默认通道
|
||||||
|
context.set_default_route_key(route_key);
|
||||||
let token = self.config_info.token.clone();
|
let token = self.config_info.token.clone();
|
||||||
let device_id = self.config_info.device_id.clone();
|
let device_id = self.config_info.device_id.clone();
|
||||||
let name = self.config_info.name.clone();
|
let name = self.config_info.name.clone();
|
||||||
@@ -469,7 +497,8 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
)?;
|
)?;
|
||||||
log::info!("发送注册请求,{:?}", self.config_info);
|
log::info!("发送注册请求,{:?}", self.config_info);
|
||||||
//注册请求只发送到默认通道
|
//注册请求只发送到默认通道
|
||||||
context.send_default(response.buffer(), current_device.connect_server)
|
context.send_default(&response, current_device.connect_server)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
fn error(
|
fn error(
|
||||||
&self,
|
&self,
|
||||||
@@ -490,7 +519,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
self.callback.error(err);
|
self.callback.error(err);
|
||||||
//掉线epoch要归零
|
//掉线epoch要归零
|
||||||
{
|
{
|
||||||
let mut dev = self.device_list.lock();
|
let mut dev = self.device_map.lock();
|
||||||
dev.0 = 0;
|
dev.0 = 0;
|
||||||
drop(dev);
|
drop(dev);
|
||||||
}
|
}
|
||||||
@@ -527,7 +556,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
net_packet: NetPacket<&mut [u8]>,
|
net_packet: NetPacket<&mut [u8]>,
|
||||||
route_key: RouteKey,
|
route_key: RouteKey,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||||
ControlPacket::PongPacket(pong_packet) => {
|
ControlPacket::PongPacket(pong_packet) => {
|
||||||
let current_time = crate::handle::now_time() as u16;
|
let current_time = crate::handle::now_time() as u16;
|
||||||
@@ -538,12 +567,12 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
let rt = (current_time - pong_packet.time()) as i64;
|
let rt = (current_time - pong_packet.time()) as i64;
|
||||||
let route = Route::from(route_key, metric, rt);
|
let route = Route::from(route_key, metric, rt);
|
||||||
context.route_table.add_route(net_packet.source(), route);
|
context.route_table.add_route(net_packet.source(), route);
|
||||||
let epoch = self.device_list.lock().0;
|
let epoch = self.device_map.lock().0;
|
||||||
if pong_packet.epoch() != epoch {
|
if pong_packet.epoch() != epoch {
|
||||||
//纪元不一致,可能有新客户端连接,向服务端拉取客户端列表
|
//纪元不一致,可能有新客户端连接,向服务端拉取客户端列表
|
||||||
let mut poll_device = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
|
let mut poll_device = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
|
||||||
poll_device.set_source(current_device.virtual_ip);
|
poll_device.set_source(current_device.virtual_ip);
|
||||||
poll_device.set_destination(GATEWAY_IP);
|
poll_device.set_destination(current_device.virtual_gateway);
|
||||||
poll_device.set_default_version();
|
poll_device.set_default_version();
|
||||||
poll_device.set_gateway_flag(true);
|
poll_device.set_gateway_flag(true);
|
||||||
poll_device.first_set_ttl(MAX_TTL);
|
poll_device.first_set_ttl(MAX_TTL);
|
||||||
@@ -552,7 +581,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
|||||||
.set_transport_protocol(service_packet::Protocol::PullDeviceList.into());
|
.set_transport_protocol(service_packet::Protocol::PullDeviceList.into());
|
||||||
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
|
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
|
||||||
//发送到默认服务端即可
|
//发送到默认服务端即可
|
||||||
context.send_default(poll_device.buffer(), current_device.connect_server)?;
|
context.send_default(&poll_device, current_device.connect_server)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ControlPacket::AddrResponse(addr_packet) => {
|
ControlPacket::AddrResponse(addr_packet) => {
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ impl PacketHandler for TurnPacketHandler {
|
|||||||
// ttl减一
|
// ttl减一
|
||||||
let ttl = net_packet.incr_ttl();
|
let ttl = net_packet.incr_ttl();
|
||||||
if ttl > 0 {
|
if ttl > 0 {
|
||||||
|
if net_packet.is_gateway() {
|
||||||
|
// 暂时不转发服务端包
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let destination = net_packet.destination();
|
let destination = net_packet.destination();
|
||||||
if let Some(route) = context.route_table.route_one(&destination) {
|
if let Some(route) = context.route_table.route_one(&destination) {
|
||||||
if route.addr == route_key.addr {
|
if route.addr == route_key.addr {
|
||||||
@@ -36,7 +40,7 @@ impl PacketHandler for TurnPacketHandler {
|
|||||||
}
|
}
|
||||||
if route.metric <= ttl {
|
if route.metric <= ttl {
|
||||||
return context
|
return context
|
||||||
.send_by_key(net_packet.buffer(), route.route_key())
|
.send_by_key(&net_packet, route.route_key())
|
||||||
.context("转发失败");
|
.context("转发失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::io;
|
use anyhow::anyhow;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
use protobuf::Message;
|
use protobuf::Message;
|
||||||
@@ -19,7 +19,7 @@ pub fn registration_request_packet(
|
|||||||
is_fast: bool,
|
is_fast: bool,
|
||||||
allow_ip_change: bool,
|
allow_ip_change: bool,
|
||||||
client_secret_hash: Option<&[u8]>,
|
client_secret_hash: Option<&[u8]>,
|
||||||
) -> io::Result<NetPacket<Vec<u8>>> {
|
) -> anyhow::Result<NetPacket<Vec<u8>>> {
|
||||||
let mut request = RegistrationRequest::new();
|
let mut request = RegistrationRequest::new();
|
||||||
request.token = token;
|
request.token = token;
|
||||||
request.device_id = device_id;
|
request.device_id = device_id;
|
||||||
@@ -36,9 +36,9 @@ pub fn registration_request_packet(
|
|||||||
.client_secret_hash
|
.client_secret_hash
|
||||||
.extend_from_slice(client_secret_hash);
|
.extend_from_slice(client_secret_hash);
|
||||||
}
|
}
|
||||||
let bytes = request.write_to_bytes().map_err(|e| {
|
let bytes = request
|
||||||
io::Error::new(io::ErrorKind::Other, format!("RegistrationRequest {:?}", e))
|
.write_to_bytes()
|
||||||
})?;
|
.map_err(|e| anyhow!("RegistrationRequest {:?}", e))?;
|
||||||
let buf = vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED];
|
let buf = vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED];
|
||||||
let mut net_packet = NetPacket::new_encrypt(buf)?;
|
let mut net_packet = NetPacket::new_encrypt(buf)?;
|
||||||
net_packet.set_destination(GATEWAY_IP);
|
net_packet.set_destination(GATEWAY_IP);
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
use std::sync::mpsc::{sync_channel, Receiver, SendError, SyncSender};
|
|
||||||
|
|
||||||
pub fn channel_group<T>(size: usize, bound: usize) -> (GroupSyncSender<T>, Vec<Receiver<T>>) {
|
|
||||||
let mut senders = Vec::with_capacity(size);
|
|
||||||
let mut receivers = Vec::with_capacity(size);
|
|
||||||
for _ in 0..size {
|
|
||||||
let (s, r) = sync_channel(bound);
|
|
||||||
senders.push(s);
|
|
||||||
receivers.push(r);
|
|
||||||
}
|
|
||||||
(
|
|
||||||
GroupSyncSender {
|
|
||||||
count: 0,
|
|
||||||
base: senders,
|
|
||||||
},
|
|
||||||
receivers,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GroupSyncSender<T> {
|
|
||||||
count: usize,
|
|
||||||
base: Vec<SyncSender<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> GroupSyncSender<T> {
|
|
||||||
pub fn send(&mut self, t: T) -> Result<(), SendError<T>> {
|
|
||||||
self.count += 1;
|
|
||||||
self.base[self.count % self.base.len()].send(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,35 @@
|
|||||||
mod channel_group;
|
|
||||||
pub mod tun_handler;
|
pub mod tun_handler;
|
||||||
|
|
||||||
#[cfg(unix)]
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
mod unix;
|
use parking_lot::Mutex;
|
||||||
#[cfg(unix)]
|
use std::sync::Arc;
|
||||||
pub(crate) use unix::*;
|
mod platform;
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
mod windows;
|
pub(crate) use platform::*;
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub(crate) use windows::*;
|
/// 仅仅是停止tun,不停止vnt
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct DeviceStop {
|
||||||
|
f: Arc<Mutex<Option<Box<dyn FnOnce() + Send>>>>,
|
||||||
|
stopped: Arc<AtomicCell<bool>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceStop {
|
||||||
|
pub fn set_stop_fn<F>(&self, f: F)
|
||||||
|
where
|
||||||
|
F: FnOnce() + Send + 'static,
|
||||||
|
{
|
||||||
|
self.f.lock().replace(Box::new(f));
|
||||||
|
}
|
||||||
|
pub fn stop(&self) {
|
||||||
|
if let Some(f) = self.f.lock().take() {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn stopped(&self) {
|
||||||
|
self.stopped.store(true);
|
||||||
|
}
|
||||||
|
pub fn is_stopped(&self) -> bool {
|
||||||
|
self.stopped.load()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,75 +3,91 @@ use crate::channel::BUFFER_SIZE;
|
|||||||
use crate::cipher::Cipher;
|
use crate::cipher::Cipher;
|
||||||
use crate::compression::Compressor;
|
use crate::compression::Compressor;
|
||||||
use crate::external_route::ExternalRoute;
|
use crate::external_route::ExternalRoute;
|
||||||
use crate::handle::tun_tap::channel_group::GroupSyncSender;
|
use crate::handle::tun_tap::DeviceStop;
|
||||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
use crate::ip_proxy::IpProxyMap;
|
use crate::ip_proxy::IpProxyMap;
|
||||||
use crate::util::{SingleU64Adder, StopManager};
|
use crate::util::StopManager;
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::io;
|
use std::collections::HashMap;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tun::device::IFace;
|
use tun_rs::{InterruptEvent, SyncDevice};
|
||||||
use tun::Device;
|
|
||||||
|
|
||||||
pub(crate) fn start_simple(
|
pub(crate) fn start_simple(
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
device: Arc<Device>,
|
device: Arc<SyncDevice>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
ip_route: ExternalRoute,
|
ip_route: ExternalRoute,
|
||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
up_counter: &mut SingleU64Adder,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
||||||
compressor: Compressor,
|
compressor: Compressor,
|
||||||
) -> io::Result<()> {
|
device_stop: DeviceStop,
|
||||||
|
allow_wire_guard: bool,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let event = Arc::new(InterruptEvent::new()?);
|
||||||
let worker = {
|
let worker = {
|
||||||
let device = device.clone();
|
let event = event.clone();
|
||||||
stop_manager.add_listener("tun_device".into(), move || {
|
stop_manager.add_listener("tun_device".into(), move || {
|
||||||
if let Err(e) = device.shutdown() {
|
if let Err(e) = event.trigger() {
|
||||||
log::warn!("{:?}", e);
|
log::warn!("{:?}", e);
|
||||||
}
|
}
|
||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
|
let worker_cell = Arc::new(AtomicCell::new(Some(worker)));
|
||||||
|
|
||||||
|
{
|
||||||
|
let worker_cell = worker_cell.clone();
|
||||||
|
device_stop.set_stop_fn(move || {
|
||||||
|
if let Some(worker) = worker_cell.take() {
|
||||||
|
worker.stop_self()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
if let Err(e) = start_simple0(
|
if let Err(e) = start_simple0(
|
||||||
context,
|
context,
|
||||||
device,
|
device,
|
||||||
|
event,
|
||||||
current_device,
|
current_device,
|
||||||
ip_route,
|
ip_route,
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
ip_proxy_map,
|
ip_proxy_map,
|
||||||
client_cipher,
|
client_cipher,
|
||||||
server_cipher,
|
server_cipher,
|
||||||
up_counter,
|
device_map,
|
||||||
device_list,
|
|
||||||
compressor,
|
compressor,
|
||||||
|
allow_wire_guard,
|
||||||
) {
|
) {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
}
|
}
|
||||||
worker.stop_all();
|
device_stop.stopped();
|
||||||
|
if let Some(worker) = worker_cell.take() {
|
||||||
|
worker.stop_all();
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_simple0(
|
fn start_simple0(
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
device: Arc<Device>,
|
device: Arc<SyncDevice>,
|
||||||
|
event: Arc<InterruptEvent>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
ip_route: ExternalRoute,
|
ip_route: ExternalRoute,
|
||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
up_counter: &mut SingleU64Adder,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
||||||
compressor: Compressor,
|
compressor: Compressor,
|
||||||
) -> io::Result<()> {
|
allow_wire_guard: bool,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let mut buf = [0; BUFFER_SIZE];
|
let mut buf = [0; BUFFER_SIZE];
|
||||||
let mut extend = [0; BUFFER_SIZE];
|
let mut extend = [0; BUFFER_SIZE];
|
||||||
loop {
|
loop {
|
||||||
let len = device.read(&mut buf[12..])? + 12;
|
let len = device.recv_intr(&mut buf[12..],&event)? + 12;
|
||||||
//单线程的
|
|
||||||
up_counter.add(len as u64);
|
|
||||||
// buf是重复利用的,需要重置头部
|
// buf是重复利用的,需要重置头部
|
||||||
buf[..12].fill(0);
|
buf[..12].fill(0);
|
||||||
match crate::handle::tun_tap::tun_handler::handle(
|
match crate::handle::tun_tap::tun_handler::handle(
|
||||||
@@ -86,8 +102,9 @@ fn start_simple0(
|
|||||||
&ip_proxy_map,
|
&ip_proxy_map,
|
||||||
&client_cipher,
|
&client_cipher,
|
||||||
&server_cipher,
|
&server_cipher,
|
||||||
&device_list,
|
&device_map,
|
||||||
&compressor,
|
&compressor,
|
||||||
|
allow_wire_guard,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -96,38 +113,3 @@ fn start_simple0(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn start_multi(
|
|
||||||
stop_manager: StopManager,
|
|
||||||
device: Arc<Device>,
|
|
||||||
group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
|
||||||
up_counter: &mut SingleU64Adder,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let worker = {
|
|
||||||
let device = device.clone();
|
|
||||||
stop_manager.add_listener("tun_device_multi".into(), move || {
|
|
||||||
if let Err(e) = device.shutdown() {
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
}
|
|
||||||
})?
|
|
||||||
};
|
|
||||||
if let Err(e) = start_multi0(device, group_sync_sender, up_counter) {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
};
|
|
||||||
worker.stop_all();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn start_multi0(
|
|
||||||
device: Arc<Device>,
|
|
||||||
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
|
||||||
up_counter: &mut SingleU64Adder,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
loop {
|
|
||||||
let mut buf = vec![0; 1024 * 16];
|
|
||||||
let len = device.read(&mut buf[12..])? + 12;
|
|
||||||
//单线程的
|
|
||||||
up_counter.add(len as u64);
|
|
||||||
if group_sync_sender.send((buf, len)).is_err() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +1,22 @@
|
|||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::{io, thread};
|
|
||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::Mutex;
|
|
||||||
|
|
||||||
use crate::channel::BUFFER_SIZE;
|
|
||||||
use packet::icmp::icmp::IcmpPacket;
|
use packet::icmp::icmp::IcmpPacket;
|
||||||
use packet::icmp::Kind;
|
use packet::icmp::Kind;
|
||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
use packet::ip::ipv4::protocol::Protocol;
|
use packet::ip::ipv4::protocol::Protocol;
|
||||||
use tun::device::IFace;
|
use parking_lot::Mutex;
|
||||||
use tun::Device;
|
use std::collections::HashMap;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::{io, thread};
|
||||||
|
use tun_rs::SyncDevice;
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
|
use crate::channel::sender::{send_to_wg, send_to_wg_broadcast};
|
||||||
use crate::cipher::Cipher;
|
use crate::cipher::Cipher;
|
||||||
use crate::compression::Compressor;
|
use crate::compression::Compressor;
|
||||||
use crate::external_route::ExternalRoute;
|
use crate::external_route::ExternalRoute;
|
||||||
use crate::handle::tun_tap::channel_group::channel_group;
|
use crate::handle::tun_tap::DeviceStop;
|
||||||
use crate::handle::{check_dest, CurrentDeviceInfo, PeerDeviceInfo};
|
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
use crate::ip_proxy::IpProxyMap;
|
use crate::ip_proxy::IpProxyMap;
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
@@ -27,9 +25,8 @@ use crate::protocol;
|
|||||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||||
use crate::protocol::ip_turn_packet::BroadcastPacket;
|
use crate::protocol::ip_turn_packet::BroadcastPacket;
|
||||||
use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL};
|
use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL};
|
||||||
use crate::util::{SingleU64Adder, StopManager};
|
use crate::util::StopManager;
|
||||||
|
fn icmp(device_writer: &SyncDevice, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyhow::Result<()> {
|
||||||
fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyhow::Result<()> {
|
|
||||||
if ipv4_packet.protocol() == Protocol::Icmp {
|
if ipv4_packet.protocol() == Protocol::Icmp {
|
||||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||||
if icmp.kind() == Kind::EchoRequest {
|
if icmp.kind() == Kind::EchoRequest {
|
||||||
@@ -39,145 +36,48 @@ fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyho
|
|||||||
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||||
ipv4_packet.set_destination_ip(src);
|
ipv4_packet.set_destination_ip(src);
|
||||||
ipv4_packet.update_checksum();
|
ipv4_packet.update_checksum();
|
||||||
device_writer.write(ipv4_packet.buffer)?;
|
device_writer.send(ipv4_packet.buffer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 接收tun数据,并且转发到udp上
|
|
||||||
pub(crate) fn handle(
|
|
||||||
context: &ChannelContext,
|
|
||||||
data: &mut [u8],
|
|
||||||
len: usize,
|
|
||||||
extend: &mut [u8],
|
|
||||||
device_writer: &Device,
|
|
||||||
current_device: CurrentDeviceInfo,
|
|
||||||
ip_route: &ExternalRoute,
|
|
||||||
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
|
|
||||||
client_cipher: &Cipher,
|
|
||||||
server_cipher: &Cipher,
|
|
||||||
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
|
|
||||||
compressor: &Compressor,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
//忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了
|
|
||||||
let ipv4_packet = match IpV4Packet::new(&mut data[12..len]) {
|
|
||||||
Ok(packet) => packet,
|
|
||||||
Err(_) => return Ok(()),
|
|
||||||
};
|
|
||||||
let src_ip = ipv4_packet.source_ip();
|
|
||||||
let dest_ip = ipv4_packet.destination_ip();
|
|
||||||
if src_ip == dest_ip {
|
|
||||||
return icmp(&device_writer, ipv4_packet);
|
|
||||||
}
|
|
||||||
return base_handle(
|
|
||||||
context,
|
|
||||||
data,
|
|
||||||
len,
|
|
||||||
extend,
|
|
||||||
current_device,
|
|
||||||
ip_route,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
proxy_map,
|
|
||||||
client_cipher,
|
|
||||||
server_cipher,
|
|
||||||
device_list,
|
|
||||||
compressor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(
|
pub fn start(
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
device: Arc<Device>,
|
device: Arc<SyncDevice>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
ip_route: ExternalRoute,
|
ip_route: ExternalRoute,
|
||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
parallel: usize,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
mut up_counter: SingleU64Adder,
|
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
||||||
compressor: Compressor,
|
compressor: Compressor,
|
||||||
|
device_stop: DeviceStop,
|
||||||
|
allow_wire_guard: bool,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
if parallel > 1 {
|
thread::Builder::new()
|
||||||
let (sender, receivers) = channel_group::<(Vec<u8>, usize)>(parallel, 16);
|
.name("tunHandlerS".into())
|
||||||
for (index, receiver) in receivers.into_iter().enumerate() {
|
.spawn(move || {
|
||||||
let context = context.clone();
|
if let Err(e) = crate::handle::tun_tap::start_simple(
|
||||||
let device = device.clone();
|
stop_manager,
|
||||||
let current_device = current_device.clone();
|
&context,
|
||||||
let ip_route = ip_route.clone();
|
device,
|
||||||
#[cfg(feature = "ip_proxy")]
|
current_device,
|
||||||
let ip_proxy_map = ip_proxy_map.clone();
|
ip_route,
|
||||||
let client_cipher = client_cipher.clone();
|
#[cfg(feature = "ip_proxy")]
|
||||||
let server_cipher = server_cipher.clone();
|
ip_proxy_map,
|
||||||
let device_list = device_list.clone();
|
client_cipher,
|
||||||
thread::Builder::new()
|
server_cipher,
|
||||||
.name(format!("tunHandler-{}", index))
|
device_map,
|
||||||
.spawn(move || {
|
compressor,
|
||||||
let mut extend = [0; BUFFER_SIZE];
|
device_stop,
|
||||||
while let Ok((mut buf, len)) = receiver.recv() {
|
allow_wire_guard,
|
||||||
#[cfg(not(target_os = "macos"))]
|
) {
|
||||||
let start = 0;
|
log::warn!("stop:{}", e);
|
||||||
#[cfg(target_os = "macos")]
|
}
|
||||||
let start = 4;
|
})?;
|
||||||
match handle(
|
|
||||||
&context,
|
|
||||||
&mut buf[start..],
|
|
||||||
len,
|
|
||||||
&mut extend,
|
|
||||||
&device,
|
|
||||||
current_device.load(),
|
|
||||||
&ip_route,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
&ip_proxy_map,
|
|
||||||
&client_cipher,
|
|
||||||
&server_cipher,
|
|
||||||
&device_list,
|
|
||||||
&compressor,
|
|
||||||
) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("{:?}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
thread::Builder::new()
|
|
||||||
.name("tunHandlerM".into())
|
|
||||||
.spawn(move || {
|
|
||||||
if let Err(e) = crate::handle::tun_tap::start_multi(
|
|
||||||
stop_manager,
|
|
||||||
device,
|
|
||||||
sender,
|
|
||||||
&mut up_counter,
|
|
||||||
) {
|
|
||||||
log::warn!("stop:{}", e);
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
} else {
|
|
||||||
thread::Builder::new()
|
|
||||||
.name("tunHandlerS".into())
|
|
||||||
.spawn(move || {
|
|
||||||
if let Err(e) = crate::handle::tun_tap::start_simple(
|
|
||||||
stop_manager,
|
|
||||||
&context,
|
|
||||||
device,
|
|
||||||
current_device,
|
|
||||||
ip_route,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
ip_proxy_map,
|
|
||||||
client_cipher,
|
|
||||||
server_cipher,
|
|
||||||
&mut up_counter,
|
|
||||||
device_list,
|
|
||||||
compressor,
|
|
||||||
) {
|
|
||||||
log::warn!("stop:{}", e);
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,18 +86,21 @@ fn broadcast(
|
|||||||
sender: &ChannelContext,
|
sender: &ChannelContext,
|
||||||
net_packet: &mut NetPacket<&mut [u8]>,
|
net_packet: &mut NetPacket<&mut [u8]>,
|
||||||
current_device: &CurrentDeviceInfo,
|
current_device: &CurrentDeviceInfo,
|
||||||
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
|
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
|
||||||
) -> io::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let list: Vec<Ipv4Addr> = device_list
|
let list: Vec<Ipv4Addr> = device_map
|
||||||
.lock()
|
.lock()
|
||||||
.1
|
.1
|
||||||
.iter()
|
.values()
|
||||||
.filter(|info| info.status.is_online())
|
.filter(|info| !info.wireguard && info.status.is_online())
|
||||||
.map(|info| info.virtual_ip)
|
.map(|info| info.virtual_ip)
|
||||||
.collect();
|
.collect();
|
||||||
|
if list.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
const MAX_COUNT: usize = 8;
|
const MAX_COUNT: usize = 8;
|
||||||
let mut p2p_ips = Vec::with_capacity(8);
|
let mut p2p_ips = Vec::with_capacity(8);
|
||||||
let mut relay_ips = Vec::with_capacity(8);
|
let mut relay = false;
|
||||||
let mut overflow = false;
|
let mut overflow = false;
|
||||||
for (index, peer_ip) in list.into_iter().enumerate() {
|
for (index, peer_ip) in list.into_iter().enumerate() {
|
||||||
if index > MAX_COUNT {
|
if index > MAX_COUNT {
|
||||||
@@ -205,46 +108,27 @@ fn broadcast(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) {
|
if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) {
|
||||||
if sender
|
if sender.send_by_key(&net_packet, route.route_key()).is_ok() {
|
||||||
.send_by_key(net_packet.buffer(), route.route_key())
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
p2p_ips.push(peer_ip);
|
p2p_ips.push(peer_ip);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
relay_ips.push(peer_ip);
|
relay = true;
|
||||||
}
|
}
|
||||||
if !overflow && relay_ips.is_empty() {
|
if !overflow && !relay {
|
||||||
//全部p2p,不需要服务器中转
|
//全部p2p,不需要服务器中转
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if p2p_ips.is_empty() {
|
|
||||||
//都没有p2p则直接由服务器转发
|
|
||||||
if current_device.status.online() {
|
|
||||||
sender.send_default(net_packet.buffer(), current_device.connect_server)?;
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if !overflow && relay_ips.len() == 2 {
|
|
||||||
// 如果转发的ip数不多就直接发
|
|
||||||
for peer_ip in relay_ips {
|
|
||||||
//非直连的广播要改变目的地址,不然服务端收到了会再次广播
|
|
||||||
net_packet.set_destination(peer_ip);
|
|
||||||
sender.send_ipv4_by_id(
|
|
||||||
net_packet.buffer(),
|
|
||||||
&peer_ip,
|
|
||||||
current_device.connect_server,
|
|
||||||
current_device.status.online(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if current_device.status.offline() {
|
if current_device.status.offline() {
|
||||||
//离线的不再转发
|
//离线的不再转发
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
if p2p_ips.is_empty() {
|
||||||
|
//都没有p2p则直接由服务器转发
|
||||||
|
sender.send_default(&net_packet, current_device.connect_server)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED];
|
let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED];
|
||||||
//剩余的发送到服务端,需要告知哪些已发送过
|
//剩余的发送到服务端,需要告知哪些已发送过
|
||||||
let mut server_packet = NetPacket::new_encrypt(buf)?;
|
let mut server_packet = NetPacket::new_encrypt(buf)?;
|
||||||
@@ -261,27 +145,39 @@ fn broadcast(
|
|||||||
broadcast.set_address(&p2p_ips)?;
|
broadcast.set_address(&p2p_ips)?;
|
||||||
broadcast.set_data(net_packet.buffer())?;
|
broadcast.set_data(net_packet.buffer())?;
|
||||||
server_cipher.encrypt_ipv4(&mut server_packet)?;
|
server_cipher.encrypt_ipv4(&mut server_packet)?;
|
||||||
sender.send_default(server_packet.buffer(), current_device.connect_server)
|
sender.send_default(&server_packet, current_device.connect_server)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 接收tun数据,并且转发到udp上
|
||||||
/// 实现一个原地发送,必须保证是如下结构
|
/// 实现一个原地发送,必须保证是如下结构
|
||||||
/// |12字节开头|ip报文|至少1024字节结尾|
|
/// |12字节开头|ip报文|至少1024字节结尾|
|
||||||
///
|
///
|
||||||
#[inline]
|
pub(crate) fn handle(
|
||||||
fn base_handle(
|
|
||||||
context: &ChannelContext,
|
context: &ChannelContext,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
data_len: usize, //数据总长度=12+ip包长度
|
data_len: usize, //数据总长度=12+ip包长度
|
||||||
extend: &mut [u8],
|
extend: &mut [u8],
|
||||||
|
device_writer: &SyncDevice,
|
||||||
current_device: CurrentDeviceInfo,
|
current_device: CurrentDeviceInfo,
|
||||||
ip_route: &ExternalRoute,
|
ip_route: &ExternalRoute,
|
||||||
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
|
#[cfg(feature = "ip_proxy")] proxy_map: &Option<IpProxyMap>,
|
||||||
client_cipher: &Cipher,
|
client_cipher: &Cipher,
|
||||||
server_cipher: &Cipher,
|
server_cipher: &Cipher,
|
||||||
device_list: &Mutex<(u16, Vec<PeerDeviceInfo>)>,
|
device_map: &Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>,
|
||||||
compressor: &Compressor,
|
compressor: &Compressor,
|
||||||
|
allow_wire_guard: bool,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?;
|
//忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了
|
||||||
|
let ipv4_packet = match IpV4Packet::new(&mut buf[12..data_len]) {
|
||||||
|
Ok(packet) => packet,
|
||||||
|
Err(_) => return Ok(()),
|
||||||
|
};
|
||||||
|
let src_ip = ipv4_packet.source_ip();
|
||||||
|
let dest_ip = ipv4_packet.destination_ip();
|
||||||
|
if src_ip == dest_ip {
|
||||||
|
return icmp(&device_writer, ipv4_packet);
|
||||||
|
}
|
||||||
let protocol = ipv4_packet.protocol();
|
let protocol = ipv4_packet.protocol();
|
||||||
let src_ip = ipv4_packet.source_ip();
|
let src_ip = ipv4_packet.source_ip();
|
||||||
let mut dest_ip = ipv4_packet.destination_ip();
|
let mut dest_ip = ipv4_packet.destination_ip();
|
||||||
@@ -298,10 +194,65 @@ fn base_handle(
|
|||||||
if protocol == Protocol::Icmp {
|
if protocol == Protocol::Icmp {
|
||||||
net_packet.set_gateway_flag(true);
|
net_packet.set_gateway_flag(true);
|
||||||
server_cipher.encrypt_ipv4(&mut net_packet)?;
|
server_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
context.send_default(net_packet.buffer(), current_device.connect_server)?;
|
context.send_default(&net_packet, current_device.connect_server)?;
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
if !dest_ip.is_multicast() && !dest_ip.is_broadcast() && current_device.broadcast_ip != dest_ip
|
||||||
|
{
|
||||||
|
if current_device.not_in_network(dest_ip) {
|
||||||
|
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
||||||
|
//路由的目标不能是自己
|
||||||
|
if r_dest_ip == src_ip {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
//需要修改目的地址
|
||||||
|
dest_ip = r_dest_ip;
|
||||||
|
net_packet.set_destination(r_dest_ip);
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
if let Some(proxy_map) = proxy_map {
|
||||||
|
let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?;
|
||||||
|
proxy_map.send_handle(&mut ipv4_packet)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if dest_ip.is_multicast() {
|
||||||
|
//当作广播处理
|
||||||
|
dest_ip = Ipv4Addr::BROADCAST;
|
||||||
|
net_packet.set_destination(Ipv4Addr::BROADCAST);
|
||||||
|
}
|
||||||
|
let is_broadcast = dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip;
|
||||||
|
if allow_wire_guard {
|
||||||
|
if is_broadcast {
|
||||||
|
// wg客户端和vnt客户端分开广播
|
||||||
|
let exists_wg = device_map
|
||||||
|
.lock()
|
||||||
|
.1
|
||||||
|
.values()
|
||||||
|
.any(|v| v.status.is_online() && v.wireguard);
|
||||||
|
if exists_wg {
|
||||||
|
send_to_wg_broadcast(context, &net_packet, server_cipher, ¤t_device)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果是wg客户端则发到vnts转发
|
||||||
|
let guard = device_map.lock();
|
||||||
|
if let Some(peer_info) = guard.1.get(&dest_ip) {
|
||||||
|
if peer_info.status.is_offline() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if peer_info.wireguard {
|
||||||
|
drop(guard);
|
||||||
|
send_to_wg(context, &mut net_packet, server_cipher, ¤t_device)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut net_packet = if compressor.compress(&net_packet, &mut out)? {
|
let mut net_packet = if compressor.compress(&net_packet, &mut out)? {
|
||||||
out.set_default_version();
|
out.set_default_version();
|
||||||
out.set_protocol(protocol::Protocol::IpTurn);
|
out.set_protocol(protocol::Protocol::IpTurn);
|
||||||
@@ -313,12 +264,7 @@ fn base_handle(
|
|||||||
} else {
|
} else {
|
||||||
net_packet
|
net_packet
|
||||||
};
|
};
|
||||||
if dest_ip.is_multicast() {
|
if is_broadcast {
|
||||||
//当作广播处理
|
|
||||||
dest_ip = Ipv4Addr::BROADCAST;
|
|
||||||
net_packet.set_destination(Ipv4Addr::BROADCAST);
|
|
||||||
}
|
|
||||||
if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip {
|
|
||||||
// 广播 发送到直连目标
|
// 广播 发送到直连目标
|
||||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
broadcast(
|
broadcast(
|
||||||
@@ -326,35 +272,14 @@ fn base_handle(
|
|||||||
context,
|
context,
|
||||||
&mut net_packet,
|
&mut net_packet,
|
||||||
¤t_device,
|
¤t_device,
|
||||||
device_list,
|
device_map,
|
||||||
)?;
|
)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if !check_dest(
|
|
||||||
dest_ip,
|
|
||||||
current_device.virtual_netmask,
|
|
||||||
current_device.virtual_network,
|
|
||||||
) {
|
|
||||||
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
|
||||||
//路由的目标不能是自己
|
|
||||||
if r_dest_ip == src_ip {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
//需要修改目的地址
|
|
||||||
dest_ip = r_dest_ip;
|
|
||||||
net_packet.set_destination(r_dest_ip);
|
|
||||||
} else {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
if let Some(proxy_map) = proxy_map {
|
|
||||||
let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?;
|
|
||||||
proxy_map.send_handle(&mut ipv4_packet)?;
|
|
||||||
}
|
|
||||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
context.send_ipv4_by_id(
|
context.send_ipv4_by_id(
|
||||||
net_packet.buffer(),
|
&net_packet,
|
||||||
&dest_ip,
|
&dest_ip,
|
||||||
current_device.connect_server,
|
current_device.connect_server,
|
||||||
current_device.status.online(),
|
current_device.status.online(),
|
||||||
|
|||||||
@@ -1,192 +0,0 @@
|
|||||||
use crate::channel::context::ChannelContext;
|
|
||||||
use crate::channel::BUFFER_SIZE;
|
|
||||||
use crate::cipher::Cipher;
|
|
||||||
use crate::compression::Compressor;
|
|
||||||
use crate::external_route::ExternalRoute;
|
|
||||||
use crate::handle::tun_tap::channel_group::GroupSyncSender;
|
|
||||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
use crate::ip_proxy::IpProxyMap;
|
|
||||||
use crate::util::{SingleU64Adder, StopManager};
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
|
||||||
use mio::event::Source;
|
|
||||||
use mio::unix::SourceFd;
|
|
||||||
use mio::{Events, Interest, Poll, Token, Waker};
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::io;
|
|
||||||
use std::os::fd::AsRawFd;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use tun::Device;
|
|
||||||
|
|
||||||
const STOP: Token = Token(0);
|
|
||||||
const FD: Token = Token(1);
|
|
||||||
|
|
||||||
pub(crate) fn start_simple(
|
|
||||||
stop_manager: StopManager,
|
|
||||||
context: &ChannelContext,
|
|
||||||
device: Arc<Device>,
|
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
|
||||||
ip_route: ExternalRoute,
|
|
||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
|
||||||
client_cipher: Cipher,
|
|
||||||
server_cipher: Cipher,
|
|
||||||
up_counter: &mut SingleU64Adder,
|
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
||||||
compressor: Compressor,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let poll = Poll::new()?;
|
|
||||||
let waker = Arc::new(Waker::new(poll.registry(), STOP)?);
|
|
||||||
let _waker = waker.clone();
|
|
||||||
let worker = stop_manager.add_listener("tun_device".into(), move || {
|
|
||||||
let _ = waker.wake();
|
|
||||||
})?;
|
|
||||||
if let Err(e) = start_simple0(
|
|
||||||
poll,
|
|
||||||
context,
|
|
||||||
device,
|
|
||||||
current_device,
|
|
||||||
ip_route,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
ip_proxy_map,
|
|
||||||
client_cipher,
|
|
||||||
server_cipher,
|
|
||||||
up_counter,
|
|
||||||
device_list,
|
|
||||||
compressor,
|
|
||||||
) {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
};
|
|
||||||
worker.stop_all();
|
|
||||||
drop(_waker);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_simple0(
|
|
||||||
mut poll: Poll,
|
|
||||||
context: &ChannelContext,
|
|
||||||
device: Arc<Device>,
|
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
|
||||||
ip_route: ExternalRoute,
|
|
||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
|
||||||
client_cipher: Cipher,
|
|
||||||
server_cipher: Cipher,
|
|
||||||
up_counter: &mut SingleU64Adder,
|
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
||||||
compressor: Compressor,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let mut buf = [0; BUFFER_SIZE];
|
|
||||||
let mut extend = [0; BUFFER_SIZE];
|
|
||||||
let fd = device.as_tun_fd();
|
|
||||||
fd.set_nonblock()?;
|
|
||||||
SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?;
|
|
||||||
let mut evnets = Events::with_capacity(4);
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
let start = 12;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
let start = 12 - 4;
|
|
||||||
loop {
|
|
||||||
poll.poll(&mut evnets, None)?;
|
|
||||||
for event in evnets.iter() {
|
|
||||||
if event.token() == STOP {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
loop {
|
|
||||||
let len = match fd.read(&mut buf[start..]) {
|
|
||||||
Ok(len) => len + start,
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() == io::ErrorKind::WouldBlock {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(e)?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//单线程的
|
|
||||||
up_counter.add(len as u64);
|
|
||||||
// buf是重复利用的,需要重置头部
|
|
||||||
buf[..12].fill(0);
|
|
||||||
match crate::handle::tun_tap::tun_handler::handle(
|
|
||||||
context,
|
|
||||||
&mut buf,
|
|
||||||
len,
|
|
||||||
&mut extend,
|
|
||||||
&device,
|
|
||||||
current_device.load(),
|
|
||||||
&ip_route,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
&ip_proxy_map,
|
|
||||||
&client_cipher,
|
|
||||||
&server_cipher,
|
|
||||||
&device_list,
|
|
||||||
&compressor,
|
|
||||||
) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!("{:?}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn start_multi(
|
|
||||||
stop_manager: StopManager,
|
|
||||||
device: Arc<Device>,
|
|
||||||
group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
|
||||||
up_counter: &mut SingleU64Adder,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let poll = Poll::new()?;
|
|
||||||
let waker = Arc::new(Waker::new(poll.registry(), STOP)?);
|
|
||||||
let _waker = waker.clone();
|
|
||||||
let worker = stop_manager.add_listener("tun_device".into(), move || {
|
|
||||||
let _ = waker.wake();
|
|
||||||
})?;
|
|
||||||
if let Err(e) = start_multi0(poll, device, group_sync_sender, up_counter) {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
};
|
|
||||||
worker.stop_all();
|
|
||||||
drop(_waker);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_multi0(
|
|
||||||
mut poll: Poll,
|
|
||||||
device: Arc<Device>,
|
|
||||||
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
|
||||||
up_counter: &mut SingleU64Adder,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let fd = device.as_tun_fd();
|
|
||||||
fd.set_nonblock()?;
|
|
||||||
SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?;
|
|
||||||
let mut evnets = Events::with_capacity(4);
|
|
||||||
let mut buf = vec![0; 1024 * 16];
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
let start = 12;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
let start = 12 - 4;
|
|
||||||
loop {
|
|
||||||
poll.poll(&mut evnets, None)?;
|
|
||||||
for event in evnets.iter() {
|
|
||||||
if event.token() == STOP {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
loop {
|
|
||||||
let len = match fd.read(&mut buf[start..]) {
|
|
||||||
Ok(len) => len + start,
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() == io::ErrorKind::WouldBlock {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Err(e)?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//单线程的
|
|
||||||
up_counter.add(len as u64);
|
|
||||||
if group_sync_sender.send((buf, len)).is_err() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
buf = vec![0; 1024 * 16];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,7 @@ use packet::icmp::icmp::HeaderOther;
|
|||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
|
use crate::channel::socket::{LocalInterface, VntSocketTrait};
|
||||||
use crate::cipher::Cipher;
|
use crate::cipher::Cipher;
|
||||||
use crate::handle::CurrentDeviceInfo;
|
use crate::handle::CurrentDeviceInfo;
|
||||||
use crate::ip_proxy::ProxyHandler;
|
use crate::ip_proxy::ProxyHandler;
|
||||||
@@ -30,6 +31,7 @@ impl IcmpProxy {
|
|||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
let icmp_socket = socket2::Socket::new(
|
let icmp_socket = socket2::Socket::new(
|
||||||
@@ -50,6 +52,9 @@ impl IcmpProxy {
|
|||||||
.bind(&socket2::SockAddr::from(addr))
|
.bind(&socket2::SockAddr::from(addr))
|
||||||
.context("bind Socket ICMPV4 failed")?;
|
.context("bind Socket ICMPV4 failed")?;
|
||||||
icmp_socket.set_nonblocking(true)?;
|
icmp_socket.set_nonblocking(true)?;
|
||||||
|
if let Err(e) = icmp_socket.set_ip_unicast_if(default_interface) {
|
||||||
|
log::warn!("set_ip_unicast_if {:?}", e)
|
||||||
|
}
|
||||||
let std_socket: std::net::UdpSocket = icmp_socket.into();
|
let std_socket: std::net::UdpSocket = icmp_socket.into();
|
||||||
|
|
||||||
let tokio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?)?;
|
let tokio_icmp_socket = UdpSocket::from_std(std_socket.try_clone()?)?;
|
||||||
@@ -155,7 +160,7 @@ fn recv_handle(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Err(e) = context.send_ipv4_by_id(
|
if let Err(e) = context.send_ipv4_by_id(
|
||||||
net_packet.buffer(),
|
&net_packet,
|
||||||
&dest_ip,
|
&dest_ip,
|
||||||
current_device.connect_server,
|
current_device.connect_server,
|
||||||
current_device.status.online(),
|
current_device.status.online(),
|
||||||
|
|||||||
@@ -68,14 +68,16 @@ pub fn init_proxy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn init_proxy0(
|
async fn init_proxy0(
|
||||||
_context: ChannelContext,
|
context: ChannelContext,
|
||||||
_current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
_current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
_client_cipher: Cipher,
|
_client_cipher: Cipher,
|
||||||
) -> anyhow::Result<IpProxyMap> {
|
) -> anyhow::Result<IpProxyMap> {
|
||||||
|
let default_interface = context.default_interface().clone();
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
let icmp_proxy = IcmpProxy::new(_context, _current_device, _client_cipher).await?;
|
let icmp_proxy =
|
||||||
let tcp_proxy = TcpProxy::new().await?;
|
IcmpProxy::new(context, _current_device, _client_cipher, &default_interface).await?;
|
||||||
let udp_proxy = UdpProxy::new().await?;
|
let tcp_proxy = TcpProxy::new(default_interface.clone()).await?;
|
||||||
|
let udp_proxy = UdpProxy::new(default_interface.clone()).await?;
|
||||||
|
|
||||||
Ok(IpProxyMap {
|
Ok(IpProxyMap {
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ use std::time::Duration;
|
|||||||
use std::{collections::HashMap, io, net::SocketAddr};
|
use std::{collections::HashMap, io, net::SocketAddr};
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
|
use crate::channel::socket::{create_tcp, LocalInterface};
|
||||||
|
use crate::ip_proxy::ProxyHandler;
|
||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
use packet::tcp::tcp::TcpPacket;
|
use packet::tcp::tcp::TcpPacket;
|
||||||
|
|
||||||
use crate::ip_proxy::ProxyHandler;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TcpProxy {
|
pub struct TcpProxy {
|
||||||
port: u16,
|
port: u16,
|
||||||
@@ -19,7 +19,7 @@ pub struct TcpProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TcpProxy {
|
impl TcpProxy {
|
||||||
pub async fn new() -> anyhow::Result<Self> {
|
pub async fn new(default_interface: LocalInterface) -> anyhow::Result<Self> {
|
||||||
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
|
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
|
||||||
Arc::new(Mutex::new(HashMap::with_capacity(16)));
|
Arc::new(Mutex::new(HashMap::with_capacity(16)));
|
||||||
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0))
|
let tcp_listener = TcpListener::bind(format!("0.0.0.0:{}", 0))
|
||||||
@@ -28,7 +28,7 @@ impl TcpProxy {
|
|||||||
let port = tcp_listener.local_addr()?.port();
|
let port = tcp_listener.local_addr()?.port();
|
||||||
{
|
{
|
||||||
let nat_map = nat_map.clone();
|
let nat_map = nat_map.clone();
|
||||||
tokio::spawn(tcp_proxy(tcp_listener, nat_map));
|
tokio::spawn(tcp_proxy(tcp_listener, nat_map, default_interface));
|
||||||
}
|
}
|
||||||
Ok(Self { port, nat_map })
|
Ok(Self { port, nat_map })
|
||||||
}
|
}
|
||||||
@@ -79,26 +79,33 @@ impl ProxyHandler for TcpProxy {
|
|||||||
async fn tcp_proxy(
|
async fn tcp_proxy(
|
||||||
tcp_listener: TcpListener,
|
tcp_listener: TcpListener,
|
||||||
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
|
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
|
||||||
|
default_interface: LocalInterface,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
match tcp_listener.accept().await {
|
match tcp_listener.accept().await {
|
||||||
Ok((tcp_stream, sender_addr)) => match sender_addr {
|
Ok((tcp_stream, sender_addr)) => match sender_addr {
|
||||||
SocketAddr::V4(sender_addr) => {
|
SocketAddr::V4(sender_addr) => {
|
||||||
if let Some(dest_addr) = nat_map.lock().get(&sender_addr).cloned() {
|
if let Some(dest_addr) = nat_map.lock().get(&sender_addr).cloned() {
|
||||||
|
let default_interface = default_interface.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let peer_tcp_stream =
|
let peer_tcp_stream = match tcp_connect(
|
||||||
match tcp_connect(sender_addr.port(), dest_addr.into()).await {
|
sender_addr.port(),
|
||||||
Ok(peer_tcp_stream) => peer_tcp_stream,
|
dest_addr.into(),
|
||||||
Err(e) => {
|
&default_interface,
|
||||||
log::warn!(
|
)
|
||||||
"tcp代理异常:{:?},来源:{},目标:{}",
|
.await
|
||||||
e,
|
{
|
||||||
sender_addr,
|
Ok(peer_tcp_stream) => peer_tcp_stream,
|
||||||
dest_addr
|
Err(e) => {
|
||||||
);
|
log::warn!(
|
||||||
return;
|
"tcp代理异常:{:?},来源:{},目标:{}",
|
||||||
}
|
e,
|
||||||
};
|
sender_addr,
|
||||||
|
dest_addr
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
proxy(sender_addr, dest_addr, tcp_stream, peer_tcp_stream).await
|
proxy(sender_addr, dest_addr, tcp_stream, peer_tcp_stream).await
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -114,15 +121,19 @@ async fn tcp_proxy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// 优先使用来源端口建立tcp连接
|
/// 优先使用来源端口建立tcp连接
|
||||||
async fn tcp_connect(src_port: u16, addr: SocketAddr) -> anyhow::Result<TcpStream> {
|
async fn tcp_connect(
|
||||||
let socket = TcpSocket::new_v4()?;
|
src_port: u16,
|
||||||
|
addr: SocketAddr,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<TcpStream> {
|
||||||
|
let socket = create_tcp(true, default_interface)?;
|
||||||
if socket
|
if socket
|
||||||
.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
|
.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, src_port).into())
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
socket.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
|
socket.bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into())?;
|
||||||
}
|
}
|
||||||
let _ = socket.set_nodelay(false);
|
let _ = socket.set_nodelay(true);
|
||||||
let tcp_stream = tokio::time::timeout(Duration::from_secs(5), socket.connect(addr))
|
let tcp_stream = tokio::time::timeout(Duration::from_secs(5), socket.connect(addr))
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("TCP connection timeout {}", addr))?
|
.with_context(|| format!("TCP connection timeout {}", addr))?
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ use std::{collections::HashMap, io, net::SocketAddr};
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
|
|
||||||
|
use crate::channel::socket::{bind_udp, LocalInterface};
|
||||||
|
use crate::ip_proxy::ProxyHandler;
|
||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
use packet::udp::udp::UdpPacket;
|
use packet::udp::udp::UdpPacket;
|
||||||
|
|
||||||
use crate::ip_proxy::ProxyHandler;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct UdpProxy {
|
pub struct UdpProxy {
|
||||||
port: u16,
|
port: u16,
|
||||||
@@ -20,7 +20,7 @@ pub struct UdpProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UdpProxy {
|
impl UdpProxy {
|
||||||
pub async fn new() -> anyhow::Result<Self> {
|
pub async fn new(default_interface: LocalInterface) -> anyhow::Result<Self> {
|
||||||
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
|
let nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>> =
|
||||||
Arc::new(Mutex::new(HashMap::with_capacity(16)));
|
Arc::new(Mutex::new(HashMap::with_capacity(16)));
|
||||||
let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0))
|
let udp = UdpSocket::bind(format!("0.0.0.0:{}", 0))
|
||||||
@@ -29,8 +29,8 @@ impl UdpProxy {
|
|||||||
let port = udp.local_addr()?.port();
|
let port = udp.local_addr()?.port();
|
||||||
{
|
{
|
||||||
let nat_map = nat_map.clone();
|
let nat_map = nat_map.clone();
|
||||||
tokio::spawn(async {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = udp_proxy(udp, nat_map).await {
|
if let Err(e) = udp_proxy(udp, nat_map, default_interface).await {
|
||||||
log::warn!("udp_proxy:{:?}", e);
|
log::warn!("udp_proxy:{:?}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -84,7 +84,8 @@ impl ProxyHandler for UdpProxy {
|
|||||||
async fn udp_proxy(
|
async fn udp_proxy(
|
||||||
udp: UdpSocket,
|
udp: UdpSocket,
|
||||||
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
|
nat_map: Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
|
||||||
) -> io::Result<()> {
|
default_interface: LocalInterface,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let mut buf = [0u8; 65536];
|
let mut buf = [0u8; 65536];
|
||||||
|
|
||||||
let inner_map: Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
|
let inner_map: Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>> =
|
||||||
@@ -94,9 +95,15 @@ async fn udp_proxy(
|
|||||||
match udp_socket.recv_from(&mut buf).await {
|
match udp_socket.recv_from(&mut buf).await {
|
||||||
Ok((len, sender_addr)) => match sender_addr {
|
Ok((len, sender_addr)) => match sender_addr {
|
||||||
SocketAddr::V4(sender_addr) => {
|
SocketAddr::V4(sender_addr) => {
|
||||||
if let Err(e) =
|
if let Err(e) = udp_proxy0(
|
||||||
udp_proxy0(&buf[..len], sender_addr, &inner_map, &nat_map, &udp_socket)
|
&buf[..len],
|
||||||
.await
|
sender_addr,
|
||||||
|
&inner_map,
|
||||||
|
&nat_map,
|
||||||
|
&udp_socket,
|
||||||
|
&default_interface,
|
||||||
|
)
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
log::warn!("udp proxy {} {:?}", sender_addr, e);
|
log::warn!("udp proxy {} {:?}", sender_addr, e);
|
||||||
}
|
}
|
||||||
@@ -116,7 +123,8 @@ async fn udp_proxy0(
|
|||||||
inner_map: &Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
|
inner_map: &Arc<Mutex<HashMap<SocketAddrV4, (Arc<UdpSocket>, Arc<AtomicCell<Instant>>)>>>,
|
||||||
map: &Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
|
map: &Arc<Mutex<HashMap<SocketAddrV4, SocketAddrV4>>>,
|
||||||
udp_socket: &Arc<UdpSocket>,
|
udp_socket: &Arc<UdpSocket>,
|
||||||
) -> io::Result<()> {
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let option = inner_map.lock().get(&sender_addr).cloned();
|
let option = inner_map.lock().get(&sender_addr).cloned();
|
||||||
if let Some((udp, time)) = option {
|
if let Some((udp, time)) = option {
|
||||||
time.store(Instant::now());
|
time.store(Instant::now());
|
||||||
@@ -125,11 +133,14 @@ async fn udp_proxy0(
|
|||||||
let option = map.lock().get(&sender_addr).cloned();
|
let option = map.lock().get(&sender_addr).cloned();
|
||||||
if let Some(dest_addr) = option {
|
if let Some(dest_addr) = option {
|
||||||
//先使用相同的端口,冲突了再随机端口
|
//先使用相同的端口,冲突了再随机端口
|
||||||
let peer_udp_socket =
|
let peer_udp_socket = match bind_udp(
|
||||||
match UdpSocket::bind(format!("0.0.0.0:{}", sender_addr.port())).await {
|
format!("0.0.0.0:{}", sender_addr.port()).parse().unwrap(),
|
||||||
Ok(udp) => udp,
|
default_interface,
|
||||||
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
|
) {
|
||||||
};
|
Ok(udp) => udp,
|
||||||
|
Err(_) => bind_udp("0.0.0.0:0".parse().unwrap(), default_interface)?,
|
||||||
|
};
|
||||||
|
let peer_udp_socket = UdpSocket::from_std(peer_udp_socket.into())?;
|
||||||
peer_udp_socket.connect(dest_addr).await?;
|
peer_udp_socket.connect(dest_addr).await?;
|
||||||
peer_udp_socket.send(buf).await?;
|
peer_udp_socket.send(buf).await?;
|
||||||
let peer_udp_socket = Arc::new(peer_udp_socket);
|
let peer_udp_socket = Arc::new(peer_udp_socket);
|
||||||
|
|||||||
+17
-5
@@ -3,17 +3,29 @@ pub const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
|||||||
pub mod channel;
|
pub mod channel;
|
||||||
pub mod cipher;
|
pub mod cipher;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod external_route;
|
mod external_route;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
pub mod ip_proxy;
|
mod ip_proxy;
|
||||||
pub mod nat;
|
pub mod nat;
|
||||||
#[cfg(feature = "port_mapping")]
|
#[cfg(feature = "port_mapping")]
|
||||||
pub mod port_mapping;
|
mod port_mapping;
|
||||||
pub mod proto;
|
mod proto;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
pub mod tun_tap_device;
|
mod tun_tap_device;
|
||||||
|
pub use tun_tap_device::*;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
pub use handle::callback::*;
|
pub use handle::callback::*;
|
||||||
|
|
||||||
pub mod compression;
|
pub mod compression;
|
||||||
|
pub use packet;
|
||||||
|
|
||||||
|
pub(crate) fn ignore_io_interrupted(e: std::io::Error) -> std::io::Result<()> {
|
||||||
|
if e.kind() == std::io::ErrorKind::Interrupted {
|
||||||
|
log::warn!("ignore_io_interrupted");
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+153
-68
@@ -1,17 +1,19 @@
|
|||||||
use anyhow::Context;
|
use anyhow::{anyhow, Context};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
|
||||||
use std::net::{SocketAddr, UdpSocket};
|
use std::net::{SocketAddr, UdpSocket};
|
||||||
use std::ops::Sub;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use rand::prelude::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::channel::punch::{NatInfo, NatType};
|
use crate::channel::punch::{NatInfo, NatType, PunchModel};
|
||||||
use crate::proto::message::PunchNatType;
|
use crate::channel::socket::LocalInterface;
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
use crate::util::UPnP;
|
||||||
|
|
||||||
mod stun;
|
mod stun;
|
||||||
|
|
||||||
@@ -47,12 +49,62 @@ pub fn local_ipv6_() -> io::Result<Ipv6Addr> {
|
|||||||
|
|
||||||
pub fn local_ipv6() -> Option<Ipv6Addr> {
|
pub fn local_ipv6() -> Option<Ipv6Addr> {
|
||||||
match local_ipv6_() {
|
match local_ipv6_() {
|
||||||
Ok(ipv6) => Some(ipv6),
|
Ok(ipv6) => {
|
||||||
|
if is_ipv6_global(&ipv6) {
|
||||||
|
return Some(ipv6);
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("获取ipv6失败:{:?}", e);
|
log::warn!("获取ipv6失败:{:?}", e);
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn is_ipv4_global(ipv4: &Ipv4Addr) -> bool {
|
||||||
|
!(ipv4.octets()[0] == 0 // "This network"
|
||||||
|
|| ipv4.is_private()
|
||||||
|
|| ipv4.octets()[0] == 100 && (ipv4.octets()[1] & 0b1100_0000 == 0b0100_0000)//ipv4.is_shared()
|
||||||
|
|| ipv4.is_loopback()
|
||||||
|
|| ipv4.is_link_local()
|
||||||
|
// addresses reserved for future protocols (`192.0.0.0/24`)
|
||||||
|
// .9 and .10 are documented as globally reachable so they're excluded
|
||||||
|
|| (
|
||||||
|
ipv4.octets()[0] == 192 && ipv4.octets()[1] == 0 && ipv4.octets()[2] == 0
|
||||||
|
&& ipv4.octets()[3] != 9 && ipv4.octets()[3] != 10
|
||||||
|
)
|
||||||
|
|| ipv4.is_documentation()
|
||||||
|
|| ipv4.octets()[0] == 198 && (ipv4.octets()[1] & 0xfe) == 18//ipv4.is_benchmarking()
|
||||||
|
|| ipv4.octets()[0] & 240 == 240 && !ipv4.is_broadcast()//ipv4.is_reserved()
|
||||||
|
|| ipv4.is_broadcast())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn is_ipv6_global(ipv6addr: &Ipv6Addr) -> bool {
|
||||||
|
!(ipv6addr.is_unspecified()
|
||||||
|
|| ipv6addr.is_loopback()
|
||||||
|
// IPv4-mapped Address (`::ffff:0:0/96`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
|
||||||
|
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
|
||||||
|
// Discard-Only Address Block (`100::/64`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x100, 0, 0, 0, _, _, _, _])
|
||||||
|
// IETF Protocol Assignments (`2001::/23`)
|
||||||
|
|| (matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
|
||||||
|
&& !(
|
||||||
|
// Port Control Protocol Anycast (`2001:1::1`)
|
||||||
|
u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
|
||||||
|
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|
||||||
|
|| u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
|
||||||
|
// AMT (`2001:3::/32`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x2001, 3, _, _, _, _, _, _])
|
||||||
|
// AS112-v6 (`2001:4:112::/48`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|
||||||
|
// ORCHIDv2 (`2001:20::/28`)
|
||||||
|
|| matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
|
||||||
|
))
|
||||||
|
|| (ipv6addr.segments()[0] == 0x2001) && (ipv6addr.segments()[1] == 0xdb8)//ipv6addr.is_documentation()
|
||||||
|
|| (ipv6addr.segments()[0] & 0xfe00) == 0xfc00//ipv6addr.is_unique_local()
|
||||||
|
|| (ipv6addr.segments()[0] & 0xffc0) == 0xfe80) //ipv6addr.is_unicast_link_local())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -62,38 +114,22 @@ pub struct NatTest {
|
|||||||
time: Arc<AtomicCell<Instant>>,
|
time: Arc<AtomicCell<Instant>>,
|
||||||
udp_ports: Vec<u16>,
|
udp_ports: Vec<u16>,
|
||||||
tcp_port: u16,
|
tcp_port: u16,
|
||||||
}
|
#[cfg(feature = "upnp")]
|
||||||
|
upnp: UPnP,
|
||||||
impl From<NatType> for PunchNatType {
|
pub(crate) update_local_ipv4: bool,
|
||||||
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 {
|
impl NatTest {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_channel_num: usize,
|
_channel_num: usize,
|
||||||
mut stun_server: Vec<String>,
|
stun_server: Vec<String>,
|
||||||
local_ipv4: Option<Ipv4Addr>,
|
local_ipv4: Option<Ipv4Addr>,
|
||||||
ipv6: Option<Ipv6Addr>,
|
ipv6: Option<Ipv6Addr>,
|
||||||
udp_ports: Vec<u16>,
|
udp_ports: Vec<u16>,
|
||||||
tcp_port: u16,
|
tcp_port: u16,
|
||||||
|
update_local_ipv4: bool,
|
||||||
|
punch_model: PunchModel,
|
||||||
) -> NatTest {
|
) -> NatTest {
|
||||||
if stun_server.len() > 5 {
|
|
||||||
stun_server.truncate(5);
|
|
||||||
}
|
|
||||||
let ports = vec![0; udp_ports.len()];
|
let ports = vec![0; udp_ports.len()];
|
||||||
let nat_info = NatInfo::new(
|
let nat_info = NatInfo::new(
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
@@ -103,17 +139,33 @@ impl NatTest {
|
|||||||
ipv6,
|
ipv6,
|
||||||
udp_ports.clone(),
|
udp_ports.clone(),
|
||||||
tcp_port,
|
tcp_port,
|
||||||
|
0,
|
||||||
NatType::Cone,
|
NatType::Cone,
|
||||||
|
punch_model,
|
||||||
);
|
);
|
||||||
let info = Arc::new(Mutex::new(nat_info));
|
let info = Arc::new(Mutex::new(nat_info));
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
let upnp = UPnP::default();
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
for port in &udp_ports {
|
||||||
|
upnp.add_udp_port(*port);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
upnp.add_tcp_port(tcp_port);
|
||||||
|
let instant = Instant::now();
|
||||||
NatTest {
|
NatTest {
|
||||||
stun_server,
|
stun_server,
|
||||||
info,
|
info,
|
||||||
time: Arc::new(AtomicCell::new(
|
time: Arc::new(AtomicCell::new(
|
||||||
Instant::now().sub(Duration::from_secs(100)),
|
instant
|
||||||
|
.checked_sub(Duration::from_secs(100))
|
||||||
|
.unwrap_or(instant),
|
||||||
)),
|
)),
|
||||||
udp_ports,
|
udp_ports,
|
||||||
tcp_port,
|
tcp_port,
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
upnp,
|
||||||
|
update_local_ipv4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn can_update(&self) -> bool {
|
pub fn can_update(&self) -> bool {
|
||||||
@@ -185,25 +237,49 @@ impl NatTest {
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) {
|
pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
|
||||||
let mut guard = self.info.lock();
|
let mut guard = self.info.lock();
|
||||||
guard.update_addr(index, ip, port)
|
guard.update_addr(index, ip, port)
|
||||||
}
|
}
|
||||||
|
pub fn update_tcp_port(&self, port: u16) {
|
||||||
|
let mut guard = self.info.lock();
|
||||||
|
guard.update_tcp_port(port)
|
||||||
|
}
|
||||||
pub fn re_test(
|
pub fn re_test(
|
||||||
&self,
|
&self,
|
||||||
local_ipv4: Option<Ipv4Addr>,
|
local_ipv4: Option<Ipv4Addr>,
|
||||||
ipv6: Option<Ipv6Addr>,
|
ipv6: Option<Ipv6Addr>,
|
||||||
) -> io::Result<NatInfo> {
|
default_interface: &LocalInterface,
|
||||||
let (nat_type, public_ips, port_range) = stun::stun_test_nat(self.stun_server.clone())?;
|
) -> anyhow::Result<NatInfo> {
|
||||||
|
let mut stun_server = self.stun_server.clone();
|
||||||
|
if stun_server.len() > 5 {
|
||||||
|
stun_server.shuffle(&mut rand::thread_rng());
|
||||||
|
stun_server.truncate(5);
|
||||||
|
log::info!("stun_server truncate {:?}", stun_server);
|
||||||
|
}
|
||||||
|
let (nat_type, public_ips, port_range) =
|
||||||
|
stun::stun_test_nat(stun_server, default_interface)?;
|
||||||
|
if public_ips.is_empty() {
|
||||||
|
Err(anyhow!("public_ips.is_empty"))?
|
||||||
|
}
|
||||||
let mut guard = self.info.lock();
|
let mut guard = self.info.lock();
|
||||||
guard.nat_type = nat_type;
|
guard.nat_type = nat_type;
|
||||||
guard.public_ips = public_ips;
|
guard.public_ips = public_ips;
|
||||||
guard.public_port_range = port_range;
|
guard.public_port_range = port_range;
|
||||||
guard.local_ipv4 = local_ipv4;
|
if local_ipv4.is_some() {
|
||||||
|
guard.local_ipv4 = local_ipv4;
|
||||||
|
}
|
||||||
guard.ipv6 = ipv6;
|
guard.ipv6 = ipv6;
|
||||||
|
|
||||||
Ok(guard.clone())
|
Ok(guard.clone())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
pub fn reset_upnp(&self) {
|
||||||
|
let local_ipv4 = self.info.lock().local_ipv4.clone();
|
||||||
|
if let Some(local_ipv4) = local_ipv4 {
|
||||||
|
self.upnp.reset(local_ipv4)
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn send_data(&self) -> anyhow::Result<(Vec<u8>, SocketAddr)> {
|
pub fn send_data(&self) -> anyhow::Result<(Vec<u8>, SocketAddr)> {
|
||||||
let len = self.stun_server.len();
|
let len = self.stun_server.len();
|
||||||
let stun_server = if len == 1 {
|
let stun_server = if len == 1 {
|
||||||
@@ -224,46 +300,55 @@ impl NatTest {
|
|||||||
source_addr: SocketAddr,
|
source_addr: SocketAddr,
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
) -> anyhow::Result<bool> {
|
) -> anyhow::Result<bool> {
|
||||||
if let Some(addr) = stun::recv_stun_response(buf) {
|
if buf[0] == 0x01 && buf[1] == 0x01 {
|
||||||
if let SocketAddr::V4(addr) = addr {
|
if let Some(addr) = stun::recv_stun_response(buf) {
|
||||||
let mut check_fail = true;
|
if let Err(e) = self.recv_data_(index, source_addr, addr) {
|
||||||
let source_ip = match source_addr.ip() {
|
log::warn!("{:?}", e);
|
||||||
IpAddr::V4(ip) => ip,
|
}
|
||||||
IpAddr::V6(ip) => {
|
}
|
||||||
if let Some(ip) = ip.to_ipv4_mapped() {
|
Ok(true)
|
||||||
ip
|
} else {
|
||||||
} else {
|
Ok(false)
|
||||||
return Ok(false);
|
}
|
||||||
}
|
}
|
||||||
}
|
fn recv_data_(
|
||||||
};
|
&self,
|
||||||
'a: for stun_server in &self.stun_server {
|
index: usize,
|
||||||
for x in stun_server.to_socket_addrs()? {
|
source_addr: SocketAddr,
|
||||||
if source_addr.port() == x.port() {
|
addr: SocketAddr,
|
||||||
if let IpAddr::V4(ip) = x.ip() {
|
) -> anyhow::Result<()> {
|
||||||
if ip == source_ip {
|
if let SocketAddr::V4(addr) = addr {
|
||||||
check_fail = false;
|
let mut check_fail = true;
|
||||||
break 'a;
|
let source_ip = match source_addr.ip() {
|
||||||
}
|
IpAddr::V4(ip) => ip,
|
||||||
};
|
IpAddr::V6(ip) => {
|
||||||
}
|
if let Some(ip) = ip.to_ipv4() {
|
||||||
|
ip
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if check_fail {
|
};
|
||||||
return Ok(false);
|
'a: for stun_server in &self.stun_server {
|
||||||
|
for x in stun_server.to_socket_addrs()? {
|
||||||
|
if source_addr.port() == x.port() {
|
||||||
|
if let IpAddr::V4(ip) = x.ip() {
|
||||||
|
if ip == source_ip {
|
||||||
|
check_fail = false;
|
||||||
|
break 'a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let ip = addr.ip();
|
}
|
||||||
if !ip.is_multicast()
|
if !check_fail {
|
||||||
&& !ip.is_broadcast()
|
if is_ipv4_global(addr.ip()) {
|
||||||
&& !ip.is_unspecified()
|
if self.update_addr(index, *addr.ip(), addr.port()) {
|
||||||
&& !ip.is_loopback()
|
log::info!("回应地址{:?},来源stun {:?}", addr, source_addr)
|
||||||
&& !ip.is_private()
|
}
|
||||||
{
|
|
||||||
self.update_addr(index, *addr.ip(), addr.port());
|
|
||||||
return Ok(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(false);
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-17
@@ -4,22 +4,21 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::channel::punch::NatType;
|
use crate::channel::punch::NatType;
|
||||||
|
use crate::channel::socket::{bind_udp, LocalInterface};
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
use stun_format::Attr;
|
use stun_format::Attr;
|
||||||
|
|
||||||
pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
pub fn stun_test_nat(
|
||||||
let mut th = Vec::new();
|
stun_servers: Vec<String>,
|
||||||
for _ in 0..2 {
|
default_interface: &LocalInterface,
|
||||||
let stun_servers = stun_servers.clone();
|
) -> anyhow::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||||
let handle = std::thread::spawn(move || stun_test_nat0(stun_servers));
|
|
||||||
th.push(handle);
|
|
||||||
}
|
|
||||||
let mut nat_type = NatType::Cone;
|
let mut nat_type = NatType::Cone;
|
||||||
let mut port_range = 0;
|
let mut port_range = 0;
|
||||||
let mut hash_set = HashSet::new();
|
let mut hash_set = HashSet::new();
|
||||||
for x in th {
|
for _ in 0..2 {
|
||||||
match x.join().unwrap() {
|
let stun_servers = stun_servers.clone();
|
||||||
|
match stun_test_nat0(stun_servers, default_interface) {
|
||||||
Ok((nat_type_t, ip_list_t, port_range_t)) => {
|
Ok((nat_type_t, ip_list_t, port_range_t)) => {
|
||||||
if nat_type_t == NatType::Symmetric {
|
if nat_type_t == NatType::Symmetric {
|
||||||
nat_type = NatType::Symmetric;
|
nat_type = NatType::Symmetric;
|
||||||
@@ -39,8 +38,13 @@ pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4
|
|||||||
Ok((nat_type, hash_set.into_iter().collect(), port_range))
|
Ok((nat_type, hash_set.into_iter().collect(), port_range))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stun_test_nat0(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
pub fn stun_test_nat0(
|
||||||
let udp = UdpSocket::bind("0.0.0.0:0")?;
|
stun_servers: Vec<String>,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||||
|
let udp = bind_udp("0.0.0.0:0".parse().unwrap(), default_interface)?;
|
||||||
|
udp.set_nonblocking(false)?;
|
||||||
|
let udp: UdpSocket = udp.into();
|
||||||
udp.set_read_timeout(Some(Duration::from_millis(500)))?;
|
udp.set_read_timeout(Some(Duration::from_millis(500)))?;
|
||||||
let mut nat_type = NatType::Cone;
|
let mut nat_type = NatType::Cone;
|
||||||
let mut min_port = u16::MAX;
|
let mut min_port = u16::MAX;
|
||||||
@@ -86,13 +90,13 @@ fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketA
|
|||||||
udp.connect(stun_server)?;
|
udp.connect(stun_server)?;
|
||||||
let tid = rand::thread_rng().next_u64() as u128;
|
let tid = rand::thread_rng().next_u64() as u128;
|
||||||
let mut addr = HashSet::new();
|
let mut addr = HashSet::new();
|
||||||
let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?;
|
let (mapped_addr1, changed_addr1) = test_nat_(&udp, stun_server, true, true, tid)?;
|
||||||
if mapped_addr1.is_ipv4() {
|
if mapped_addr1.is_ipv4() {
|
||||||
addr.insert(mapped_addr1);
|
addr.insert(mapped_addr1);
|
||||||
}
|
}
|
||||||
if let Some(changed_addr1) = changed_addr1 {
|
if let Some(changed_addr1) = changed_addr1 {
|
||||||
if udp.connect(changed_addr1).is_ok() {
|
if udp.connect(changed_addr1).is_ok() {
|
||||||
match test_nat_(&udp, false, false, tid + 1) {
|
match test_nat_(&udp, stun_server, false, false, tid + 1) {
|
||||||
Ok((mapped_addr2, _)) => {
|
Ok((mapped_addr2, _)) => {
|
||||||
if mapped_addr2.is_ipv4() {
|
if mapped_addr2.is_ipv4() {
|
||||||
addr.insert(mapped_addr1);
|
addr.insert(mapped_addr1);
|
||||||
@@ -116,6 +120,7 @@ fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketA
|
|||||||
|
|
||||||
fn test_nat_(
|
fn test_nat_(
|
||||||
udp: &UdpSocket,
|
udp: &UdpSocket,
|
||||||
|
stun_server: &String,
|
||||||
change_ip: bool,
|
change_ip: bool,
|
||||||
change_port: bool,
|
change_port: bool,
|
||||||
tid: u128,
|
tid: u128,
|
||||||
@@ -134,7 +139,7 @@ fn test_nat_(
|
|||||||
let (len, _addr) = match udp.recv_from(&mut buf) {
|
let (len, _addr) = match udp.recv_from(&mut buf) {
|
||||||
Ok(rs) => rs,
|
Ok(rs) => rs,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("stun error {:?}", e);
|
log::warn!("stun {} error {:?}", stun_server, e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -198,9 +203,6 @@ pub fn send_stun_request() -> Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_stun_response(buf: &[u8]) -> Option<SocketAddr> {
|
pub fn recv_stun_response(buf: &[u8]) -> Option<SocketAddr> {
|
||||||
if buf[0] != 0x01 && buf[1] != 0x01 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let msg = stun_format::Msg::from(buf);
|
let msg = stun_format::Msg::from(buf);
|
||||||
if let Some(tid) = msg.tid() {
|
if let Some(tid) = msg.tid() {
|
||||||
if tid & TAG != TAG {
|
if tid & TAG != TAG {
|
||||||
|
|||||||
+13
-12
@@ -15,10 +15,10 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
|||||||
for x in vec {
|
for x in vec {
|
||||||
let string = x.trim().to_lowercase();
|
let string = x.trim().to_lowercase();
|
||||||
if let Some(udp_mapping) = string.strip_prefix("udp:") {
|
if let Some(udp_mapping) = string.strip_prefix("udp:") {
|
||||||
let mut split = udp_mapping.split("->");
|
let mut split = udp_mapping.split("-");
|
||||||
let bind_addr = split.next().with_context(|| {
|
let bind_addr = split.next().with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080",
|
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
|
||||||
x
|
x
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
@@ -26,7 +26,7 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
|||||||
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
|
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
|
||||||
let dest = split.next().with_context(|| {
|
let dest = split.next().with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080",
|
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
|
||||||
x
|
x
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
@@ -34,10 +34,10 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
|
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
|
||||||
let mut split = tcp_mapping.split("->");
|
let mut split = tcp_mapping.split("-");
|
||||||
let bind_addr = split.next().with_context(|| {
|
let bind_addr = split.next().with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
|
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
|
||||||
x
|
x
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
@@ -45,7 +45,7 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
|||||||
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
|
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
|
||||||
let dest = split.next().with_context(|| {
|
let dest = split.next().with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
|
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
|
||||||
x
|
x
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
@@ -53,7 +53,7 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(anyhow::anyhow!(
|
Err(anyhow::anyhow!(
|
||||||
"port_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
|
"port_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
|
||||||
x
|
x
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
@@ -66,11 +66,7 @@ pub fn start_port_mapping(
|
|||||||
if vec.is_empty() {
|
if vec.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
|
||||||
.enable_all()
|
|
||||||
.thread_name("portMapping")
|
|
||||||
.build()?;
|
|
||||||
runtime.block_on(start_port_mapping0(vec))?;
|
|
||||||
let (sender, receiver) = tokio::sync::oneshot::channel::<()>();
|
let (sender, receiver) = tokio::sync::oneshot::channel::<()>();
|
||||||
let worker = stop_manager.add_listener("portMapping".into(), move || {
|
let worker = stop_manager.add_listener("portMapping".into(), move || {
|
||||||
let _ = sender.send(());
|
let _ = sender.send(());
|
||||||
@@ -78,6 +74,11 @@ pub fn start_port_mapping(
|
|||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("portMapping".into())
|
.name("portMapping".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.thread_name("portMapping")
|
||||||
|
.build().unwrap();
|
||||||
|
runtime.block_on(start_port_mapping0(vec)).unwrap();
|
||||||
runtime.block_on(async {
|
runtime.block_on(async {
|
||||||
let _ = receiver.await;
|
let _ = receiver.await;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ pub async fn tcp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::
|
|||||||
let tcp_listener = TcpListener::bind(bind_addr)
|
let tcp_listener = TcpListener::bind(bind_addr)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("TCP binding {:?} failed", bind_addr))?;
|
.with_context(|| format!("TCP binding {:?} failed", bind_addr))?;
|
||||||
tokio::spawn(tcp_mapping_(bind_addr, tcp_listener, destination));
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = tcp_mapping_(bind_addr, tcp_listener, destination).await {
|
||||||
|
log::warn!("tcp_mapping {:?}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +32,7 @@ async fn tcp_mapping_(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn copy(source_tcp: TcpStream, destination: &String) -> anyhow::Result<()> {
|
async fn copy(source_tcp: TcpStream, destination: &String) -> anyhow::Result<()> {
|
||||||
|
// 或许这里也应该绑定最匹配的网卡,不然全局代理会影响映射
|
||||||
let dest_tcp = TcpStream::connect(destination)
|
let dest_tcp = TcpStream::connect(destination)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("TCP connection target failed {:?}", destination))?;
|
.with_context(|| format!("TCP connection target failed {:?}", destination))?;
|
||||||
|
|||||||
@@ -4,6 +4,261 @@ pub const ENCRYPTION_RESERVED: usize = 16 + 32 + 12;
|
|||||||
pub const AES_GCM_ENCRYPTION_RESERVED: usize = 32;
|
pub const AES_GCM_ENCRYPTION_RESERVED: usize = 32;
|
||||||
pub const RSA_ENCRYPTION_RESERVED: usize = 32;
|
pub const RSA_ENCRYPTION_RESERVED: usize = 32;
|
||||||
|
|
||||||
|
pub const RANDOM_RESERVED: usize = 4;
|
||||||
|
pub const FINGER_RESERVED: usize = 12;
|
||||||
|
pub const TAG_RESERVED: usize = 16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| random(32) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| finger(32) |
|
||||||
|
| finger(32) |
|
||||||
|
| finger(32) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
pub trait SecretTail {
|
||||||
|
fn buffer(&self) -> &[u8];
|
||||||
|
fn exist_finger(&self) -> bool;
|
||||||
|
fn random_buf(&self) -> &[u8] {
|
||||||
|
let buf = self.buffer();
|
||||||
|
let mut end = buf.len();
|
||||||
|
if self.exist_finger() {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
&buf[end - RANDOM_RESERVED..end]
|
||||||
|
}
|
||||||
|
fn finger(&self) -> &[u8] {
|
||||||
|
if self.exist_finger() {
|
||||||
|
let buf = self.buffer();
|
||||||
|
let end = buf.len();
|
||||||
|
&buf[end - FINGER_RESERVED..end]
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SecretTailMut: SecretTail {
|
||||||
|
fn buffer_mut(&mut self) -> &mut [u8];
|
||||||
|
fn set_random(&mut self, random: &[u8]) {
|
||||||
|
let f = self.exist_finger();
|
||||||
|
let buf = self.buffer_mut();
|
||||||
|
let mut end = buf.len();
|
||||||
|
if f {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
buf[end - RANDOM_RESERVED..end].copy_from_slice(random);
|
||||||
|
}
|
||||||
|
fn set_finger(&mut self, finger: &[u8]) -> io::Result<()> {
|
||||||
|
if self.exist_finger() {
|
||||||
|
if finger.len() != FINGER_RESERVED {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
"finger.len != 12",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let buf = self.buffer_mut();
|
||||||
|
let end = buf.len();
|
||||||
|
buf[end - FINGER_RESERVED..end].copy_from_slice(finger);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
"not exist finger",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* aead加密数据体
|
||||||
|
0 15 31
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| 数据体 |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| tag(32) |
|
||||||
|
| tag(32) |
|
||||||
|
| tag(32) |
|
||||||
|
| tag(32) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| random(32) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| finger(32) |
|
||||||
|
| finger(32) |
|
||||||
|
| finger(32) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
注:finger用于快速校验数据是否被修改,上层可使用token、协议头参与计算finger,
|
||||||
|
确保服务端和客户端都能感知修改(服务端不能解密也能校验指纹)
|
||||||
|
*/
|
||||||
|
pub struct AEADSecretBody<B> {
|
||||||
|
buffer: B,
|
||||||
|
exist_finger: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> AEADSecretBody<B> {
|
||||||
|
pub fn new(buffer: B, exist_finger: bool) -> io::Result<AEADSecretBody<B>> {
|
||||||
|
let len = buffer.as_ref().len();
|
||||||
|
let min_len = if exist_finger {
|
||||||
|
TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED
|
||||||
|
} else {
|
||||||
|
TAG_RESERVED + RANDOM_RESERVED
|
||||||
|
};
|
||||||
|
// 不能大于udp最大载荷长度
|
||||||
|
if len < min_len || len > 65535 - 20 - 8 - 12 {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("AEADSecretBody length overflow {}", len),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(AEADSecretBody {
|
||||||
|
buffer,
|
||||||
|
exist_finger,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn data(&self) -> &[u8] {
|
||||||
|
let mut end = self.buffer.as_ref().len() - TAG_RESERVED - RANDOM_RESERVED;
|
||||||
|
if self.exist_finger {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
&self.buffer.as_ref()[..end]
|
||||||
|
}
|
||||||
|
pub fn tag(&self) -> &[u8] {
|
||||||
|
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
|
||||||
|
if self.exist_finger {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
&self.buffer.as_ref()[end - TAG_RESERVED..end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> SecretTail for AEADSecretBody<B> {
|
||||||
|
#[inline]
|
||||||
|
fn buffer(&self) -> &[u8] {
|
||||||
|
self.buffer.as_ref()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn exist_finger(&self) -> bool {
|
||||||
|
self.exist_finger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretTailMut for AEADSecretBody<B> {
|
||||||
|
#[inline]
|
||||||
|
fn buffer_mut(&mut self) -> &mut [u8] {
|
||||||
|
self.buffer.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> AEADSecretBody<B> {
|
||||||
|
/// 数据部分
|
||||||
|
pub fn data_mut(&mut self) -> &mut [u8] {
|
||||||
|
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED - TAG_RESERVED;
|
||||||
|
if self.exist_finger {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
&mut self.buffer.as_mut()[..end]
|
||||||
|
}
|
||||||
|
/// 数据和tag部分
|
||||||
|
pub fn data_tag_mut(&mut self) -> &mut [u8] {
|
||||||
|
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
|
||||||
|
if self.exist_finger {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
&mut self.buffer.as_mut()[..end]
|
||||||
|
}
|
||||||
|
pub fn set_tag(&mut self, tag: &[u8]) -> io::Result<()> {
|
||||||
|
if tag.len() != 16 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::InvalidData, "tag.len != 16"));
|
||||||
|
}
|
||||||
|
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
|
||||||
|
if self.exist_finger {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
self.buffer.as_mut()[end - TAG_RESERVED..end].copy_from_slice(tag);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 带随机数的加密数据体
|
||||||
|
0 15 31
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| 数据体 |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| random(32) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| finger(32) |
|
||||||
|
| finger(32) |
|
||||||
|
| finger(32) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
注:finger用于快速校验数据是否被修改,上层可使用token、协议头参与计算finger,
|
||||||
|
确保服务端和客户端都能感知修改(服务端不能解密也能校验指纹)
|
||||||
|
*/
|
||||||
|
pub struct IVSecretBody<B> {
|
||||||
|
buffer: B,
|
||||||
|
exist_finger: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> IVSecretBody<B> {
|
||||||
|
pub fn new(buffer: B, exist_finger: bool) -> io::Result<IVSecretBody<B>> {
|
||||||
|
let len = buffer.as_ref().len();
|
||||||
|
let min_len = if exist_finger {
|
||||||
|
FINGER_RESERVED + RANDOM_RESERVED
|
||||||
|
} else {
|
||||||
|
RANDOM_RESERVED
|
||||||
|
};
|
||||||
|
// 不能大于udp最大载荷长度
|
||||||
|
if len < min_len || len > 65535 - 20 - 8 - 12 {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
format!("IVSecretBody length overflow {}", len),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(IVSecretBody {
|
||||||
|
buffer,
|
||||||
|
exist_finger,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn data(&self) -> &[u8] {
|
||||||
|
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
|
||||||
|
if self.exist_finger {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
&self.buffer.as_ref()[..end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> IVSecretBody<B> {
|
||||||
|
pub fn data_mut(&mut self) -> &mut [u8] {
|
||||||
|
let mut end = self.buffer.as_ref().len() - RANDOM_RESERVED;
|
||||||
|
if self.exist_finger {
|
||||||
|
end -= FINGER_RESERVED;
|
||||||
|
}
|
||||||
|
&mut self.buffer.as_mut()[..end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> SecretTail for IVSecretBody<B> {
|
||||||
|
#[inline]
|
||||||
|
fn buffer(&self) -> &[u8] {
|
||||||
|
self.buffer.as_ref()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn exist_finger(&self) -> bool {
|
||||||
|
self.exist_finger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> SecretTailMut for IVSecretBody<B> {
|
||||||
|
#[inline]
|
||||||
|
fn buffer_mut(&mut self) -> &mut [u8] {
|
||||||
|
self.buffer.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* aes_gcm加密数据体
|
/* aes_gcm加密数据体
|
||||||
0 15 31
|
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
|
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
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum Protocol {
|
pub enum Protocol {
|
||||||
Ipv4,
|
Ipv4,
|
||||||
|
WGIpv4,
|
||||||
Ipv4Broadcast,
|
Ipv4Broadcast,
|
||||||
Unknown(u8),
|
Unknown(u8),
|
||||||
}
|
}
|
||||||
@@ -12,16 +15,18 @@ impl From<u8> for Protocol {
|
|||||||
fn from(value: u8) -> Self {
|
fn from(value: u8) -> Self {
|
||||||
match value {
|
match value {
|
||||||
4 => Protocol::Ipv4,
|
4 => Protocol::Ipv4,
|
||||||
|
5 => Protocol::WGIpv4,
|
||||||
201 => Protocol::Ipv4Broadcast,
|
201 => Protocol::Ipv4Broadcast,
|
||||||
val => Protocol::Unknown(val),
|
val => Protocol::Unknown(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u8> for Protocol {
|
impl From<Protocol> for u8 {
|
||||||
fn into(self) -> u8 {
|
fn from(val: Protocol) -> Self {
|
||||||
match self {
|
match val {
|
||||||
Protocol::Ipv4 => 4,
|
Protocol::Ipv4 => 4,
|
||||||
|
Protocol::WGIpv4 => 5,
|
||||||
Protocol::Ipv4Broadcast => 201,
|
Protocol::Ipv4Broadcast => 201,
|
||||||
Protocol::Unknown(val) => val,
|
Protocol::Unknown(val) => val,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::{fmt, io};
|
|||||||
0 15 31
|
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
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|e |s |u |u| 版本(4) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
|
|e |s |x |u| 版本(4) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| 源ip地址(32) |
|
| 源ip地址(32) |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@@ -14,7 +14,7 @@ use std::{fmt, io};
|
|||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| 数据体 |
|
| 数据体 |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
注:e为是否加密标志,s为服务端通信包标志,u未使用
|
注:e为是否加密标志,s为服务端通信包标志,x扩展标志,u未使用
|
||||||
*/
|
*/
|
||||||
pub const HEAD_LEN: usize = 12;
|
pub const HEAD_LEN: usize = 12;
|
||||||
|
|
||||||
@@ -128,15 +128,15 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
|
|||||||
"length overflow",
|
"length overflow",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// 不能大于udp最大载荷长度
|
if data_len < 12 {
|
||||||
if data_len < 12 || data_len > 65535 - 20 - 8 {
|
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
io::ErrorKind::InvalidData,
|
||||||
"length overflow",
|
"data_len too short",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(NetPacket { data_len, buffer })
|
Ok(NetPacket { data_len, buffer })
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
pub fn buffer(&self) -> &[u8] {
|
pub fn buffer(&self) -> &[u8] {
|
||||||
&self.buffer.as_ref()[..self.data_len]
|
&self.buffer.as_ref()[..self.data_len]
|
||||||
}
|
}
|
||||||
@@ -214,8 +214,7 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
|||||||
}
|
}
|
||||||
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
|
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
|
||||||
if is_gateway {
|
if is_gateway {
|
||||||
// 后面的版本再改为0x40,改了之后不兼容1.2.5之前的版本
|
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x40
|
||||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
|
|
||||||
} else {
|
} else {
|
||||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
|
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,85 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tun::device::IFace;
|
use tun_rs::SyncDevice;
|
||||||
use tun::Device;
|
|
||||||
|
use crate::{DeviceConfig, ErrorInfo, ErrorType, VntCallback};
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||||
const DEFAULT_TUN_NAME: &str = "vnt-tun";
|
const DEFAULT_TUN_NAME: &str = "vnt-tun";
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
const DEFAULT_TAP_NAME: &str = "vnt-tap";
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
pub fn create_device<Call: VntCallback>(
|
||||||
pub fn create_device(config: &crate::core::Config) -> io::Result<Arc<Device>> {
|
config: DeviceConfig,
|
||||||
#[cfg(target_os = "windows")]
|
call: &Call,
|
||||||
let default_name: &str = if config.tap {
|
) -> Result<Arc<SyncDevice>, ErrorInfo> {
|
||||||
DEFAULT_TAP_NAME
|
let device = match create_device0(&config) {
|
||||||
} else {
|
Ok(device) => device,
|
||||||
DEFAULT_TUN_NAME
|
Err(e) => {
|
||||||
|
return Err(ErrorInfo::new_msg(
|
||||||
|
ErrorType::FailedToCrateDevice,
|
||||||
|
format!("create device {:?}", e),
|
||||||
|
));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
#[cfg(windows)]
|
||||||
|
let index = device.if_index().unwrap();
|
||||||
|
#[cfg(unix)]
|
||||||
|
let index = &device.name().unwrap();
|
||||||
|
if let Err(e) = add_route(index, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST) {
|
||||||
|
log::warn!("添加广播路由失败 ={:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = add_route(
|
||||||
|
index,
|
||||||
|
Ipv4Addr::from([224, 0, 0, 0]),
|
||||||
|
Ipv4Addr::from([240, 0, 0, 0]),
|
||||||
|
) {
|
||||||
|
log::warn!("添加组播路由失败 ={:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dest, mask) in config.external_route {
|
||||||
|
if let Err(e) = add_route(index, dest, mask) {
|
||||||
|
log::warn!("添加路由失败,请检查-i参数是否和现有路由冲突 ={:?}", e);
|
||||||
|
call.error(ErrorInfo::new_msg(
|
||||||
|
ErrorType::Warn,
|
||||||
|
format!(
|
||||||
|
"警告! 添加路由失败,请检查-i参数是否和现有路由冲突 ={:?}",
|
||||||
|
e
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_device0(config: &DeviceConfig) -> io::Result<Arc<SyncDevice>> {
|
||||||
|
let mut tun_builder = tun_rs::DeviceBuilder::default();
|
||||||
|
tun_builder = tun_builder.ipv4(config.virtual_ip, config.virtual_netmask, None);
|
||||||
|
|
||||||
|
match &config.device_name {
|
||||||
|
None => {
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||||
|
{
|
||||||
|
tun_builder = tun_builder.name(DEFAULT_TUN_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(name) => {
|
||||||
|
tun_builder = tun_builder.name(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
let name = config
|
||||||
|
.device_name
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| DEFAULT_TUN_NAME.to_string());
|
||||||
|
_ = delete_adapter_info_from_reg(&name);
|
||||||
|
tun_builder = tun_builder.metric(0).ring_capacity(4 * 1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
let device = {
|
{
|
||||||
let device_name = config
|
let device_name = config
|
||||||
.device_name
|
.device_name
|
||||||
.clone()
|
.clone()
|
||||||
@@ -25,27 +87,10 @@ pub fn create_device(config: &crate::core::Config) -> io::Result<Arc<Device>> {
|
|||||||
if &device_name == DEFAULT_TUN_NAME {
|
if &device_name == DEFAULT_TUN_NAME {
|
||||||
delete_device(DEFAULT_TUN_NAME);
|
delete_device(DEFAULT_TUN_NAME);
|
||||||
}
|
}
|
||||||
Arc::new(Device::new(Some(device_name))?)
|
}
|
||||||
};
|
|
||||||
#[cfg(target_os = "macos")]
|
let device = tun_builder.mtu(config.mtu as u16).build_sync()?;
|
||||||
let device = Arc::new(Device::new(config.device_name.clone())?);
|
Ok(Arc::new(device))
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
let device = Arc::new(Device::new(
|
|
||||||
config
|
|
||||||
.device_name
|
|
||||||
.clone()
|
|
||||||
.unwrap_or(default_name.to_string()),
|
|
||||||
config.tap,
|
|
||||||
)?);
|
|
||||||
let mtu = config.mtu.unwrap_or_else(|| {
|
|
||||||
if config.password.is_none() {
|
|
||||||
1450
|
|
||||||
} else {
|
|
||||||
1410
|
|
||||||
}
|
|
||||||
});
|
|
||||||
device.set_mtu(mtu)?;
|
|
||||||
Ok(device)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@@ -62,3 +107,135 @@ fn delete_device(name: &str) {
|
|||||||
log::warn!("删除网卡失败:{:?}", delete_tun);
|
log::warn!("删除网卡失败:{:?}", delete_tun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn delete_adapter_info_from_reg(dev_name: &str) -> std::io::Result<()> {
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use winreg::{enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS, RegKey};
|
||||||
|
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||||
|
let profiles_key = hklm.open_subkey_with_flags(
|
||||||
|
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles",
|
||||||
|
KEY_ALL_ACCESS,
|
||||||
|
)?;
|
||||||
|
let mut profile_guid_set = HashSet::new();
|
||||||
|
for sub_key_name in profiles_key.enum_keys().filter_map(Result::ok) {
|
||||||
|
let sub_key = profiles_key.open_subkey(&sub_key_name)?;
|
||||||
|
match sub_key.get_value::<String, _>("Description") {
|
||||||
|
Ok(profile_name) => {
|
||||||
|
if dev_name == profile_name {
|
||||||
|
match profiles_key.delete_subkey_all(&sub_key_name) {
|
||||||
|
Ok(_) => {
|
||||||
|
log::info!("deleted Profiles sub_key: {}", sub_key_name);
|
||||||
|
profile_guid_set.insert(sub_key_name);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Failed to delete Profiles sub_key {}: {}", sub_key_name, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => log::warn!(
|
||||||
|
"Failed to read Description for sub_key {}: {}",
|
||||||
|
sub_key_name,
|
||||||
|
e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let unmanaged_key = hklm.open_subkey_with_flags(
|
||||||
|
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged",
|
||||||
|
KEY_ALL_ACCESS,
|
||||||
|
)?;
|
||||||
|
for sub_key_name in unmanaged_key.enum_keys().filter_map(Result::ok) {
|
||||||
|
let sub_key = unmanaged_key.open_subkey(&sub_key_name)?;
|
||||||
|
match sub_key.get_value::<String, _>("ProfileGuid") {
|
||||||
|
Ok(profile_guid) => {
|
||||||
|
if profile_guid_set.contains(&profile_guid) {
|
||||||
|
match unmanaged_key.delete_subkey_all(&sub_key_name) {
|
||||||
|
Ok(_) => log::info!("deleted Unmanaged sub_key: {}", sub_key_name),
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Failed to delete Unmanaged sub_key {}: {}", sub_key_name, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => log::warn!(
|
||||||
|
"Failed to read Description for sub_key {}: {}",
|
||||||
|
sub_key_name,
|
||||||
|
e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub fn add_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||||
|
let cmd = format!(
|
||||||
|
"route add {:?} mask {:?} {:?} metric {} if {}",
|
||||||
|
dest,
|
||||||
|
netmask,
|
||||||
|
Ipv4Addr::UNSPECIFIED,
|
||||||
|
1,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
exe_cmd(&cmd)
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub fn exe_cmd(cmd: &str) -> io::Result<()> {
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
|
println!("exe cmd: {}", cmd);
|
||||||
|
let out = std::process::Command::new("cmd")
|
||||||
|
.creation_flags(windows_sys::Win32::System::Threading::CREATE_NO_WINDOW)
|
||||||
|
.arg("/C")
|
||||||
|
.arg(&cmd)
|
||||||
|
.output()?;
|
||||||
|
if !out.status.success() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("cmd={},out={:?}", cmd, String::from_utf8(out.stderr)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||||
|
let cmd = format!(
|
||||||
|
"route -n add {} -netmask {} -interface {}",
|
||||||
|
address, netmask, name
|
||||||
|
);
|
||||||
|
exe_cmd(&cmd)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||||
|
let cmd = if netmask.is_broadcast() {
|
||||||
|
format!("route add -host {:?} {}", address, name)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"route add -net {}/{} {}",
|
||||||
|
address,
|
||||||
|
u32::from(netmask).count_ones(),
|
||||||
|
name
|
||||||
|
)
|
||||||
|
};
|
||||||
|
exe_cmd(&cmd)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
pub fn exe_cmd(cmd: &str) -> io::Result<std::process::Output> {
|
||||||
|
use std::process::Command;
|
||||||
|
println!("exe cmd: {}", cmd);
|
||||||
|
let out = Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(cmd)
|
||||||
|
.output()
|
||||||
|
.expect("sh exec error!");
|
||||||
|
if !out.status.success() {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("cmd={},out={:?}", cmd, out),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
pub use create_device::create_device;
|
pub use create_device::create_device;
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
mod create_device;
|
mod create_device;
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
pub mod tun_create_helper;
|
pub mod tun_create_helper;
|
||||||
|
|
||||||
|
pub mod vnt_device;
|
||||||
|
|||||||
@@ -1,72 +1,62 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
|
|
||||||
use tun::Device;
|
|
||||||
|
|
||||||
use crate::channel::context::ChannelContext;
|
use crate::channel::context::ChannelContext;
|
||||||
use crate::cipher::Cipher;
|
use crate::cipher::Cipher;
|
||||||
use crate::compression::Compressor;
|
use crate::compression::Compressor;
|
||||||
use crate::external_route::ExternalRoute;
|
use crate::external_route::ExternalRoute;
|
||||||
|
use crate::handle::tun_tap::DeviceStop;
|
||||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
use crate::ip_proxy::IpProxyMap;
|
use crate::ip_proxy::IpProxyMap;
|
||||||
use crate::util::{SingleU64Adder, StopManager};
|
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
use crate::util::StopManager;
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use tun_rs::SyncDevice;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct DeviceAdapter {
|
pub struct DeviceAdapter {
|
||||||
tun: Arc<Device>,
|
tun: Arc<Mutex<Option<Arc<SyncDevice>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceAdapter {
|
impl DeviceAdapter {
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
pub fn insert(&self, device: Arc<SyncDevice>) {
|
||||||
pub fn new(tun: Arc<Device>) -> Self {
|
let r = self.tun.lock().replace(device);
|
||||||
Self { tun }
|
assert!(r.is_none());
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "android")]
|
/// 要保证先remove 再insert
|
||||||
pub fn new(tun_device_helper: TunDeviceHelper) -> Self {
|
pub fn remove(&self) {
|
||||||
Self {
|
drop(self.tun.lock().take());
|
||||||
tun: Arc::new(AtomicCell::new(-1 as _)),
|
}
|
||||||
tun_device_helper,
|
}
|
||||||
|
|
||||||
|
impl DeviceWrite for DeviceAdapter {
|
||||||
|
#[inline]
|
||||||
|
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
if let Some(tun) = self.tun.lock().as_ref() {
|
||||||
|
tun.send(buf)
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::NotFound, "not tun device"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
||||||
impl std::ops::Deref for DeviceAdapter {
|
|
||||||
type Target = Arc<Device>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn into_device_adapter(self) -> DeviceAdapter {
|
||||||
&self.tun
|
self
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DeviceAdapter {
|
|
||||||
tun: Arc<AtomicCell<std::os::fd::RawFd>>,
|
|
||||||
tun_device_helper: TunDeviceHelper,
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
impl DeviceAdapter {
|
|
||||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let fd = self.tun.load();
|
|
||||||
tun::Fd(fd).write(buf)
|
|
||||||
}
|
|
||||||
pub fn start(&self, fd: std::os::fd::RawFd) -> io::Result<()> {
|
|
||||||
//安卓端fd是由外部释放的,所以这里这么搞免得加锁
|
|
||||||
self.tun_device_helper.start(Arc::new(Device::new(fd)?))?;
|
|
||||||
self.tun.store(fd);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TunDeviceHelper {
|
pub struct TunDeviceHelper {
|
||||||
inner: Arc<AtomicCell<Option<TunDeviceHelperInner>>>,
|
inner: Arc<Mutex<TunDeviceHelperInner>>,
|
||||||
|
device_adapter: DeviceAdapter,
|
||||||
|
device_stop: Arc<Mutex<Option<DeviceStop>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct TunDeviceHelperInner {
|
struct TunDeviceHelperInner {
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
context: ChannelContext,
|
context: ChannelContext,
|
||||||
@@ -76,9 +66,7 @@ struct TunDeviceHelperInner {
|
|||||||
ip_proxy_map: Option<IpProxyMap>,
|
ip_proxy_map: Option<IpProxyMap>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
parallel: usize,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
up_counter: SingleU64Adder,
|
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
||||||
compressor: Compressor,
|
compressor: Compressor,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,48 +79,63 @@ impl TunDeviceHelper {
|
|||||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||||
client_cipher: Cipher,
|
client_cipher: Cipher,
|
||||||
server_cipher: Cipher,
|
server_cipher: Cipher,
|
||||||
parallel: usize,
|
device_map: Arc<Mutex<(u16, HashMap<Ipv4Addr, PeerDeviceInfo>)>>,
|
||||||
up_counter: SingleU64Adder,
|
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
||||||
compressor: Compressor,
|
compressor: Compressor,
|
||||||
|
device_adapter: DeviceAdapter,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let inner = TunDeviceHelperInner {
|
||||||
|
stop_manager,
|
||||||
|
context,
|
||||||
|
current_device,
|
||||||
|
ip_route,
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
ip_proxy_map,
|
||||||
|
client_cipher,
|
||||||
|
server_cipher,
|
||||||
|
device_map,
|
||||||
|
compressor,
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(AtomicCell::new(Some(TunDeviceHelperInner {
|
inner: Arc::new(Mutex::new(inner)),
|
||||||
stop_manager,
|
device_adapter,
|
||||||
context,
|
device_stop: Default::default(),
|
||||||
current_device,
|
|
||||||
ip_route,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
ip_proxy_map,
|
|
||||||
client_cipher,
|
|
||||||
server_cipher,
|
|
||||||
parallel,
|
|
||||||
up_counter,
|
|
||||||
device_list,
|
|
||||||
compressor,
|
|
||||||
}))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn start(&self, device: Arc<Device>) -> io::Result<()> {
|
pub fn stop(&self) {
|
||||||
if let Some(inner) = self.inner.take() {
|
//先停止旧的,再启动新的,改变旧网卡的IP太麻烦
|
||||||
crate::handle::tun_tap::tun_handler::start(
|
if let Some(device_stop) = self.device_stop.lock().take() {
|
||||||
inner.stop_manager,
|
self.device_adapter.remove();
|
||||||
inner.context,
|
loop {
|
||||||
device,
|
device_stop.stop();
|
||||||
inner.current_device,
|
std::thread::sleep(std::time::Duration::from_millis(300));
|
||||||
inner.ip_route,
|
//确保停止了
|
||||||
#[cfg(feature = "ip_proxy")]
|
if device_stop.is_stopped() {
|
||||||
inner.ip_proxy_map,
|
break;
|
||||||
inner.client_cipher,
|
}
|
||||||
inner.server_cipher,
|
}
|
||||||
inner.parallel,
|
|
||||||
inner.up_counter,
|
|
||||||
inner.device_list,
|
|
||||||
inner.compressor,
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "Repeated start"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// 要保证先stop 再start
|
||||||
|
pub fn start(&self, device: Arc<SyncDevice>, allow_wire_guard: bool) -> io::Result<()> {
|
||||||
|
self.device_adapter.insert(device.clone());
|
||||||
|
let device_stop = DeviceStop::default();
|
||||||
|
let s = self.device_stop.lock().replace(device_stop.clone());
|
||||||
|
assert!(s.is_none());
|
||||||
|
let inner = self.inner.lock().clone();
|
||||||
|
crate::handle::tun_tap::tun_handler::start(
|
||||||
|
inner.stop_manager,
|
||||||
|
inner.context,
|
||||||
|
device,
|
||||||
|
inner.current_device,
|
||||||
|
inner.ip_route,
|
||||||
|
#[cfg(feature = "ip_proxy")]
|
||||||
|
inner.ip_proxy_map,
|
||||||
|
inner.client_cipher,
|
||||||
|
inner.server_cipher,
|
||||||
|
inner.device_map,
|
||||||
|
inner.compressor,
|
||||||
|
device_stop,
|
||||||
|
allow_wire_guard,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub trait DeviceWrite: Clone + Send + Sync + 'static {
|
||||||
|
fn write(&self, buf: &[u8]) -> io::Result<usize>;
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
fn into_device_adapter(self) -> crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
||||||
|
}
|
||||||
@@ -1,138 +1,33 @@
|
|||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// 不安全的并发计数器,谨慎使用
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
pub struct U64Adder {
|
pub struct U64Adder {
|
||||||
global_index: Arc<AtomicUsize>,
|
count: Arc<AtomicCell<u64>>,
|
||||||
inner: Arc<U64AdderInner>,
|
|
||||||
index: usize,
|
|
||||||
}
|
|
||||||
pub struct SingleU64Adder {
|
|
||||||
inner: Arc<SingleU64AdderInner>,
|
|
||||||
}
|
|
||||||
impl SingleU64Adder {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Arc::new(SingleU64AdderInner::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn add(&mut self, num: u64) {
|
|
||||||
self.inner.add(num);
|
|
||||||
}
|
|
||||||
pub fn get(&self) -> u64 {
|
|
||||||
self.inner.get()
|
|
||||||
}
|
|
||||||
pub fn watch(&self) -> WatchSingleU64Adder {
|
|
||||||
WatchSingleU64Adder {
|
|
||||||
inner: self.inner.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SingleU64AdderInner {
|
|
||||||
ptr: *mut u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SingleU64AdderInner {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
ptr: Box::into_raw(Box::new(0)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn add(&self, num: u64) {
|
|
||||||
unsafe { *self.ptr += num }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self) -> u64 {
|
|
||||||
unsafe { *self.ptr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Drop for SingleU64AdderInner {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
let _ = Box::from_raw(self.ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for SingleU64AdderInner {}
|
|
||||||
|
|
||||||
unsafe impl Sync for SingleU64AdderInner {}
|
|
||||||
|
|
||||||
struct U64AdderInner {
|
|
||||||
base: Vec<SingleU64AdderInner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl U64AdderInner {
|
|
||||||
pub fn get(&self) -> u64 {
|
|
||||||
let mut count = 0;
|
|
||||||
for counter in self.base.iter() {
|
|
||||||
count += counter.get()
|
|
||||||
}
|
|
||||||
count
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl U64Adder {
|
impl U64Adder {
|
||||||
/// 计数槽容量
|
pub fn add(&self, num: u64) {
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
self.count.fetch_add(num);
|
||||||
let mut base = Vec::with_capacity(capacity);
|
|
||||||
for _ in 0..capacity {
|
|
||||||
base.push(SingleU64AdderInner::new())
|
|
||||||
}
|
|
||||||
let inner = Arc::new(U64AdderInner { base });
|
|
||||||
U64Adder {
|
|
||||||
global_index: Arc::new(AtomicUsize::new(1)),
|
|
||||||
inner,
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn add(&mut self, num: u64) {
|
|
||||||
self.inner.base[self.index].add(num);
|
|
||||||
}
|
}
|
||||||
pub fn get(&self) -> u64 {
|
pub fn get(&self) -> u64 {
|
||||||
self.inner.get()
|
self.count.load()
|
||||||
}
|
}
|
||||||
pub fn watch(&self) -> WatchU64Adder {
|
pub fn watch(&self) -> WatchU64Adder {
|
||||||
WatchU64Adder {
|
WatchU64Adder {
|
||||||
inner: self.inner.clone(),
|
count: self.count.clone(),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for U64Adder {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let index = self.global_index.fetch_add(1, Ordering::AcqRel);
|
|
||||||
if index > self.inner.base.len() {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
|
||||||
global_index: self.global_index.clone(),
|
|
||||||
inner: self.inner.clone(),
|
|
||||||
index,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WatchU64Adder {
|
pub struct WatchU64Adder {
|
||||||
inner: Arc<U64AdderInner>,
|
count: Arc<AtomicCell<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WatchU64Adder {
|
impl WatchU64Adder {
|
||||||
pub fn get(&self) -> u64 {
|
pub fn get(&self) -> u64 {
|
||||||
self.inner.get()
|
self.count.load()
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct WatchSingleU64Adder {
|
|
||||||
inner: Arc<SingleU64AdderInner>,
|
|
||||||
}
|
|
||||||
impl WatchSingleU64Adder {
|
|
||||||
pub fn get(&self) -> u64 {
|
|
||||||
self.inner.get()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+174
-26
@@ -1,3 +1,8 @@
|
|||||||
|
use crate::channel::socket::LocalInterface;
|
||||||
|
use anyhow::Context;
|
||||||
|
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
|
||||||
|
use http_req::request::{RedirectPolicy, Request};
|
||||||
|
use http_req::uri::Uri;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
|
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
|
||||||
@@ -5,9 +10,6 @@ use std::str::FromStr;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
|
|
||||||
use anyhow::Context;
|
|
||||||
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
|
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static HISTORY: RefCell<HashMap<SocketAddr,usize>> = RefCell::new(HashMap::new());
|
static HISTORY: RefCell<HashMap<SocketAddr,usize>> = RefCell::new(HashMap::new());
|
||||||
}
|
}
|
||||||
@@ -79,22 +81,49 @@ fn address_choose0(addrs: Vec<SocketAddr>) -> anyhow::Result<SocketAddr> {
|
|||||||
pub fn dns_query_all(
|
pub fn dns_query_all(
|
||||||
domain: &str,
|
domain: &str,
|
||||||
mut name_servers: Vec<String>,
|
mut name_servers: Vec<String>,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
) -> anyhow::Result<Vec<SocketAddr>> {
|
) -> anyhow::Result<Vec<SocketAddr>> {
|
||||||
match SocketAddr::from_str(domain) {
|
let mut current_domain = domain.to_string(); // 引入可变变量存储当前域名
|
||||||
|
match SocketAddr::from_str(¤t_domain) {
|
||||||
Ok(addr) => Ok(vec![addr]),
|
Ok(addr) => Ok(vec![addr]),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let txt_domain = domain
|
// 重定向判断 http:
|
||||||
|
let current_domain_lower = current_domain.to_lowercase();
|
||||||
|
let redirect_domain = current_domain_lower
|
||||||
|
.strip_prefix("http:")
|
||||||
|
.or_else(|| current_domain_lower.strip_prefix("https:"))
|
||||||
|
.map(|v| v.to_string());
|
||||||
|
|
||||||
|
// 执行重定向检查
|
||||||
|
if let Some(stripped) = redirect_domain {
|
||||||
|
if let Some(redirected_url) = check_for_redirect(&stripped)? {
|
||||||
|
// 去掉 URL 开头的协议部分
|
||||||
|
let final_domain = remove_http_prefix(&redirected_url);
|
||||||
|
println!("Server Address: {}", final_domain);
|
||||||
|
|
||||||
|
// 检查是否为 IP 和端口组合
|
||||||
|
if let Ok(socket_addr) = SocketAddr::from_str(&final_domain) {
|
||||||
|
// 如果是 IP 和端口格式,直接返回结果
|
||||||
|
return Ok(vec![socket_addr]);
|
||||||
|
} else {
|
||||||
|
// 如果不是 IP 和端口格式,则更新为重定向地址
|
||||||
|
current_domain = final_domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let txt_domain = current_domain
|
||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
.strip_prefix("txt:")
|
.strip_prefix("txt:")
|
||||||
.map(|v| v.to_string());
|
.map(|v| v.to_string());
|
||||||
if name_servers.is_empty() {
|
if name_servers.is_empty() {
|
||||||
if txt_domain.is_some() {
|
if txt_domain.is_some() {
|
||||||
name_servers.push("223.5.5.5:53".into());
|
name_servers.push("223.5.5.5:53".into());
|
||||||
|
name_servers.push("119.29.29.29:53".into());
|
||||||
name_servers.push("114.114.114.114:53".into());
|
name_servers.push("114.114.114.114:53".into());
|
||||||
} else {
|
} else {
|
||||||
return Ok(domain
|
return Ok(current_domain
|
||||||
.to_socket_addrs()
|
.to_socket_addrs()
|
||||||
.with_context(|| format!("DNS query failed {:?}", domain))?
|
.with_context(|| format!("DNS query failed {:?}", current_domain))?
|
||||||
.collect());
|
.collect());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,9 +131,10 @@ pub fn dns_query_all(
|
|||||||
let mut err: Option<anyhow::Error> = None;
|
let mut err: Option<anyhow::Error> = None;
|
||||||
for name_server in name_servers {
|
for name_server in name_servers {
|
||||||
if let Some(domain) = txt_domain.as_ref() {
|
if let Some(domain) = txt_domain.as_ref() {
|
||||||
match txt_dns(domain, name_server) {
|
match txt_dns(domain, name_server, default_interface) {
|
||||||
Ok(addr) => {
|
Ok(addr) => {
|
||||||
if !addr.is_empty() {
|
if !addr.is_empty() {
|
||||||
|
println!("TXT: {:?}", addr);
|
||||||
return Ok(addr);
|
return Ok(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,21 +148,24 @@ pub fn dns_query_all(
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let end_index = domain
|
|
||||||
|
let end_index = current_domain
|
||||||
.rfind(':')
|
.rfind(':')
|
||||||
.with_context(|| format!("{:?} not port", domain))?;
|
.with_context(|| format!("{:?} not port", current_domain))?;
|
||||||
let host = &domain[..end_index];
|
let host = &domain[..end_index];
|
||||||
let port = u16::from_str(&domain[end_index + 1..])
|
let port = u16::from_str(&domain[end_index + 1..])
|
||||||
.with_context(|| format!("{:?} not port", domain))?;
|
.with_context(|| format!("{:?} not port", current_domain))?;
|
||||||
let th1 = {
|
let th1 = {
|
||||||
let host = host.to_string();
|
let host = host.to_string();
|
||||||
let name_server = name_server.clone();
|
let name_server = name_server.clone();
|
||||||
thread::spawn(move || a_dns(host, name_server))
|
let default_interface = default_interface.clone();
|
||||||
|
thread::spawn(move || a_dns(host, name_server, &default_interface))
|
||||||
};
|
};
|
||||||
let th2 = {
|
let th2 = {
|
||||||
let host = host.to_string();
|
let host = host.to_string();
|
||||||
let name_server = name_server.clone();
|
let name_server = name_server.clone();
|
||||||
thread::spawn(move || aaaa_dns(host, name_server))
|
let default_interface = default_interface.clone();
|
||||||
|
thread::spawn(move || aaaa_dns(host, name_server, &default_interface))
|
||||||
};
|
};
|
||||||
let mut addr = Vec::new();
|
let mut addr = Vec::new();
|
||||||
match th1.join().unwrap() {
|
match th1.join().unwrap() {
|
||||||
@@ -170,12 +203,110 @@ pub fn dns_query_all(
|
|||||||
if let Some(e) = err {
|
if let Some(e) = err {
|
||||||
Err(e)
|
Err(e)
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!("DNS query failed {:?}", domain))
|
Err(anyhow::anyhow!("DNS query failed {:?}", current_domain))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_host_port(addr: &str) -> bool {
|
||||||
|
// 处理 IPv6 地址(格式为 [::1]:8080)
|
||||||
|
if addr.starts_with('[') {
|
||||||
|
if let Some(idx) = addr.rfind(']') {
|
||||||
|
if let Some(port_idx) = addr[idx + 1..].find(':') {
|
||||||
|
let port = &addr[idx + 1 + port_idx + 1..]; // 提取端口部分
|
||||||
|
return !port.is_empty() && port.chars().all(|c| c.is_numeric());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 处理 IPv4 和普通域名(格式为 example.com:443 或 192.168.1.1:8080)
|
||||||
|
if let Some((_host, port)) = addr.rsplit_once(':') {
|
||||||
|
return !port.is_empty() && port.chars().all(|c| c.is_numeric());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_for_redirect(domain: &String) -> anyhow::Result<Option<String>> {
|
||||||
|
// 确保域名有 http:// 或 https:// 前缀
|
||||||
|
let mut url = if domain.starts_with("http://") || domain.starts_with("https://") {
|
||||||
|
domain.clone()
|
||||||
|
} else {
|
||||||
|
format!("http://{}", domain)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut count = 0; // 重定向次数计数器
|
||||||
|
let mut last_redirect_url: Option<String> = None; // 记录最后一个重定向的 URL
|
||||||
|
|
||||||
|
loop {
|
||||||
|
count += 1;
|
||||||
|
if count > 3 {
|
||||||
|
println!("重定向次数超过 3 次,跳过");
|
||||||
|
return Ok(last_redirect_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析 URL
|
||||||
|
let uri = match Uri::try_from(url.as_str()) {
|
||||||
|
Ok(u) => u,
|
||||||
|
Err(e) => {
|
||||||
|
println!("解析地址失败: {}", e);
|
||||||
|
return Ok(last_redirect_url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut response_body = Vec::new();
|
||||||
|
|
||||||
|
// 发送 HTTP 请求
|
||||||
|
let response = match Request::new(&uri)
|
||||||
|
.timeout(Duration::from_secs(10))
|
||||||
|
.redirect_policy(RedirectPolicy::Limit(0))
|
||||||
|
.send(&mut response_body)
|
||||||
|
{
|
||||||
|
Ok(resp) => {
|
||||||
|
println!("HTTP Status Code: {}", resp.status_code());
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Ok(last_redirect_url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let body_str = String::from_utf8_lossy(&response_body);
|
||||||
|
let cleaned_body = body_str.replace('\n', "").replace('\r', "");
|
||||||
|
println!("Response Body: {}", cleaned_body);
|
||||||
|
// 处理 3XX 重定向
|
||||||
|
if response.status_code().is_redirect() {
|
||||||
|
if let Some(location) = response.headers().get("Location") {
|
||||||
|
url = location.to_string().trim_end_matches('/').to_string();
|
||||||
|
last_redirect_url = Some(url.clone()); // 更新最后的重定向地址
|
||||||
|
println!("Location: {}", url);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return Ok(last_redirect_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 处理 200 响应
|
||||||
|
else if response.status_code().is_success() {
|
||||||
|
for line in body_str.lines() {
|
||||||
|
let trimmed = line.trim();
|
||||||
|
if parse_host_port(trimmed) {
|
||||||
|
println!("text: {}", trimmed);
|
||||||
|
return Ok(Some(trimmed.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(last_redirect_url);
|
||||||
|
}
|
||||||
|
return Ok(last_redirect_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 去掉 http:// 或 https:// 前缀
|
||||||
|
fn remove_http_prefix(url: &str) -> String {
|
||||||
|
url.trim_start_matches("http://")
|
||||||
|
.trim_start_matches("https://")
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn query<'a>(
|
fn query<'a>(
|
||||||
udp: &UdpSocket,
|
udp: &UdpSocket,
|
||||||
domain: &str,
|
domain: &str,
|
||||||
@@ -230,9 +361,13 @@ fn query<'a>(
|
|||||||
Ok(pkt)
|
Ok(pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn txt_dns(domain: &str, name_server: String) -> anyhow::Result<Vec<SocketAddr>> {
|
pub fn txt_dns(
|
||||||
|
domain: &str,
|
||||||
|
name_server: String,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<Vec<SocketAddr>> {
|
||||||
let name_server: SocketAddr = name_server.parse()?;
|
let name_server: SocketAddr = name_server.parse()?;
|
||||||
let udp = bind_udp(name_server)?;
|
let udp = bind_udp(name_server, default_interface)?;
|
||||||
let mut buf = [0; 65536];
|
let mut buf = [0; 65536];
|
||||||
let message = query(&udp, domain, name_server, QueryType::TXT, &mut buf)?;
|
let message = query(&udp, domain, name_server, QueryType::TXT, &mut buf)?;
|
||||||
let mut rs = Vec::new();
|
let mut rs = Vec::new();
|
||||||
@@ -249,19 +384,28 @@ pub fn txt_dns(domain: &str, name_server: String) -> anyhow::Result<Vec<SocketAd
|
|||||||
Ok(rs)
|
Ok(rs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind_udp(name_server: SocketAddr) -> anyhow::Result<UdpSocket> {
|
fn bind_udp(
|
||||||
let udp = if name_server.is_ipv4() {
|
name_server: SocketAddr,
|
||||||
UdpSocket::bind("0.0.0.0:0")?
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<UdpSocket> {
|
||||||
|
let addr: SocketAddr = if name_server.is_ipv4() {
|
||||||
|
"0.0.0.0:0".parse().unwrap()
|
||||||
} else {
|
} else {
|
||||||
UdpSocket::bind("[::]:0")?
|
"[::]:0".parse().unwrap()
|
||||||
};
|
};
|
||||||
udp.set_read_timeout(Some(Duration::from_millis(800)))?;
|
let socket = crate::channel::socket::bind_udp(addr, default_interface)?;
|
||||||
Ok(udp)
|
socket.set_nonblocking(false)?;
|
||||||
|
socket.set_read_timeout(Some(Duration::from_millis(800)))?;
|
||||||
|
Ok(socket.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a_dns(domain: String, name_server: String) -> anyhow::Result<Vec<Ipv4Addr>> {
|
pub fn a_dns(
|
||||||
|
domain: String,
|
||||||
|
name_server: String,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<Vec<Ipv4Addr>> {
|
||||||
let name_server: SocketAddr = name_server.parse()?;
|
let name_server: SocketAddr = name_server.parse()?;
|
||||||
let udp = bind_udp(name_server)?;
|
let udp = bind_udp(name_server, default_interface)?;
|
||||||
let mut buf = [0; 65536];
|
let mut buf = [0; 65536];
|
||||||
let message = query(&udp, &domain, name_server, QueryType::A, &mut buf)?;
|
let message = query(&udp, &domain, name_server, QueryType::A, &mut buf)?;
|
||||||
let mut rs = Vec::new();
|
let mut rs = Vec::new();
|
||||||
@@ -273,9 +417,13 @@ pub fn a_dns(domain: String, name_server: String) -> anyhow::Result<Vec<Ipv4Addr
|
|||||||
Ok(rs)
|
Ok(rs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aaaa_dns(domain: String, name_server: String) -> anyhow::Result<Vec<Ipv6Addr>> {
|
pub fn aaaa_dns(
|
||||||
|
domain: String,
|
||||||
|
name_server: String,
|
||||||
|
default_interface: &LocalInterface,
|
||||||
|
) -> anyhow::Result<Vec<Ipv6Addr>> {
|
||||||
let name_server: SocketAddr = name_server.parse()?;
|
let name_server: SocketAddr = name_server.parse()?;
|
||||||
let udp = bind_udp(name_server)?;
|
let udp = bind_udp(name_server, default_interface)?;
|
||||||
let mut buf = [0; 65536];
|
let mut buf = [0; 65536];
|
||||||
let message = query(&udp, &domain, name_server, QueryType::AAAA, &mut buf)?;
|
let message = query(&udp, &domain, name_server, QueryType::AAAA, &mut buf)?;
|
||||||
let mut rs = Vec::new();
|
let mut rs = Vec::new();
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
mod rate_limiter;
|
||||||
|
pub use rate_limiter::*;
|
||||||
|
|
||||||
|
mod traffic_meter;
|
||||||
|
pub use traffic_meter::*;
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use parking_lot::Mutex;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ConcurrentRateLimiter {
|
||||||
|
inner: Arc<Mutex<RateLimiter>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConcurrentRateLimiter {
|
||||||
|
pub fn new(capacity: usize, refill_rate: usize) -> Self {
|
||||||
|
let inner = RateLimiter::new(capacity, refill_rate);
|
||||||
|
Self {
|
||||||
|
inner: Arc::new(Mutex::new(inner)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn try_acquire(&self) -> bool {
|
||||||
|
self.inner.lock().try_acquire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RateLimiter {
|
||||||
|
capacity: usize,
|
||||||
|
tokens: usize,
|
||||||
|
refill_rate: usize,
|
||||||
|
last_refill: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RateLimiter {
|
||||||
|
// 初始化限流器
|
||||||
|
pub fn new(capacity: usize, refill_rate: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
capacity,
|
||||||
|
tokens: capacity,
|
||||||
|
refill_rate,
|
||||||
|
last_refill: Instant::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试获取一个令牌
|
||||||
|
pub fn try_acquire(&mut self) -> bool {
|
||||||
|
self.refill();
|
||||||
|
if self.tokens > 0 {
|
||||||
|
self.tokens -= 1;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 补充令牌
|
||||||
|
fn refill(&mut self) {
|
||||||
|
let now = Instant::now();
|
||||||
|
let elapsed = now.duration_since(self.last_refill).as_secs() as usize;
|
||||||
|
let new_tokens = elapsed * self.refill_rate;
|
||||||
|
|
||||||
|
if new_tokens > 0 {
|
||||||
|
self.tokens = std::cmp::min(self.capacity, self.tokens + new_tokens);
|
||||||
|
self.last_refill = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
use parking_lot::Mutex;
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TrafficMeterMultiAddress {
|
||||||
|
history_capacity: usize,
|
||||||
|
inner: Arc<Mutex<(u64, HashMap<Ipv4Addr, TrafficMeter>)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TrafficMeterMultiAddress {
|
||||||
|
fn default() -> Self {
|
||||||
|
TrafficMeterMultiAddress::new(100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrafficMeterMultiAddress {
|
||||||
|
pub fn new(history_capacity: usize) -> Self {
|
||||||
|
let inner = Arc::new(Mutex::new((0, HashMap::new())));
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
history_capacity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add_traffic(&self, ip: Ipv4Addr, amount: usize) {
|
||||||
|
let mut guard = self.inner.lock();
|
||||||
|
guard.0 += amount as u64;
|
||||||
|
guard
|
||||||
|
.1
|
||||||
|
.entry(ip)
|
||||||
|
.or_insert(TrafficMeter::new(self.history_capacity))
|
||||||
|
.add_traffic(amount)
|
||||||
|
}
|
||||||
|
pub fn total(&self) -> u64 {
|
||||||
|
self.inner.lock().0
|
||||||
|
}
|
||||||
|
pub fn get_all(&self) -> (u64, HashMap<Ipv4Addr, u64>) {
|
||||||
|
let guard = self.inner.lock();
|
||||||
|
(
|
||||||
|
guard.0,
|
||||||
|
guard.1.iter().map(|(ip, t)| (*ip, t.total())).collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn get_all_history(&self) -> (u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>) {
|
||||||
|
let guard = self.inner.lock();
|
||||||
|
(
|
||||||
|
guard.0,
|
||||||
|
guard
|
||||||
|
.1
|
||||||
|
.iter()
|
||||||
|
.map(|(ip, t)| (*ip, (t.total(), t.get_history())))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn get_history(&self, ip: &Ipv4Addr) -> Option<(u64, Vec<usize>)> {
|
||||||
|
self.inner
|
||||||
|
.lock()
|
||||||
|
.1
|
||||||
|
.get(ip)
|
||||||
|
.map(|t| (t.total(), t.get_history()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ConcurrentTrafficMeter {
|
||||||
|
inner: Arc<Mutex<TrafficMeter>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConcurrentTrafficMeter {
|
||||||
|
pub fn new(history_capacity: usize) -> Self {
|
||||||
|
let inner = Arc::new(Mutex::new(TrafficMeter::new(history_capacity)));
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
pub fn add_traffic(&self, amount: usize) {
|
||||||
|
self.inner.lock().add_traffic(amount)
|
||||||
|
}
|
||||||
|
pub fn get_history(&self) -> Vec<usize> {
|
||||||
|
self.inner.lock().get_history()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TrafficMeter {
|
||||||
|
start_time: Instant,
|
||||||
|
total: u64,
|
||||||
|
count: usize,
|
||||||
|
history_capacity: usize,
|
||||||
|
history: VecDeque<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrafficMeter {
|
||||||
|
// 初始化一个新的 TrafficMeter
|
||||||
|
pub fn new(history_capacity: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
start_time: Instant::now(),
|
||||||
|
total: 0,
|
||||||
|
count: 0,
|
||||||
|
history: VecDeque::with_capacity(history_capacity),
|
||||||
|
history_capacity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加流量计数
|
||||||
|
pub fn add_traffic(&mut self, amount: usize) {
|
||||||
|
self.total += amount as u64;
|
||||||
|
self.count += amount;
|
||||||
|
self.check_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查时间是否超过一秒,如果是,记录流量并重置计数器和时间
|
||||||
|
fn check_time(&mut self) {
|
||||||
|
if self.start_time.elapsed() >= Duration::new(1, 0) {
|
||||||
|
// 将当前计数添加到历史记录
|
||||||
|
if self.history.len() >= self.history_capacity {
|
||||||
|
self.history.pop_front(); // 保持历史记录不超过capacity
|
||||||
|
}
|
||||||
|
self.history.push_back(self.count);
|
||||||
|
|
||||||
|
// 重置计数器和时间
|
||||||
|
self.count = 0;
|
||||||
|
self.start_time = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn total(&self) -> u64 {
|
||||||
|
self.total
|
||||||
|
}
|
||||||
|
// 获取流量记录
|
||||||
|
pub fn get_history(&self) -> Vec<usize> {
|
||||||
|
self.history.iter().cloned().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-3
@@ -1,10 +1,17 @@
|
|||||||
mod notify;
|
mod notify;
|
||||||
mod scheduler;
|
mod scheduler;
|
||||||
pub use notify::StopManager;
|
pub use notify::{StopManager, Worker};
|
||||||
pub use scheduler::Scheduler;
|
pub use scheduler::Scheduler;
|
||||||
|
|
||||||
mod counter;
|
// mod counter;
|
||||||
pub use counter::*;
|
// pub use counter::*;
|
||||||
|
|
||||||
mod dns_query;
|
mod dns_query;
|
||||||
pub use dns_query::*;
|
pub use dns_query::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
mod upnp;
|
||||||
|
#[cfg(feature = "upnp")]
|
||||||
|
pub use upnp::*;
|
||||||
|
|
||||||
|
pub mod limit;
|
||||||
|
|||||||
+33
-18
@@ -1,9 +1,10 @@
|
|||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
use std::thread::Thread;
|
use std::thread::Thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{io, thread};
|
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -20,14 +21,14 @@ impl StopManager {
|
|||||||
inner: Arc::new(StopManagerInner::new(f)),
|
inner: Arc::new(StopManagerInner::new(f)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn add_listener<F>(&self, name: String, f: F) -> io::Result<Worker>
|
pub fn add_listener<F>(&self, name: String, f: F) -> anyhow::Result<Worker>
|
||||||
where
|
where
|
||||||
F: FnOnce() + Send + 'static,
|
F: FnOnce() + Send + 'static,
|
||||||
{
|
{
|
||||||
self.inner.add_listener(name, f)
|
self.inner.add_listener(name, f)
|
||||||
}
|
}
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
self.inner.stop("");
|
self.inner.stop();
|
||||||
}
|
}
|
||||||
pub fn wait(&self) {
|
pub fn wait(&self) {
|
||||||
self.inner.wait();
|
self.inner.wait();
|
||||||
@@ -35,8 +36,8 @@ impl StopManager {
|
|||||||
pub fn wait_timeout(&self, dur: Duration) -> bool {
|
pub fn wait_timeout(&self, dur: Duration) -> bool {
|
||||||
self.inner.wait_timeout(dur)
|
self.inner.wait_timeout(dur)
|
||||||
}
|
}
|
||||||
pub fn is_stop(&self) -> bool {
|
pub fn is_stopped(&self) -> bool {
|
||||||
self.inner.state.load(Ordering::Acquire)
|
self.inner.is_stopped()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,39 +62,36 @@ impl StopManagerInner {
|
|||||||
stop_call: Mutex::new(Some(Box::new(f))),
|
stop_call: Mutex::new(Some(Box::new(f))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_listener<F>(self: &Arc<Self>, name: String, f: F) -> io::Result<Worker>
|
fn add_listener<F>(self: &Arc<Self>, name: String, f: F) -> anyhow::Result<Worker>
|
||||||
where
|
where
|
||||||
F: FnOnce() + Send + 'static,
|
F: FnOnce() + Send + 'static,
|
||||||
{
|
{
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "name cannot be empty"));
|
return Err(anyhow!("name cannot be empty"));
|
||||||
}
|
}
|
||||||
let mut guard = self.listeners.lock();
|
let mut guard = self.listeners.lock();
|
||||||
if guard.0 {
|
if guard.0 {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "stopped"));
|
return Err(anyhow!("stopped"));
|
||||||
}
|
}
|
||||||
for (n, _) in &guard.1 {
|
for (n, _) in &guard.1 {
|
||||||
if &name == n {
|
if &name == n {
|
||||||
return Err(io::Error::new(
|
return Err(anyhow!("stop add_listener {:?} name already exists", name));
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("stop add_listener {:?} name already exists", name),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
guard.1.push((name.clone(), Box::new(f)));
|
guard.1.push((name.clone(), Box::new(f)));
|
||||||
Ok(Worker::new(name, self.clone()))
|
Ok(Worker::new(name, self.clone()))
|
||||||
}
|
}
|
||||||
fn stop(&self, skip_name: &str) {
|
fn stop(&self) {
|
||||||
self.state.store(true, Ordering::Release);
|
self.state.store(true, Ordering::Release);
|
||||||
let mut guard = self.listeners.lock();
|
let mut guard = self.listeners.lock();
|
||||||
guard.0 = true;
|
guard.0 = true;
|
||||||
for (name, listener) in guard.1.drain(..) {
|
for (_name, listener) in guard.1.drain(..) {
|
||||||
if &name == skip_name {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
listener();
|
listener();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn is_stopped(&self) -> bool {
|
||||||
|
self.worker_num.load(Ordering::Acquire) == 0
|
||||||
|
}
|
||||||
fn wait(&self) {
|
fn wait(&self) {
|
||||||
{
|
{
|
||||||
let mut guard = self.park_threads.lock();
|
let mut guard = self.park_threads.lock();
|
||||||
@@ -120,6 +118,7 @@ impl StopManagerInner {
|
|||||||
self.worker_num.load(Ordering::Acquire) == 0
|
self.worker_num.load(Ordering::Acquire) == 0
|
||||||
}
|
}
|
||||||
fn stop_call(&self) {
|
fn stop_call(&self) {
|
||||||
|
self.stop();
|
||||||
if let Some(call) = self.stop_call.lock().take() {
|
if let Some(call) = self.stop_call.lock().take() {
|
||||||
call();
|
call();
|
||||||
}
|
}
|
||||||
@@ -138,6 +137,19 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
fn release0(&self) {
|
fn release0(&self) {
|
||||||
let inner = &self.inner;
|
let inner = &self.inner;
|
||||||
|
let worker_name = &self.name;
|
||||||
|
{
|
||||||
|
let mut mutex_guard = inner.listeners.lock();
|
||||||
|
if let Some(pos) = mutex_guard
|
||||||
|
.1
|
||||||
|
.iter()
|
||||||
|
.position(|(name, _)| name == worker_name)
|
||||||
|
{
|
||||||
|
let (_, listener) = mutex_guard.1.remove(pos);
|
||||||
|
listener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let count = inner.worker_num.fetch_sub(1, Ordering::AcqRel);
|
let count = inner.worker_num.fetch_sub(1, Ordering::AcqRel);
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
for x in inner.park_threads.lock().drain(..) {
|
for x in inner.park_threads.lock().drain(..) {
|
||||||
@@ -147,7 +159,10 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn stop_all(self) {
|
pub fn stop_all(self) {
|
||||||
self.inner.stop(&self.name)
|
self.inner.stop()
|
||||||
|
}
|
||||||
|
pub fn stop_self(self) {
|
||||||
|
drop(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
use crate::util::StopManager;
|
use crate::util::StopManager;
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use std::collections::BinaryHeap;
|
use std::collections::BinaryHeap;
|
||||||
|
use std::sync::mpsc::TrySendError;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
io,
|
|
||||||
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
@@ -11,45 +13,62 @@ struct DelayedTask {
|
|||||||
f: Box<dyn FnOnce(&Scheduler) + Send>,
|
f: Box<dyn FnOnce(&Scheduler) + Send>,
|
||||||
next: Instant,
|
next: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for DelayedTask {}
|
impl Eq for DelayedTask {}
|
||||||
|
|
||||||
impl PartialEq for DelayedTask {
|
impl PartialEq for DelayedTask {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.next.eq(&other.next)
|
self.next.eq(&other.next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for DelayedTask {
|
impl PartialOrd for DelayedTask {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
|
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for DelayedTask {
|
impl Ord for DelayedTask {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.next.cmp(&other.next).reverse()
|
self.next.cmp(&other.next).reverse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Op {
|
enum Op {
|
||||||
Task(DelayedTask),
|
Task(DelayedTask),
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Scheduler {
|
pub struct Scheduler {
|
||||||
sender: SyncSender<Op>,
|
sender: SyncSender<Op>,
|
||||||
|
state: Arc<AtomicCell<SchedulerState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
enum SchedulerState {
|
||||||
|
Running,
|
||||||
|
ShutdownNow, // 立即停止任务执行,队列中剩余的任务不再执行
|
||||||
|
_Shutdown, //执行完队列中剩余的任务再停止
|
||||||
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
pub fn new(stop_manager: StopManager) -> io::Result<Self> {
|
pub fn new(stop_manager: StopManager) -> anyhow::Result<Self> {
|
||||||
let (sender, receiver) = sync_channel::<Op>(32);
|
let (sender, receiver) = sync_channel::<Op>(32);
|
||||||
let s = Self { sender };
|
let state = Arc::new(AtomicCell::new(SchedulerState::Running));
|
||||||
|
let s = Self { sender, state };
|
||||||
let s_inner = s.clone();
|
let s_inner = s.clone();
|
||||||
let worker = {
|
let worker = {
|
||||||
let scheduler = s.clone();
|
let scheduler = s.clone();
|
||||||
stop_manager.add_listener("Scheduler".into(), move || {
|
stop_manager.add_listener("Scheduler".into(), move || {
|
||||||
scheduler.shutdown();
|
scheduler.shutdown_now();
|
||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("Scheduler".into())
|
.name("Scheduler".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
run(receiver, s_inner);
|
run(receiver, &s_inner);
|
||||||
|
s_inner.shutdown_now();
|
||||||
worker.stop_all();
|
worker.stop_all();
|
||||||
})
|
})
|
||||||
.expect("Scheduler");
|
.expect("Scheduler");
|
||||||
@@ -59,20 +78,44 @@ impl Scheduler {
|
|||||||
where
|
where
|
||||||
F: FnOnce(&Scheduler) + Send + 'static,
|
F: FnOnce(&Scheduler) + Send + 'static,
|
||||||
{
|
{
|
||||||
|
if self.state.load() != SchedulerState::Running {
|
||||||
|
log::error!("定时任务执行停止");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let task = DelayedTask {
|
let task = DelayedTask {
|
||||||
f: Box::new(f),
|
f: Box::new(f),
|
||||||
next: Instant::now().checked_add(time).unwrap(),
|
next: Instant::now().checked_add(time).unwrap(),
|
||||||
};
|
};
|
||||||
self.sender.send(Op::Task(task)).is_ok()
|
// 如果是任务中调用此方法,那这里用send可能会导致整个定时任务阻塞
|
||||||
|
// 任务总数不能大于或等于通道长度,所以改成try_send快速失败
|
||||||
|
match self.sender.try_send(Op::Task(task)) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(e) => {
|
||||||
|
match e {
|
||||||
|
TrySendError::Full(_) => {
|
||||||
|
log::error!("定时任务队列达到上限");
|
||||||
|
}
|
||||||
|
TrySendError::Disconnected(_) => {
|
||||||
|
log::error!("定时任务执行停止 通道关闭");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn shutdown(self) {
|
pub fn shutdown_now(&self) {
|
||||||
|
self.state.store(SchedulerState::ShutdownNow);
|
||||||
let _ = self.sender.send(Op::Stop);
|
let _ = self.sender.send(Op::Stop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
|
||||||
|
fn run(receiver: Receiver<Op>, s_inner: &Scheduler) {
|
||||||
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
|
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
|
||||||
loop {
|
loop {
|
||||||
while let Some(task) = binary_heap.peek() {
|
while let Some(task) = binary_heap.peek() {
|
||||||
|
if s_inner.state.load() == SchedulerState::ShutdownNow {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now < task.next {
|
if now < task.next {
|
||||||
//需要等待对应时间
|
//需要等待对应时间
|
||||||
@@ -90,7 +133,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(task) = binary_heap.pop() {
|
if let Some(task) = binary_heap.pop() {
|
||||||
(task.f)(&s_inner);
|
(task.f)(s_inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +164,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
|
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
|
||||||
return match op {
|
return match op {
|
||||||
Op::Task(task) => {
|
Op::Task(task) => {
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
use igd::{search_gateway, PortMappingProtocol};
|
||||||
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct UPnP {
|
||||||
|
inner: Arc<UpnpInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for UPnP {
|
||||||
|
type Target = UpnpInner;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct UpnpInner {
|
||||||
|
list: Mutex<Vec<(PortMappingProtocol, u16)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UpnpInner {
|
||||||
|
pub fn add_tcp_port(&self, port: u16) {
|
||||||
|
self.list.lock().push((PortMappingProtocol::TCP, port));
|
||||||
|
}
|
||||||
|
pub fn add_udp_port(&self, port: u16) {
|
||||||
|
self.list.lock().push((PortMappingProtocol::UDP, port));
|
||||||
|
}
|
||||||
|
pub fn reset(&self, local_ip: Ipv4Addr) {
|
||||||
|
let gateway = match search_gateway(Default::default()) {
|
||||||
|
Ok(gateway) => gateway,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("search_gateway {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let guard = self.list.lock();
|
||||||
|
|
||||||
|
// 不支持upnp的情况会阻塞30秒,之后再改这个库
|
||||||
|
for (protocol, port) in guard.iter() {
|
||||||
|
let local_addr = SocketAddrV4::new(local_ip, *port);
|
||||||
|
log::info!("add upnp protocol={} {}", protocol, local_addr);
|
||||||
|
if let Err(e) = gateway.add_port(*protocol, *port, local_addr, 700, "upnp") {
|
||||||
|
log::warn!(
|
||||||
|
"add upnp failed protocol={},port={} err:{:?}",
|
||||||
|
protocol,
|
||||||
|
port,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for UpnpInner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// let gateway = match search_gateway(Default::default()) {
|
||||||
|
// Ok(gateway) => gateway,
|
||||||
|
// Err(e) => {
|
||||||
|
// log::warn!("search_gateway {:?}", e);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// let guard = self.list.lock();
|
||||||
|
// for (protocol, port) in guard.iter() {
|
||||||
|
// if let Err(e) = gateway.remove_port(*protocol, *port) {
|
||||||
|
// log::warn!(
|
||||||
|
// "remove upnp failed protocol={},port={} err:{:?}",
|
||||||
|
// protocol,
|
||||||
|
// port,
|
||||||
|
// e
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "tun"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
libc = "0.2.153"
|
|
||||||
|
|
||||||
log = { version = "0.4.20", features = [] }
|
|
||||||
rand = "0.8.5"
|
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
|
||||||
ioctl = { version = "0.8", package = "ioctl-sys" }
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
|
||||||
libloading = "0.8.0"
|
|
||||||
widestring = "1.0.2"
|
|
||||||
winapi = {version = "0.3",features = [
|
|
||||||
"errhandlingapi",
|
|
||||||
"combaseapi",
|
|
||||||
"ioapiset",
|
|
||||||
"winioctl",
|
|
||||||
"setupapi",
|
|
||||||
"synchapi",
|
|
||||||
"netioapi",
|
|
||||||
"fileapi","handleapi","winerror","minwindef","ifdef","basetsd","winnt","winreg","winbase","minwinbase",
|
|
||||||
"impl-default"
|
|
||||||
]}
|
|
||||||
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
use crate::device::IFace;
|
|
||||||
use crate::Fd;
|
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::os::fd::RawFd;
|
|
||||||
|
|
||||||
pub struct Device {
|
|
||||||
fd: Fd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
pub fn new(fd: RawFd) -> io::Result<Self> {
|
|
||||||
Ok(Self { fd: Fd::new(fd)? })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Device {
|
|
||||||
pub fn as_tun_fd(&self) -> &Fd {
|
|
||||||
&self.fd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl IFace for Device {
|
|
||||||
fn version(&self) -> io::Result<String> {
|
|
||||||
Ok(String::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> io::Result<String> {
|
|
||||||
Ok(String::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
|
||||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_ip(&self, _address: Ipv4Addr, _mask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mtu(&self) -> io::Result<u32> {
|
|
||||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mtu(&self, _value: u32) -> io::Result<()> {
|
|
||||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
|
|
||||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_route(&self, _dest: Ipv4Addr, _netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
self.fd.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
self.fd.write(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
use io::Result;
|
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
pub trait IFace {
|
|
||||||
fn version(&self) -> Result<String>;
|
|
||||||
/// Get the device name.
|
|
||||||
fn name(&self) -> Result<String>;
|
|
||||||
|
|
||||||
fn shutdown(&self) -> Result<()>;
|
|
||||||
|
|
||||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> Result<()>;
|
|
||||||
|
|
||||||
/// Get the MTU.
|
|
||||||
fn mtu(&self) -> Result<u32>;
|
|
||||||
|
|
||||||
/// Set the MTU.
|
|
||||||
fn set_mtu(&self, value: u32) -> Result<()>;
|
|
||||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> Result<()>;
|
|
||||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> Result<()>;
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize>;
|
|
||||||
fn write(&self, buf: &[u8]) -> Result<usize>;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/// 参考
|
|
||||||
/// https://github.com/meh/rust-tun
|
|
||||||
/// https://github.com/Tazdevil971/tap-windows
|
|
||||||
/// https://github.com/nulldotblack/wintun
|
|
||||||
pub mod device;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
mod linux;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub use linux::Device;
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
mod android;
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
pub use android::Device;
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
mod macos;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub use macos::Device;
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
mod unix;
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub use unix::Fd;
|
|
||||||
#[cfg(windows)]
|
|
||||||
mod windows;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub use windows::Device;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
mod packet;
|
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
use std::ffi::{CStr, CString};
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::os::fd::AsRawFd;
|
|
||||||
use std::{io, mem, ptr};
|
|
||||||
|
|
||||||
use libc::{
|
|
||||||
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TUN,
|
|
||||||
IFF_UP, IFNAMSIZ, O_RDWR, SOCK_DGRAM,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::device::IFace;
|
|
||||||
use crate::linux::route;
|
|
||||||
use crate::linux::sys::*;
|
|
||||||
use crate::unix::{exe_cmd, Fd, SockAddr};
|
|
||||||
|
|
||||||
pub struct Device {
|
|
||||||
name: String,
|
|
||||||
ctl: Fd,
|
|
||||||
tun: Fd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
pub fn new(name: Option<String>) -> io::Result<Self> {
|
|
||||||
let device = unsafe {
|
|
||||||
let dev = match name {
|
|
||||||
Some(name) => {
|
|
||||||
let name =
|
|
||||||
CString::new(name).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
|
||||||
|
|
||||||
if name.as_bytes_with_nul().len() > IFNAMSIZ {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut req: ifreq = mem::zeroed();
|
|
||||||
|
|
||||||
if let Some(dev) = dev.as_ref() {
|
|
||||||
ptr::copy_nonoverlapping(
|
|
||||||
dev.as_ptr() as *const c_char,
|
|
||||||
req.ifr_name.as_mut_ptr(),
|
|
||||||
dev.as_bytes().len(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let device_type: c_short = IFF_TUN as c_short; //if tap { IFF_TAP } else { IFF_TUN } as c_short;
|
|
||||||
|
|
||||||
let queues_num = 1;
|
|
||||||
|
|
||||||
let iff_no_pi = IFF_NO_PI as c_short;
|
|
||||||
let iff_multi_queue = IFF_MULTI_QUEUE as c_short;
|
|
||||||
let packet_information = false;
|
|
||||||
req.ifr_ifru.ifru_flags = device_type
|
|
||||||
| if packet_information { 0 } else { iff_no_pi }
|
|
||||||
| if queues_num > 1 { iff_multi_queue } else { 0 };
|
|
||||||
|
|
||||||
let tun = Fd::new(libc::open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR))
|
|
||||||
.map_err(|_| io::Error::last_os_error())?;
|
|
||||||
|
|
||||||
if tunsetiff(tun.0, &mut req as *mut _ as *mut _) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
|
|
||||||
|
|
||||||
let name = CStr::from_ptr(req.ifr_name.as_ptr())
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_string();
|
|
||||||
let set_txqueuelen = format!("ifconfig {} txqueuelen 1000", name);
|
|
||||||
if let Err(e) = exe_cmd(&set_txqueuelen) {
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
}
|
|
||||||
Device { name, tun, ctl }
|
|
||||||
};
|
|
||||||
device.enabled(true)?;
|
|
||||||
Ok(device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
fn enabled(&self, value: bool) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
if value {
|
|
||||||
req.ifr_ifru.ifru_flags |= (IFF_UP | IFF_RUNNING) as c_short;
|
|
||||||
} else {
|
|
||||||
req.ifr_ifru.ifru_flags &= !(IFF_UP as c_short);
|
|
||||||
}
|
|
||||||
|
|
||||||
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsafe fn request(&self) -> ifreq {
|
|
||||||
let mut req: ifreq = mem::zeroed();
|
|
||||||
ptr::copy_nonoverlapping(
|
|
||||||
self.name.as_ptr() as *const c_char,
|
|
||||||
req.ifr_name.as_mut_ptr(),
|
|
||||||
self.name.len(),
|
|
||||||
);
|
|
||||||
req
|
|
||||||
}
|
|
||||||
fn address(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error().into());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::new(&req.ifr_ifru.ifru_addr).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_address(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifr_ifru.ifru_addr = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destination(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::new(&req.ifr_ifru.ifru_dstaddr).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_destination(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn broadcast(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::new(&req.ifr_ifru.ifru_broadaddr).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_broadcast(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn netmask(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::new(&req.ifr_ifru.ifru_netmask).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_netmask(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifr_ifru.ifru_netmask = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
pub fn as_tun_fd(&self) -> &Fd {
|
|
||||||
&self.tun
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IFace for Device {
|
|
||||||
fn version(&self) -> io::Result<String> {
|
|
||||||
Ok(String::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> io::Result<String> {
|
|
||||||
Ok(self.name.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
|
||||||
exe_cmd(&format!("ip link delete {}", self.name))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
self.set_address(address)?;
|
|
||||||
self.set_netmask(mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mtu(&self) -> io::Result<u32> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(req.ifr_ifru.ifru_mtu as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifr_ifru.ifru_mtu = value as _;
|
|
||||||
|
|
||||||
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
|
|
||||||
route::add_route(&self.name, dest, netmask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
route::del_route(&self.name, dest, netmask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
self.tun.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
self.tun.write(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
mod device;
|
|
||||||
pub use device::Device;
|
|
||||||
mod route;
|
|
||||||
mod sys;
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
use crate::unix::exe_cmd;
|
|
||||||
|
|
||||||
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
let cmd = format!("ip route add {:?}/{:?} dev {}", address, netmask, name);
|
|
||||||
exe_cmd(&cmd)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
let cmd = format!("ip route del {:?}/{:?} dev {}", address, netmask, name);
|
|
||||||
exe_cmd(&cmd)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
use ioctl::*;
|
|
||||||
use libc::{c_int, ifreq};
|
|
||||||
|
|
||||||
ioctl!(bad read siocgifflags with 0x8913; ifreq);
|
|
||||||
ioctl!(bad write siocsifflags with 0x8914; ifreq);
|
|
||||||
ioctl!(bad read siocgifaddr with 0x8915; ifreq);
|
|
||||||
ioctl!(bad write siocsifaddr with 0x8916; ifreq);
|
|
||||||
ioctl!(bad read siocgifdstaddr with 0x8917; ifreq);
|
|
||||||
ioctl!(bad write siocsifdstaddr with 0x8918; ifreq);
|
|
||||||
ioctl!(bad read siocgifbrdaddr with 0x8919; ifreq);
|
|
||||||
ioctl!(bad write siocsifbrdaddr with 0x891a; ifreq);
|
|
||||||
ioctl!(bad read siocgifnetmask with 0x891b; ifreq);
|
|
||||||
ioctl!(bad write siocsifnetmask with 0x891c; ifreq);
|
|
||||||
ioctl!(bad read siocgifmtu with 0x8921; ifreq);
|
|
||||||
ioctl!(bad write siocsifmtu with 0x8922; ifreq);
|
|
||||||
ioctl!(bad write siocsifname with 0x8923; ifreq);
|
|
||||||
|
|
||||||
ioctl!(write tunsetiff with b'T', 202; c_int);
|
|
||||||
ioctl!(write tunsetpersist with b'T', 203; c_int);
|
|
||||||
ioctl!(write tunsetowner with b'T', 204; c_int);
|
|
||||||
ioctl!(write tunsetgroup with b'T', 206; c_int);
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
use std::ffi::{c_void, CStr};
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::os::fd::AsRawFd;
|
|
||||||
use std::{io, mem, ptr};
|
|
||||||
|
|
||||||
use libc::{
|
|
||||||
c_char, c_short, c_uint, sockaddr, socklen_t, AF_INET, AF_SYSTEM, AF_SYS_CONTROL, IFF_RUNNING,
|
|
||||||
IFF_UP, IFNAMSIZ, PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::device::IFace;
|
|
||||||
use crate::macos::route;
|
|
||||||
use crate::macos::sys::*;
|
|
||||||
use crate::unix::{Fd, SockAddr};
|
|
||||||
|
|
||||||
pub struct Device {
|
|
||||||
name: String,
|
|
||||||
ctl: Fd,
|
|
||||||
tun: Fd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
pub fn new(name: Option<String>) -> io::Result<Self> {
|
|
||||||
let id = if let Some(name) = name {
|
|
||||||
if name.len() > IFNAMSIZ {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "name too long"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !name.starts_with("utun") {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid name"));
|
|
||||||
}
|
|
||||||
|
|
||||||
name[4..]
|
|
||||||
.parse::<u32>()
|
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
|
|
||||||
+ 1u32
|
|
||||||
} else {
|
|
||||||
0u32
|
|
||||||
};
|
|
||||||
let device = unsafe {
|
|
||||||
let tun = Fd::new(libc::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL))?;
|
|
||||||
|
|
||||||
let mut info = ctl_info {
|
|
||||||
ctl_id: 0,
|
|
||||||
ctl_name: {
|
|
||||||
let mut buffer = [0; 96];
|
|
||||||
for (i, o) in UTUN_CONTROL_NAME.as_bytes().iter().zip(buffer.iter_mut()) {
|
|
||||||
*o = *i as _;
|
|
||||||
}
|
|
||||||
buffer
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if ctliocginfo(tun.0, &mut info as *mut _ as *mut _) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let addr = sockaddr_ctl {
|
|
||||||
sc_id: info.ctl_id,
|
|
||||||
sc_len: mem::size_of::<sockaddr_ctl>() as _,
|
|
||||||
sc_family: AF_SYSTEM as _,
|
|
||||||
ss_sysaddr: AF_SYS_CONTROL as _,
|
|
||||||
sc_unit: id as c_uint,
|
|
||||||
sc_reserved: [0; 5],
|
|
||||||
};
|
|
||||||
|
|
||||||
let address = &addr as *const sockaddr_ctl as *const sockaddr;
|
|
||||||
if libc::connect(tun.0, address, mem::size_of_val(&addr) as socklen_t) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut name = [0u8; 64];
|
|
||||||
let mut name_len: socklen_t = 64;
|
|
||||||
|
|
||||||
let optval = &mut name as *mut _ as *mut c_void;
|
|
||||||
let optlen = &mut name_len as *mut socklen_t;
|
|
||||||
if libc::getsockopt(tun.0, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, optval, optlen) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let ctl = Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0))?;
|
|
||||||
|
|
||||||
Device {
|
|
||||||
name: CStr::from_ptr(name.as_ptr() as *const c_char)
|
|
||||||
.to_string_lossy()
|
|
||||||
.into(),
|
|
||||||
tun,
|
|
||||||
ctl,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
device.enabled(true)?;
|
|
||||||
Ok(device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
fn enabled(&self, value: bool) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
if value {
|
|
||||||
req.ifru.flags |= (IFF_UP | IFF_RUNNING) as c_short;
|
|
||||||
} else {
|
|
||||||
req.ifru.flags &= !(IFF_UP as c_short);
|
|
||||||
}
|
|
||||||
|
|
||||||
if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsafe fn request(&self) -> ifreq {
|
|
||||||
let mut req: ifreq = mem::zeroed();
|
|
||||||
ptr::copy_nonoverlapping(
|
|
||||||
self.name.as_ptr() as *const c_char,
|
|
||||||
req.ifrn.name.as_mut_ptr(),
|
|
||||||
self.name.len(),
|
|
||||||
);
|
|
||||||
req
|
|
||||||
}
|
|
||||||
fn address(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::new(&req.ifru.addr).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_address(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifru.addr = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destination(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::new(&req.ifru.dstaddr).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_destination(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifru.dstaddr = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn broadcast(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::new(&req.ifru.broadaddr).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_broadcast(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifru.broadaddr = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn netmask(&self) -> io::Result<Ipv4Addr> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
SockAddr::unchecked(&req.ifru.addr).map(Into::into)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_netmask(&self, value: Ipv4Addr) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifru.addr = SockAddr::from(value).into();
|
|
||||||
|
|
||||||
if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Device {
|
|
||||||
pub fn as_tun_fd(&self) -> &Fd {
|
|
||||||
&self.tun
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IFace for Device {
|
|
||||||
fn version(&self) -> io::Result<String> {
|
|
||||||
Ok(String::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> io::Result<String> {
|
|
||||||
Ok(self.name.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
self.set_address(address)?;
|
|
||||||
self.set_netmask(mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mtu(&self) -> io::Result<u32> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
|
|
||||||
if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(req.ifru.mtu as _)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let mut req = self.request();
|
|
||||||
req.ifru.mtu = value as _;
|
|
||||||
|
|
||||||
if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
|
|
||||||
return Err(io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, _metric: u16) -> io::Result<()> {
|
|
||||||
route::add_route(&self.name, dest, netmask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
route::del_route(&self.name, dest, netmask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
self.tun.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let mut packet = Vec::<u8>::with_capacity(4 + buf.len());
|
|
||||||
packet.push(0);
|
|
||||||
packet.push(0);
|
|
||||||
packet.extend_from_slice(&(libc::PF_INET as u16).to_be_bytes());
|
|
||||||
packet.extend_from_slice(buf);
|
|
||||||
self.tun.write(&packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
mod device;
|
|
||||||
pub use device::Device;
|
|
||||||
mod sys;
|
|
||||||
|
|
||||||
mod route;
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
use crate::unix::exe_cmd;
|
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
let cmd = format!(
|
|
||||||
"route -n add {} -netmask {} -interface {}",
|
|
||||||
address, netmask, name
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
pub fn del_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
let cmd = format!(
|
|
||||||
"route -n delete {} -netmask {} -interface {}",
|
|
||||||
address, netmask, name
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
//! Bindings to internal macOS stuff.
|
|
||||||
|
|
||||||
use ioctl::*;
|
|
||||||
use libc::{c_char, c_int, c_short, c_uint, c_ushort, c_void, sockaddr, IFNAMSIZ};
|
|
||||||
|
|
||||||
pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct ctl_info {
|
|
||||||
pub ctl_id: c_uint,
|
|
||||||
pub ctl_name: [c_char; 96],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct sockaddr_ctl {
|
|
||||||
pub sc_len: c_char,
|
|
||||||
pub sc_family: c_char,
|
|
||||||
pub ss_sysaddr: c_ushort,
|
|
||||||
pub sc_id: c_uint,
|
|
||||||
pub sc_unit: c_uint,
|
|
||||||
pub sc_reserved: [c_uint; 5],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub union ifrn {
|
|
||||||
pub name: [c_char; IFNAMSIZ],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct ifdevmtu {
|
|
||||||
pub current: c_int,
|
|
||||||
pub min: c_int,
|
|
||||||
pub max: c_int,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub union ifku {
|
|
||||||
pub ptr: *mut c_void,
|
|
||||||
pub value: c_int,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct ifkpi {
|
|
||||||
pub module_id: c_uint,
|
|
||||||
pub type_: c_uint,
|
|
||||||
pub ifku: ifku,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub union ifru {
|
|
||||||
pub addr: sockaddr,
|
|
||||||
pub dstaddr: sockaddr,
|
|
||||||
pub broadaddr: sockaddr,
|
|
||||||
|
|
||||||
pub flags: c_short,
|
|
||||||
pub metric: c_int,
|
|
||||||
pub mtu: c_int,
|
|
||||||
pub phys: c_int,
|
|
||||||
pub media: c_int,
|
|
||||||
pub intval: c_int,
|
|
||||||
pub data: *mut c_void,
|
|
||||||
pub devmtu: ifdevmtu,
|
|
||||||
pub wake_flags: c_uint,
|
|
||||||
pub route_refcnt: c_uint,
|
|
||||||
pub cap: [c_int; 2],
|
|
||||||
pub functional_type: c_uint,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct ifreq {
|
|
||||||
pub ifrn: ifrn,
|
|
||||||
pub ifru: ifru,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct ifaliasreq {
|
|
||||||
pub ifran: [c_char; IFNAMSIZ],
|
|
||||||
pub addr: sockaddr,
|
|
||||||
pub broadaddr: sockaddr,
|
|
||||||
pub mask: sockaddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
ioctl!(readwrite ctliocginfo with 'N', 3; ctl_info);
|
|
||||||
|
|
||||||
ioctl!(write siocsifflags with 'i', 16; ifreq);
|
|
||||||
ioctl!(readwrite siocgifflags with 'i', 17; ifreq);
|
|
||||||
|
|
||||||
ioctl!(write siocsifaddr with 'i', 12; ifreq);
|
|
||||||
ioctl!(readwrite siocgifaddr with 'i', 33; ifreq);
|
|
||||||
|
|
||||||
ioctl!(write siocsifdstaddr with 'i', 14; ifreq);
|
|
||||||
ioctl!(readwrite siocgifdstaddr with 'i', 34; ifreq);
|
|
||||||
|
|
||||||
ioctl!(write siocsifbrdaddr with 'i', 19; ifreq);
|
|
||||||
ioctl!(readwrite siocgifbrdaddr with 'i', 35; ifreq);
|
|
||||||
|
|
||||||
ioctl!(write siocsifnetmask with 'i', 22; ifreq);
|
|
||||||
ioctl!(readwrite siocgifnetmask with 'i', 37; ifreq);
|
|
||||||
|
|
||||||
ioctl!(write siocsifmtu with 'i', 52; ifreq);
|
|
||||||
ioctl!(readwrite siocgifmtu with 'i', 51; ifreq);
|
|
||||||
|
|
||||||
ioctl!(write siocaifaddr with 'i', 26; ifaliasreq);
|
|
||||||
ioctl!(write siocdifaddr with 'i', 25; ifreq);
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub mod packet;
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
pub mod packet;
|
|
||||||
pub mod protocol;
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
use crate::packet::ethernet::protocol::Protocol;
|
|
||||||
use std::{fmt, io};
|
|
||||||
|
|
||||||
/// 以太网帧协议
|
|
||||||
/// 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::new(
|
|
||||||
io::ErrorKind::InvalidData,
|
|
||||||
format!("len={}", packet.buffer.as_ref().len()),
|
|
||||||
))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
/// 以太网帧协议
|
|
||||||
#[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,67 +0,0 @@
|
|||||||
use crate::packet::ethernet::protocol::Protocol;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
pub mod arp;
|
|
||||||
pub mod ethernet;
|
|
||||||
|
|
||||||
const MAC: [u8; 6] = [0xf, 0xf, 0xf, 0xf, 0xe, 0x9];
|
|
||||||
pub fn read_tap<W, R>(buf: &mut [u8], read_fn: R, write_fn: W) -> io::Result<usize>
|
|
||||||
where
|
|
||||||
W: Fn(&[u8]) -> io::Result<usize>,
|
|
||||||
R: Fn(&mut [u8]) -> io::Result<usize>,
|
|
||||||
{
|
|
||||||
let mut eth_buf = [0; 65536];
|
|
||||||
loop {
|
|
||||||
let len = read_fn(&mut eth_buf)?;
|
|
||||||
if len == 0 {
|
|
||||||
return Ok(len);
|
|
||||||
}
|
|
||||||
//处理arp包
|
|
||||||
let mut ether = ethernet::packet::EthernetPacket::new(&mut eth_buf[..len])?;
|
|
||||||
match ether.protocol() {
|
|
||||||
Protocol::Ipv4 => {
|
|
||||||
let len = ether.payload().len();
|
|
||||||
if len > buf.len() {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "short"));
|
|
||||||
}
|
|
||||||
buf[..len].copy_from_slice(ether.payload());
|
|
||||||
return Ok(len);
|
|
||||||
}
|
|
||||||
Protocol::Arp => {
|
|
||||||
let mut arp_packet = arp::packet::ArpPacket::unchecked(ether.payload_mut());
|
|
||||||
let sender_h: [u8; 6] = arp_packet.sender_hardware_addr().try_into().unwrap();
|
|
||||||
let sender_p: [u8; 4] = arp_packet.sender_protocol_addr().try_into().unwrap();
|
|
||||||
let target_p: [u8; 4] = arp_packet.target_protocol_addr().try_into().unwrap();
|
|
||||||
if target_p == [0, 0, 0, 0] || sender_p == [0, 0, 0, 0] || target_p == sender_p {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if arp_packet.op_code() == 1 {
|
|
||||||
//回复一个默认的MAC
|
|
||||||
arp_packet.set_op_code(2);
|
|
||||||
arp_packet.set_target_hardware_addr(&sender_h);
|
|
||||||
arp_packet.set_target_protocol_addr(&sender_p);
|
|
||||||
arp_packet.set_sender_protocol_addr(&target_p);
|
|
||||||
arp_packet.set_sender_hardware_addr(&MAC);
|
|
||||||
ether.set_destination(&sender_h);
|
|
||||||
ether.set_source(&MAC);
|
|
||||||
write_fn(ether.buffer)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
//忽略这些数据
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn write_tap<W>(buf: &[u8], write_fn: W, mac: &[u8; 6]) -> io::Result<usize>
|
|
||||||
where
|
|
||||||
W: Fn(&[u8]) -> io::Result<usize>,
|
|
||||||
{
|
|
||||||
// 封装二层数据
|
|
||||||
let mut ether = ethernet::packet::EthernetPacket::unchecked(vec![0; 14 + buf.len()]);
|
|
||||||
ether.set_source(&MAC);
|
|
||||||
ether.set_destination(mac);
|
|
||||||
ether.set_protocol(Protocol::Ipv4);
|
|
||||||
ether.payload_mut().copy_from_slice(buf);
|
|
||||||
write_fn(ðer.buffer)
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
use libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
|
|
||||||
use std::io;
|
|
||||||
use std::os::fd::{AsRawFd, IntoRawFd, RawFd};
|
|
||||||
|
|
||||||
pub struct Fd(pub RawFd);
|
|
||||||
|
|
||||||
impl Fd {
|
|
||||||
pub fn new(value: RawFd) -> io::Result<Self> {
|
|
||||||
if value < 0 {
|
|
||||||
return Err(io::Error::from(io::ErrorKind::InvalidInput));
|
|
||||||
}
|
|
||||||
Ok(Fd(value))
|
|
||||||
}
|
|
||||||
pub fn set_nonblock(&self) -> io::Result<()> {
|
|
||||||
match unsafe { fcntl(self.0, F_SETFL, fcntl(self.0, F_GETFL) | O_NONBLOCK) } {
|
|
||||||
0 => Ok(()),
|
|
||||||
_ => Err(io::Error::last_os_error()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fd {
|
|
||||||
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 write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
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(amount as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRawFd for Fd {
|
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoRawFd for Fd {
|
|
||||||
fn into_raw_fd(mut self) -> RawFd {
|
|
||||||
let fd = self.0;
|
|
||||||
self.0 = -1;
|
|
||||||
fd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
impl Drop for Fd {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
if self.0 >= 0 {
|
|
||||||
libc::close(self.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
mod fd;
|
|
||||||
|
|
||||||
pub use fd::Fd;
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
|
||||||
use std::process::Output;
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
|
||||||
mod sockaddr;
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
|
||||||
pub use sockaddr::SockAddr;
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
|
||||||
pub fn exe_cmd(cmd: &str) -> std::io::Result<Output> {
|
|
||||||
use std::io;
|
|
||||||
use std::process::Command;
|
|
||||||
println!("exe cmd: {}", cmd);
|
|
||||||
let out = Command::new("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(cmd)
|
|
||||||
.output()
|
|
||||||
.expect("sh exec error!");
|
|
||||||
if !out.status.success() {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("cmd={},out={:?}", cmd, out),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
use libc::{in_addr, sockaddr, sockaddr_in};
|
|
||||||
use std::{io, mem, net::Ipv4Addr, ptr};
|
|
||||||
|
|
||||||
use io::Result;
|
|
||||||
|
|
||||||
/// A wrapper for `sockaddr_in`.
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct SockAddr(sockaddr_in);
|
|
||||||
|
|
||||||
impl SockAddr {
|
|
||||||
/// Create a new `SockAddr` from a generic `sockaddr`.
|
|
||||||
pub fn new(value: &sockaddr) -> Result<Self> {
|
|
||||||
if value.sa_family != libc::AF_INET as libc::sa_family_t {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "invalid address"));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { Self::unchecked(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// Create a new `SockAddr` and not check the source.
|
|
||||||
pub unsafe fn unchecked(value: &sockaddr) -> Result<Self> {
|
|
||||||
Ok(SockAddr(ptr::read(value as *const _ as *const _)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// Get a generic pointer to the `SockAddr`.
|
|
||||||
pub unsafe fn as_ptr(&self) -> *const sockaddr {
|
|
||||||
&self.0 as *const _ as *const sockaddr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Ipv4Addr> for SockAddr {
|
|
||||||
fn from(ip: Ipv4Addr) -> SockAddr {
|
|
||||||
let octets = ip.octets();
|
|
||||||
let mut addr = unsafe { mem::zeroed::<sockaddr_in>() };
|
|
||||||
|
|
||||||
addr.sin_family = libc::AF_INET as libc::sa_family_t;
|
|
||||||
addr.sin_port = 0;
|
|
||||||
addr.sin_addr = in_addr {
|
|
||||||
s_addr: u32::from_ne_bytes(octets),
|
|
||||||
};
|
|
||||||
|
|
||||||
SockAddr(addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SockAddr> for Ipv4Addr {
|
|
||||||
fn from(addr: SockAddr) -> Ipv4Addr {
|
|
||||||
let ip = addr.0.sin_addr.s_addr;
|
|
||||||
let [a, b, c, d] = ip.to_ne_bytes();
|
|
||||||
|
|
||||||
Ipv4Addr::new(a, b, c, d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SockAddr> for sockaddr {
|
|
||||||
fn from(addr: SockAddr) -> sockaddr {
|
|
||||||
unsafe { mem::transmute(addr.0) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SockAddr> for sockaddr_in {
|
|
||||||
fn from(addr: SockAddr) -> sockaddr_in {
|
|
||||||
addr.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
use crate::device::IFace;
|
|
||||||
use crate::windows::{tap, tun};
|
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
pub enum Device {
|
|
||||||
Tap(tap::Device),
|
|
||||||
Tun(tun::Device),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
pub fn new(name: String, tap: bool) -> io::Result<Self> {
|
|
||||||
if tap {
|
|
||||||
Ok(Device::Tap(tap::Device::new(name)?))
|
|
||||||
} else {
|
|
||||||
Ok(Device::Tun(tun::Device::new(name)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IFace for Device {
|
|
||||||
fn version(&self) -> io::Result<String> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.version(),
|
|
||||||
Device::Tun(dev) => dev.version(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> io::Result<String> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.name(),
|
|
||||||
Device::Tun(dev) => dev.name(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.shutdown(),
|
|
||||||
Device::Tun(dev) => dev.shutdown(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.set_ip(address, mask),
|
|
||||||
Device::Tun(dev) => dev.set_ip(address, mask),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mtu(&self) -> io::Result<u32> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.mtu(),
|
|
||||||
Device::Tun(dev) => dev.mtu(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.set_mtu(value),
|
|
||||||
Device::Tun(dev) => dev.set_mtu(value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.add_route(dest, netmask, metric),
|
|
||||||
Device::Tun(dev) => dev.add_route(dest, netmask, metric),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.delete_route(dest, netmask),
|
|
||||||
Device::Tun(dev) => dev.delete_route(dest, netmask),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.read(buf),
|
|
||||||
Device::Tun(dev) => dev.read(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
match self {
|
|
||||||
Device::Tap(dev) => dev.write(buf),
|
|
||||||
Device::Tun(dev) => dev.write(buf),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,502 +0,0 @@
|
|||||||
// 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::error::Error;
|
|
||||||
use std::{io, mem, ptr};
|
|
||||||
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) == ERROR_IO_PENDING as _ {
|
|
||||||
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) == ERROR_IO_PENDING as _ {
|
|
||||||
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(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
use std::io;
|
|
||||||
use std::os::windows::process::CommandExt;
|
|
||||||
use winapi::shared::minwindef::DWORD;
|
|
||||||
use winapi::um::winbase::CREATE_NO_WINDOW;
|
|
||||||
|
|
||||||
mod device;
|
|
||||||
mod ffi;
|
|
||||||
mod netsh;
|
|
||||||
mod route;
|
|
||||||
mod tap;
|
|
||||||
mod tun;
|
|
||||||
pub use device::Device;
|
|
||||||
|
|
||||||
/// Encode a string as a utf16 buffer
|
|
||||||
pub fn encode_utf16(string: &str) -> Vec<u16> {
|
|
||||||
use std::iter::once;
|
|
||||||
string.encode_utf16().chain(once(0)).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub 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 const fn ctl_code(device_type: DWORD, function: DWORD, method: DWORD, access: DWORD) -> DWORD {
|
|
||||||
(device_type << 16) | (access << 14) | (function << 2) | method
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exe_cmd(cmd: &str) -> io::Result<()> {
|
|
||||||
println!("exe cmd: {}", cmd);
|
|
||||||
let out = std::process::Command::new("cmd")
|
|
||||||
.creation_flags(CREATE_NO_WINDOW)
|
|
||||||
.arg("/C")
|
|
||||||
.arg(&cmd)
|
|
||||||
.output()?;
|
|
||||||
if !out.status.success() {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("cmd={},out={:?}", cmd, String::from_utf8(out.stderr)),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
use crate::windows::exe_cmd;
|
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
/// 设置网卡名称
|
|
||||||
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
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)
|
|
||||||
}
|
|
||||||
/// 删除缓存
|
|
||||||
pub fn delete_cache() -> io::Result<()> {
|
|
||||||
//清除缓存
|
|
||||||
let cmd = "netsh interface ip delete destinationcache";
|
|
||||||
exe_cmd(cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 设置网卡ip
|
|
||||||
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
|
|
||||||
let cmd = format!(
|
|
||||||
"netsh interface ip set address {} static {:?} {:?} ",
|
|
||||||
index, address, netmask,
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_interface_mtu(index: u32, mtu: u32) -> io::Result<()> {
|
|
||||||
let cmd = format!(
|
|
||||||
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
|
|
||||||
index, mtu
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)
|
|
||||||
}
|
|
||||||
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
|
|
||||||
let cmd = format!(
|
|
||||||
"netsh interface ip set interface {} metric={}",
|
|
||||||
index, metric
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)
|
|
||||||
}
|
|
||||||
/// 禁用ipv6
|
|
||||||
pub fn disabled_ipv6(index: u32) -> io::Result<()> {
|
|
||||||
let cmd = format!("netsh interface ipv6 set interface {} disabled", index);
|
|
||||||
exe_cmd(&cmd)
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
use crate::windows::exe_cmd;
|
|
||||||
|
|
||||||
/// 添加路由
|
|
||||||
pub fn add_route(
|
|
||||||
index: u32,
|
|
||||||
dest: Ipv4Addr,
|
|
||||||
netmask: Ipv4Addr,
|
|
||||||
gateway: Ipv4Addr,
|
|
||||||
metric: u16,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let cmd = format!(
|
|
||||||
"route add {:?} mask {:?} {:?} metric {} if {}",
|
|
||||||
dest, netmask, gateway, metric, index
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 删除路由
|
|
||||||
pub fn delete_route(
|
|
||||||
index: u32,
|
|
||||||
dest: Ipv4Addr,
|
|
||||||
netmask: Ipv4Addr,
|
|
||||||
gateway: Ipv4Addr,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let cmd = format!(
|
|
||||||
"route delete {:?} mask {:?} {:?} if {}",
|
|
||||||
dest, netmask, gateway, index
|
|
||||||
);
|
|
||||||
exe_cmd(&cmd)
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use winapi::shared::ifdef::NET_LUID;
|
|
||||||
use winapi::shared::minwindef::DWORD;
|
|
||||||
use winapi::um::fileapi::OPEN_EXISTING;
|
|
||||||
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
|
||||||
use winapi::um::winioctl::{FILE_ANY_ACCESS, FILE_DEVICE_UNKNOWN, METHOD_BUFFERED};
|
|
||||||
use winapi::um::winnt::{
|
|
||||||
FILE_ATTRIBUTE_SYSTEM, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::device::IFace;
|
|
||||||
use crate::packet;
|
|
||||||
use crate::windows::{ctl_code, decode_utf16, encode_utf16, ffi, netsh, route};
|
|
||||||
|
|
||||||
/* Present in 8.1 */
|
|
||||||
const TAP_WIN_IOCTL_GET_MAC: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_GET_VERSION: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_GET_MTU: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_GET_INFO: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 4, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 5, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_SET_MEDIA_STATUS: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_CONFIG_DHCP_MASQ: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 7, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_GET_LOG_LINE: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 8, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
const TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 9, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
/* Added in 8.2 */
|
|
||||||
/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
|
|
||||||
const TAP_WIN_IOCTL_CONFIG_TUN: DWORD =
|
|
||||||
ctl_code(FILE_DEVICE_UNKNOWN, 10, METHOD_BUFFERED, FILE_ANY_ACCESS);
|
|
||||||
|
|
||||||
pub struct Device {
|
|
||||||
handle: HANDLE,
|
|
||||||
index: u32,
|
|
||||||
luid: NET_LUID,
|
|
||||||
mac: [u8; 6],
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for Device {}
|
|
||||||
|
|
||||||
unsafe impl Sync for Device {}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
/// 打开设备,设置为TUN模式,激活网卡
|
|
||||||
pub fn new(name: String) -> io::Result<Self> {
|
|
||||||
let luid = ffi::alias_to_luid(&encode_utf16(&name)).map_err(|e| {
|
|
||||||
io::Error::new(e.kind(), format!("alias_to_luid name={},err={:?}", name, e))
|
|
||||||
})?;
|
|
||||||
let guid = ffi::luid_to_guid(&luid)
|
|
||||||
.and_then(|guid| ffi::string_from_guid(&guid))
|
|
||||||
.map_err(|e| {
|
|
||||||
io::Error::new(e.kind(), format!("luid_to_guid name={},err={:?}", name, e))
|
|
||||||
})?;
|
|
||||||
let path = format!(r"\\.\Global\{}.tap", decode_utf16(&guid));
|
|
||||||
let handle = ffi::create_file(
|
|
||||||
&encode_utf16(&path),
|
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
|
||||||
)
|
|
||||||
.map_err(|e| io::Error::new(e.kind(), format!("tap name={},err={:?}", name, e)))?;
|
|
||||||
|
|
||||||
// ep保存tun网卡的IP地址和掩码
|
|
||||||
// let mut ep = [0;3];
|
|
||||||
// ep[0] = Ipv4Addr::new(10,26,0,11).into();
|
|
||||||
// ep[2] = Ipv4Addr::new(255,255,255,0).into();;
|
|
||||||
// ep[1] = ep[0] & ep[2];
|
|
||||||
// //tun模式收不到ipv4包,原因未知 https://github.com/OpenVPN/tap-windows6/issues/111
|
|
||||||
// ffi::device_io_control(handle, TAP_WIN_IOCTL_CONFIG_TUN, &ep, &mut ()).map_err(
|
|
||||||
// |e| {
|
|
||||||
// io::Error::new(
|
|
||||||
// e.kind(),
|
|
||||||
// format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name_str, e),
|
|
||||||
// )
|
|
||||||
// },
|
|
||||||
// )?;
|
|
||||||
let mut mac = [0u8; 6];
|
|
||||||
ffi::device_io_control(handle, TAP_WIN_IOCTL_GET_MAC, &(), &mut mac)
|
|
||||||
.map_err(|e| {
|
|
||||||
io::Error::new(
|
|
||||||
e.kind(),
|
|
||||||
format!("TAP_WIN_IOCTL_CONFIG_TUN name={},err={:?}", name, e),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|e| io::Error::new(e.kind(), format!("TAP_WIN_IOCTL_GET_MAC,err={:?}", e)))?;
|
|
||||||
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
|
||||||
// 设置网卡跃点
|
|
||||||
if let Err(e) = netsh::set_interface_metric(index, 0) {
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
}
|
|
||||||
let device = Self {
|
|
||||||
handle,
|
|
||||||
index,
|
|
||||||
luid,
|
|
||||||
mac,
|
|
||||||
};
|
|
||||||
device.enabled(true)?;
|
|
||||||
Ok(device)
|
|
||||||
}
|
|
||||||
fn write_tap(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
ffi::write_file(self.handle, buf).map(|res| res as _)
|
|
||||||
}
|
|
||||||
fn enabled(&self, value: bool) -> io::Result<()> {
|
|
||||||
let status: u32 = if value { 1 } else { 0 };
|
|
||||||
ffi::device_io_control(
|
|
||||||
self.handle,
|
|
||||||
TAP_WIN_IOCTL_SET_MEDIA_STATUS,
|
|
||||||
&status,
|
|
||||||
&mut (),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IFace for Device {
|
|
||||||
fn version(&self) -> io::Result<String> {
|
|
||||||
let mut version = [0u32; 3];
|
|
||||||
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_VERSION, &(), &mut version)?;
|
|
||||||
Ok(format!("{}.{}.{}", version[0], version[1], version[2]))
|
|
||||||
}
|
|
||||||
fn name(&self) -> io::Result<String> {
|
|
||||||
ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
|
||||||
self.enabled(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
netsh::set_interface_ip(self.index, &address, &mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mtu(&self) -> io::Result<u32> {
|
|
||||||
let mut mtu = 0;
|
|
||||||
ffi::device_io_control(self.handle, TAP_WIN_IOCTL_GET_MTU, &(), &mut mtu).map(|_| mtu)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
|
||||||
netsh::set_interface_mtu(self.index, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
|
|
||||||
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
|
|
||||||
netsh::delete_cache()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
|
|
||||||
netsh::delete_cache()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
packet::read_tap(
|
|
||||||
buf,
|
|
||||||
|eth_buf| ffi::read_file(self.handle, eth_buf).map(|res| res as usize),
|
|
||||||
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
// 封装二层数据
|
|
||||||
packet::write_tap(
|
|
||||||
buf,
|
|
||||||
|eth_buf| ffi::write_file(self.handle, eth_buf).map(|res| res as _),
|
|
||||||
&self.mac,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Device {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Err(e) = ffi::close_handle(self.handle) {
|
|
||||||
log::warn!("close_handle={:?}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,344 +0,0 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
use libloading::Library;
|
|
||||||
use std::io;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
use rand::Rng;
|
|
||||||
use winapi::um::winbase;
|
|
||||||
use winapi::um::{synchapi, winnt};
|
|
||||||
|
|
||||||
use crate::device::IFace;
|
|
||||||
use crate::windows::decode_utf16;
|
|
||||||
use crate::windows::{encode_utf16, ffi, netsh, route};
|
|
||||||
|
|
||||||
mod packet;
|
|
||||||
mod wintun_log;
|
|
||||||
mod wintun_raw;
|
|
||||||
|
|
||||||
/// 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 Device {
|
|
||||||
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 Device {}
|
|
||||||
|
|
||||||
unsafe impl Sync for Device {}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
pub fn new(name: String) -> io::Result<Self> {
|
|
||||||
unsafe {
|
|
||||||
let library = match Library::new("wintun.dll") {
|
|
||||||
Ok(library) => library,
|
|
||||||
Err(e) => {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("wintun.dll not found {:?}", e),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
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 name_utf16 = encode_utf16(&name);
|
|
||||||
if name_utf16.len() > MAX_POOL {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("too long {}:{:?}", MAX_POOL, name),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
wintun_log::set_default_logger_if_unset(&win_tun);
|
|
||||||
let _ = Self::delete_for_name(&win_tun, &name_utf16);
|
|
||||||
let mut guid_bytes: [u8; 16] = [0u8; 16];
|
|
||||||
rand::thread_rng().fill(&mut guid_bytes);
|
|
||||||
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 = std::mem::transmute(guid);
|
|
||||||
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
|
|
||||||
|
|
||||||
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
|
|
||||||
//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(name_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
|
|
||||||
if adapter.is_null() {
|
|
||||||
log::error!("adapter.is_null {:?}", io::Error::last_os_error());
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Failed to crate adapter",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
// 开启session
|
|
||||||
let session = win_tun.WintunStartSession(adapter, MAX_RING_CAPACITY);
|
|
||||||
if session.is_null() {
|
|
||||||
log::error!("session.is_null {:?}", io::Error::last_os_error());
|
|
||||||
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)?;
|
|
||||||
// 设置网卡跃点
|
|
||||||
if let Err(e) = netsh::set_interface_metric(index, 0) {
|
|
||||||
log::warn!("{:?}", e);
|
|
||||||
}
|
|
||||||
Ok(Self {
|
|
||||||
luid: std::mem::transmute(luid),
|
|
||||||
index,
|
|
||||||
session,
|
|
||||||
win_tun,
|
|
||||||
read_event,
|
|
||||||
shutdown_event,
|
|
||||||
adapter,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub unsafe fn delete_for_name(
|
|
||||||
win_tun: &wintun_raw::wintun,
|
|
||||||
name_utf16: &Vec<u16>,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
|
|
||||||
if adapter.is_null() {
|
|
||||||
log::error!(
|
|
||||||
"delete_for_name adapter.is_null {:?}",
|
|
||||||
io::Error::last_os_error()
|
|
||||||
);
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Failed to open adapter",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
win_tun.WintunCloseAdapter(adapter);
|
|
||||||
win_tun.WintunDeleteDriver();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IFace for Device {
|
|
||||||
fn version(&self) -> io::Result<String> {
|
|
||||||
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
|
|
||||||
if version == 0 {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"WintunGetRunningDriverVersion",
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
Ok(format!("{}.{}", (version >> 16) & 0xFFFF, version & 0xFFFF))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn name(&self) -> io::Result<String> {
|
|
||||||
let luid = self.luid;
|
|
||||||
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| decode_utf16(&name))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shutdown(&self) -> io::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
if 0 == synchapi::SetEvent(self.shutdown_event) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(io::Error::last_os_error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_ip(&self, address: Ipv4Addr, mask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
netsh::set_interface_ip(self.index, &address, &mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mtu(&self) -> io::Result<u32> {
|
|
||||||
Err(io::Error::from(io::ErrorKind::Unsupported))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mtu(&self, value: u32) -> io::Result<()> {
|
|
||||||
netsh::set_interface_mtu(self.index, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr, metric: u16) -> io::Result<()> {
|
|
||||||
route::add_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED, metric)?;
|
|
||||||
netsh::delete_cache()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_route(&self, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
|
||||||
route::delete_route(self.index, dest, netmask, Ipv4Addr::UNSPECIFIED)?;
|
|
||||||
netsh::delete_cache()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
let packet = self.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let mut packet = self.allocate_send_packet(buf.len() as u16)?;
|
|
||||||
packet.bytes_mut().copy_from_slice(buf);
|
|
||||||
self.send_packet(packet);
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
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 16 times to receive without blocking so we don't have to issue a syscall to wait
|
|
||||||
//for the event if packets are being received at a rapid rate
|
|
||||||
for _i in 0..20 {
|
|
||||||
match self.try_receive()? {
|
|
||||||
None => {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Some(packet) => {
|
|
||||||
return Ok(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//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",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 Device {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
if let Err(e) = ffi::close_handle(self.shutdown_event) {
|
|
||||||
log::warn!("close shutdown_event={:?}", e)
|
|
||||||
}
|
|
||||||
self.win_tun.WintunEndSession(self.session);
|
|
||||||
self.win_tun.WintunCloseAdapter(self.adapter);
|
|
||||||
if 0 != self.win_tun.WintunDeleteDriver() {
|
|
||||||
log::warn!("WintunDeleteDriver failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
use crate::windows::tun::Device;
|
|
||||||
|
|
||||||
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 Device>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
use log::*;
|
|
||||||
|
|
||||||
use crate::windows::tun::wintun_raw;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use widestring::U16CStr;
|
|
||||||
|
|
||||||
/// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,449 +0,0 @@
|
|||||||
#![allow(non_snake_case)]
|
|
||||||
#![allow(non_camel_case_types)]
|
|
||||||
/* automatically generated by rust-bindgen 0.59.1 */
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
|
||||||
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