Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6773aa549 | ||
|
|
0314c66635 | ||
|
|
3fb172b4d2 | ||
|
|
96fc19b803 | ||
|
|
9f7ba8ab8f | ||
|
|
e592e9f29a | ||
|
|
4608bca998 | ||
|
|
b5dfc7374c | ||
|
|
b469f8197a | ||
|
|
0a38a8ef4a | ||
|
|
e75be7801f | ||
|
|
6c49bb1865 | ||
|
|
f9c24bc205 |
@@ -6,72 +6,84 @@ rustflags = ["-C", "linker-flavor=ld.lld"]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
linker = "aarch64-linux-musl-gcc"
|
||||
linker = "aarch64-unknown-linux-musl-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
|
||||
[target.'cfg(all(windows, target_env = "msvc"))']
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
|
||||
[target.mipsel-unknown-linux-musl]
|
||||
linker = "mipsel-linux-muslsf-gcc"
|
||||
linker = "mipsel-unknown-linux-muslsf-gcc"
|
||||
rustflags = [
|
||||
"-C",
|
||||
"target-feature=+crt-static",
|
||||
"-L",
|
||||
"./musl_gcc/mipsel-linux-muslsf-cross/mipsel-linux-muslsf/lib",
|
||||
"./musl_gcc/mipsel-unknown-linux-muslsf/mipsel-unknown-linux-muslsf/lib",
|
||||
"-L",
|
||||
"./musl_gcc/mipsel-linux-muslsf-cross/lib/gcc/mipsel-linux-muslsf/11.2.1",
|
||||
"./musl_gcc/mipsel-unknown-linux-muslsf/mipsel-unknown-linux-muslsf/sysroot/usr/lib",
|
||||
"-L",
|
||||
"./musl_gcc/mipsel-unknown-linux-muslsf/lib/gcc/mipsel-unknown-linux-muslsf/15.1.0",
|
||||
"-l",
|
||||
"atomic",
|
||||
"-l",
|
||||
"ctz",
|
||||
"-l",
|
||||
"gcc",
|
||||
]
|
||||
|
||||
[target.mips-unknown-linux-musl]
|
||||
linker = "mips-linux-muslsf-gcc"
|
||||
linker = "mips-unknown-linux-muslsf-gcc"
|
||||
rustflags = [
|
||||
"-C",
|
||||
"target-feature=+crt-static",
|
||||
"-L",
|
||||
"./musl_gcc/mips-linux-muslsf-cross/mips-linux-muslsf/lib",
|
||||
"./musl_gcc/mips-unknown-linux-muslsf/mips-unknown-linux-muslsf/lib",
|
||||
"-L",
|
||||
"./musl_gcc/mips-linux-muslsf-cross/lib/gcc/mips-linux-muslsf/11.2.1",
|
||||
"./musl_gcc/mips-unknown-linux-muslsf/mips-unknown-linux-muslsf/sysroot/usr/lib",
|
||||
"-L",
|
||||
"./musl_gcc/mips-unknown-linux-muslsf/lib/gcc/mips-unknown-linux-muslsf/15.1.0",
|
||||
"-l",
|
||||
"atomic",
|
||||
"-l",
|
||||
"ctz",
|
||||
"-l",
|
||||
"gcc",
|
||||
]
|
||||
|
||||
[target.armv7-unknown-linux-musleabihf]
|
||||
linker = "armv7l-linux-musleabihf-gcc"
|
||||
linker = "armv7-unknown-linux-musleabihf-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
|
||||
[target.armv7-unknown-linux-musleabi]
|
||||
linker = "armv7m-linux-musleabi-gcc"
|
||||
linker = "armv7-unknown-linux-musleabi-gcc"
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
|
||||
[target.arm-unknown-linux-musleabihf]
|
||||
linker = "arm-linux-musleabihf-gcc"
|
||||
linker = "arm-unknown-linux-musleabihf-gcc"
|
||||
rustflags = [
|
||||
"-C",
|
||||
"target-feature=+crt-static",
|
||||
"-L",
|
||||
"./musl_gcc/arm-linux-musleabihf-cross/arm-linux-musleabihf/lib",
|
||||
"./musl_gcc/arm-unknown-linux-musleabihf/arm-unknown-linux-musleabihf/lib",
|
||||
"-L",
|
||||
"./musl_gcc/arm-linux-musleabihf-cross/lib/gcc/arm-linux-musleabihf/11.2.1",
|
||||
"./musl_gcc/arm-unknown-linux-musleabihf/lib/gcc/arm-unknown-linux-musleabihf/15.1.0",
|
||||
"-l",
|
||||
"atomic",
|
||||
"-l",
|
||||
"gcc",
|
||||
]
|
||||
|
||||
[target.arm-unknown-linux-musleabi]
|
||||
linker = "arm-linux-musleabi-gcc"
|
||||
linker = "arm-unknown-linux-musleabi-gcc"
|
||||
rustflags = [
|
||||
"-C",
|
||||
"target-feature=+crt-static",
|
||||
"-L",
|
||||
"./musl_gcc/arm-linux-musleabi-cross/arm-linux-musleabi/lib",
|
||||
"./musl_gcc/arm-unknown-linux-musleabi/arm-unknown-linux-musleabi/lib",
|
||||
"-L",
|
||||
"./musl_gcc/arm-linux-musleabi-cross/lib/gcc/arm-linux-musleabi/11.2.1",
|
||||
"./musl_gcc/arm-unknown-linux-musleabi/lib/gcc/arm-unknown-linux-musleabi/15.1.0",
|
||||
"-l",
|
||||
"atomic",
|
||||
"-l",
|
||||
"gcc",
|
||||
]
|
||||
|
||||
21
.github/workflows/core.yml
vendored
21
.github/workflows/core.yml
vendored
@@ -166,9 +166,14 @@ jobs:
|
||||
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }}
|
||||
run: |
|
||||
bash ./.github/workflows/install_rust.sh
|
||||
|
||||
# we set the sysroot when sysroot is a dir
|
||||
# this dir is a soft link generated by install_rust.sh
|
||||
# kcp-sys need this to gen ffi bindings. without this clang may fail to find some libc headers such as bits/libc-header-start.h
|
||||
export KCP_SYS_EXTRA_HEADER_PATH=/usr/include/musl-cross
|
||||
if [[ -d "./musl_gcc/sysroot" ]]; then
|
||||
export BINDGEN_EXTRA_CLANG_ARGS=--sysroot=$(readlink -f ./musl_gcc/sysroot)
|
||||
fi
|
||||
|
||||
if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then
|
||||
cargo +nightly build -r --verbose --target $TARGET -Z build-std=std,panic_abort --no-default-features --features mips --package=easytier
|
||||
else
|
||||
@@ -218,13 +223,6 @@ jobs:
|
||||
mv ./target/$TARGET/release/easytier-web ./target/$TARGET/release/easytier-web-embed
|
||||
cargo build --release --verbose --target $TARGET
|
||||
|
||||
- name: Install UPX
|
||||
if: ${{ matrix.OS != 'macos-latest' }}
|
||||
uses: crazy-max/ghaction-upx@v3
|
||||
with:
|
||||
version: latest
|
||||
install-only: true
|
||||
|
||||
- name: Compress
|
||||
run: |
|
||||
mkdir -p ./artifacts/objects/
|
||||
@@ -246,8 +244,11 @@ jobs:
|
||||
fi
|
||||
|
||||
if [[ $OS =~ ^ubuntu.*$ && ! $TARGET =~ ^.*freebsd$ ]]; then
|
||||
upx --lzma --best ./target/$TARGET/release/easytier-core"$SUFFIX"
|
||||
upx --lzma --best ./target/$TARGET/release/easytier-cli"$SUFFIX"
|
||||
UPX_VERSION=5.0.1
|
||||
curl -L https://github.com/upx/upx/releases/download/v${UPX_VERSION}/upx-${UPX_VERSION}-amd64_linux.tar.xz -s | tar xJvf -
|
||||
cp upx-${UPX_VERSION}-amd64_linux/upx .
|
||||
./upx --lzma --best ./target/$TARGET/release/easytier-core"$SUFFIX"
|
||||
./upx --lzma --best ./target/$TARGET/release/easytier-cli"$SUFFIX"
|
||||
fi
|
||||
|
||||
mv ./target/$TARGET/release/easytier-core"$SUFFIX" ./artifacts/objects/
|
||||
|
||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
image_tag:
|
||||
description: 'Tag for this image build'
|
||||
type: string
|
||||
default: 'v2.3.0'
|
||||
default: 'v2.3.1'
|
||||
required: true
|
||||
mark_latest:
|
||||
description: 'Mark this image as latest'
|
||||
|
||||
48
.github/workflows/install_rust.sh
vendored
48
.github/workflows/install_rust.sh
vendored
@@ -8,38 +8,22 @@
|
||||
# dependencies are only needed on ubuntu as that's the only place where
|
||||
# we make cross-compilation
|
||||
if [[ $OS =~ ^ubuntu.*$ ]]; then
|
||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools libappindicator3-dev llvm clang
|
||||
# curl -s musl.cc | grep mipsel
|
||||
case $TARGET in
|
||||
mipsel-unknown-linux-musl)
|
||||
MUSL_URI=mipsel-linux-muslsf
|
||||
;;
|
||||
mips-unknown-linux-musl)
|
||||
MUSL_URI=mips-linux-muslsf
|
||||
;;
|
||||
aarch64-unknown-linux-musl)
|
||||
MUSL_URI=aarch64-linux-musl
|
||||
;;
|
||||
armv7-unknown-linux-musleabihf)
|
||||
MUSL_URI=armv7l-linux-musleabihf
|
||||
;;
|
||||
armv7-unknown-linux-musleabi)
|
||||
MUSL_URI=armv7m-linux-musleabi
|
||||
;;
|
||||
arm-unknown-linux-musleabihf)
|
||||
MUSL_URI=arm-linux-musleabihf
|
||||
;;
|
||||
arm-unknown-linux-musleabi)
|
||||
MUSL_URI=arm-linux-musleabi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$MUSL_URI" ]; then
|
||||
sudo apt-get update && sudo apt-get install -qq musl-tools libappindicator3-dev llvm clang
|
||||
# https://github.com/cross-tools/musl-cross/releases
|
||||
# if "musl" is a substring of TARGET, we assume that we are using musl
|
||||
MUSL_TARGET=$TARGET
|
||||
# if target is mips or mipsel, we should use soft-float version of musl
|
||||
if [[ $TARGET =~ ^mips.*$ || $TARGET =~ ^mipsel.*$ ]]; then
|
||||
MUSL_TARGET=${TARGET}sf
|
||||
fi
|
||||
if [[ $MUSL_TARGET =~ musl ]]; then
|
||||
mkdir -p ./musl_gcc
|
||||
wget --inet4-only -c https://musl.cc/${MUSL_URI}-cross.tgz -P ./musl_gcc/
|
||||
tar zxf ./musl_gcc/${MUSL_URI}-cross.tgz -C ./musl_gcc/
|
||||
sudo ln -s $(pwd)/musl_gcc/${MUSL_URI}-cross/bin/*gcc /usr/bin/
|
||||
sudo ln -s $(pwd)/musl_gcc/${MUSL_URI}-cross/${MUSL_URI}/include/ /usr/include/musl-cross
|
||||
wget --inet4-only -c https://github.com/cross-tools/musl-cross/releases/download/20250520/${MUSL_TARGET}.tar.xz -P ./musl_gcc/
|
||||
tar xf ./musl_gcc/${MUSL_TARGET}.tar.xz -C ./musl_gcc/
|
||||
sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/bin/*gcc /usr/bin/
|
||||
sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/include/ /usr/include/musl-cross
|
||||
sudo ln -sf $(pwd)/musl_gcc/${MUSL_TARGET}/${MUSL_TARGET}/sysroot/ ./musl_gcc/sysroot
|
||||
sudo chmod -R a+rwx ./musl_gcc
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -50,7 +34,7 @@ rustup default 1.86
|
||||
|
||||
# mips/mipsel cannot add target from rustup, need compile by ourselves
|
||||
if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then
|
||||
cd "$PWD/musl_gcc/${MUSL_URI}-cross/lib/gcc/${MUSL_URI}/11.2.1" || exit 255
|
||||
cd "$PWD/musl_gcc/${MUSL_TARGET}/lib/gcc/${MUSL_TARGET}/15.1.0" || exit 255
|
||||
# for panic-abort
|
||||
cp libgcc_eh.a libunwind.a
|
||||
|
||||
|
||||
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
@@ -21,7 +21,7 @@ on:
|
||||
version:
|
||||
description: 'Version for this release'
|
||||
type: string
|
||||
default: 'v2.3.0'
|
||||
default: 'v2.3.1'
|
||||
required: true
|
||||
make_latest:
|
||||
description: 'Mark this release as latest'
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
repo: EasyTier/EasyTier
|
||||
path: release_assets_nozip
|
||||
|
||||
- name: Download GUI Artifact
|
||||
- name: Download Mobile Artifact
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
@@ -78,7 +78,14 @@ jobs:
|
||||
ls -l -R ./
|
||||
chmod -R 755 .
|
||||
for x in `ls`; do
|
||||
zip ../zipped_assets/$x-${VERSION}.zip $x/*;
|
||||
if [ "$x" = "Easytier-Magisk" ]; then
|
||||
# for Easytier-Magisk, make sure files are in the root of the zip
|
||||
cd $x;
|
||||
zip -r ../../zipped_assets/$x-${VERSION}.zip .;
|
||||
cd ..;
|
||||
else
|
||||
zip -r ../zipped_assets/$x-${VERSION}.zip $x;
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Release
|
||||
|
||||
277
Cargo.lock
generated
277
Cargo.lock
generated
@@ -23,6 +23,12 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
@@ -196,6 +202,15 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
||||
dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arboard"
|
||||
version = "3.4.0"
|
||||
@@ -229,7 +244,7 @@ dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"cpufeatures",
|
||||
"password-hash 0.5.0",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -274,8 +289,8 @@ dependencies = [
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"zstd 0.13.2",
|
||||
"zstd-safe 7.2.1",
|
||||
"zstd",
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -632,7 +647,7 @@ dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.7.4",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
@@ -853,9 +868,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
@@ -924,22 +939,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.4.4"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
|
||||
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.11+1.0.8"
|
||||
version = "0.1.13+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
|
||||
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
@@ -1289,9 +1302,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
||||
|
||||
[[package]]
|
||||
name = "conv"
|
||||
@@ -1550,12 +1563,6 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cty"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.1.3"
|
||||
@@ -1674,6 +1681,12 @@ dependencies = [
|
||||
"thiserror 1.0.63",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate64"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "0.3.8"
|
||||
@@ -1719,14 +1732,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_arbitrary"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.20.2"
|
||||
@@ -1918,11 +1942,10 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
|
||||
|
||||
[[package]]
|
||||
name = "easytier"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"async-compression",
|
||||
"async-recursion",
|
||||
"async-ringbuf",
|
||||
"async-stream",
|
||||
@@ -1950,6 +1973,7 @@ dependencies = [
|
||||
"gethostname 0.5.0",
|
||||
"git-version",
|
||||
"globwalk",
|
||||
"hashbrown 0.15.3",
|
||||
"hickory-client",
|
||||
"hickory-proto",
|
||||
"hickory-resolver",
|
||||
@@ -1964,7 +1988,7 @@ dependencies = [
|
||||
"kcp-sys",
|
||||
"machine-uid",
|
||||
"maplit",
|
||||
"mimalloc-rust",
|
||||
"mimalloc",
|
||||
"multimap",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-route 0.21.0",
|
||||
@@ -2030,6 +2054,7 @@ dependencies = [
|
||||
"winreg 0.52.0",
|
||||
"zerocopy",
|
||||
"zip",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2045,7 +2070,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "easytier-gui"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -2091,7 +2116,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "easytier-web"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -2401,12 +2426,13 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.31"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
"libz-rs-sys",
|
||||
"miniz_oxide 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2813,9 +2839,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3075,9 +3103,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
@@ -3681,7 +3709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
"hashbrown 0.15.3",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -3946,10 +3974,11 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.70"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -4090,12 +4119,42 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "liblzma"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66352d7a8ac12d4877b6e6ea5a9b7650ee094257dc40889955bea5bc5b08c1d0"
|
||||
dependencies = [
|
||||
"liblzma-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "liblzma-sys"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5839bad90c3cc2e0b8c4ed8296b80e86040240f81d46b9c0e9bc8dd51ddd3af1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "libmimalloc-sys"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
@@ -4123,6 +4182,15 @@ version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961"
|
||||
|
||||
[[package]]
|
||||
name = "libz-rs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
|
||||
dependencies = [
|
||||
"zlib-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
@@ -4154,9 +4222,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
@@ -4298,21 +4366,12 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mimalloc-rust"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/EasyTier/mimalloc-rust#eb61c4d50fef4eb5fbd5db83e4ea83153646b482"
|
||||
name = "mimalloc"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af"
|
||||
dependencies = [
|
||||
"cty",
|
||||
"mimalloc-rust-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mimalloc-rust-sys"
|
||||
version = "2.1.2-source"
|
||||
source = "git+https://github.com/EasyTier/mimalloc-rust#eb61c4d50fef4eb5fbd5db83e4ea83153646b482"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cty",
|
||||
"libmimalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4347,6 +4406,15 @@ dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.2"
|
||||
@@ -4788,7 +4856,7 @@ version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
|
||||
dependencies = [
|
||||
"proc-macro-crate 2.0.0",
|
||||
"proc-macro-crate 3.2.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
@@ -5270,21 +5338,10 @@ checksum = "1a2a4764cc1f8d961d802af27193c6f4f0124bd0e76e8393cf818e18880f0524"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"getrandom 0.2.15",
|
||||
"password-hash 0.5.0",
|
||||
"password-hash",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.5.0"
|
||||
@@ -5310,14 +5367,12 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.11.0"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
|
||||
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
"password-hash 0.4.2",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5362,7 +5417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06"
|
||||
dependencies = [
|
||||
"fixedbitset 0.5.7",
|
||||
"hashbrown 0.15.2",
|
||||
"hashbrown 0.15.3",
|
||||
"indexmap 2.7.1",
|
||||
"serde",
|
||||
]
|
||||
@@ -5667,7 +5722,7 @@ dependencies = [
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8421,9 +8476,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa 1.0.11",
|
||||
@@ -8438,15 +8493,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.18"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
@@ -9294,24 +9349,24 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.93"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.93"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
@@ -9332,9 +9387,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.93"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -9342,9 +9397,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.93"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -9355,9 +9410,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.93"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@@ -10311,31 +10369,46 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.6"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||
checksum = "153a6fff49d264c4babdcfa6b4d534747f520e56e8f0f384f3b808c4b64cc1fd"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"byteorder",
|
||||
"arbitrary",
|
||||
"bzip2",
|
||||
"constant_time_eq",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"deflate64",
|
||||
"flate2",
|
||||
"getrandom 0.3.2",
|
||||
"hmac",
|
||||
"indexmap 2.7.1",
|
||||
"liblzma",
|
||||
"memchr",
|
||||
"pbkdf2",
|
||||
"sha1",
|
||||
"time",
|
||||
"zstd 0.11.2+zstd.1.5.2",
|
||||
"zeroize",
|
||||
"zopfli",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.11.2+zstd.1.5.2"
|
||||
name = "zlib-rs"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
|
||||
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
|
||||
dependencies = [
|
||||
"zstd-safe 5.0.2+zstd.1.5.2",
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"log",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10344,17 +10417,7 @@ version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
|
||||
dependencies = [
|
||||
"zstd-safe 7.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "5.0.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"zstd-sys",
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -16,5 +16,5 @@ panic = "unwind"
|
||||
panic = "abort"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
opt-level = 'z'
|
||||
opt-level = 3
|
||||
strip = true
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
magisk安装后重启
|
||||
|
||||
目录位置:/data/adb/modules/easytier_magisk
|
||||
配置文件位置://data/adb/modules/easytier_magisk/config/config.conf
|
||||
配置文件位置://data/adb/modules/easytier_magisk/config/config.toml
|
||||
修改config.conf即可,修改后配置文件后去magisk app重新开关模块即可生效
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#!/data/adb/magisk/busybox sh
|
||||
MODDIR=${0%/*}
|
||||
echo 'Easytier 服务停止中....'
|
||||
|
||||
PIDS=$(pgrep -f "^${MODDIR}/easytier-core -c ${MODDIR}/config/config.conf")
|
||||
# 查找 easytier-core 进程的 PID
|
||||
PID=$(pgrep easytier-core)
|
||||
|
||||
if [ -n "$PIDS" ]; then
|
||||
kill $PIDS # 杀死所有匹配的进程
|
||||
echo "已停止所有 Easytier 进程 (PIDs: $PIDS)"
|
||||
# 检查是否找到了进程
|
||||
if [ -z "$PID" ]; then
|
||||
echo "easytier-core 进程未找到"
|
||||
else
|
||||
echo "Easytier 服务未运行"
|
||||
# 结束进程
|
||||
kill $PID
|
||||
echo "已结束 easytier-core 进程 (PID: $PID)"
|
||||
fi
|
||||
echo '重启服务中...'
|
||||
nohup sh ${MODDIR}/service.sh >> ${MODDIR}/log/start.log 2>&1 &
|
||||
echo '服务已重启'
|
||||
exit
|
||||
@@ -2,6 +2,6 @@ ui_print '安装完成'
|
||||
ui_print '当前架构为' + $ARCH
|
||||
ui_print '当前系统版本为' + $API
|
||||
ui_print '安装目录为: /data/adb/modules/easytier_magisk'
|
||||
ui_print '配置文件位置: /data/adb/modules/easytier_magisk/config/config.conf'
|
||||
ui_print '配置文件位置: /data/adb/modules/easytier_magisk/config/config.toml'
|
||||
ui_print '修改后配置文件后在magisk app点击操作按钮即可生效'
|
||||
ui_print '记得重启'
|
||||
48
easytier-contrib/easytier-magisk/easytier_core.sh
Normal file
48
easytier-contrib/easytier-magisk/easytier_core.sh
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
MODDIR=${0%/*}
|
||||
CONFIG_FILE="${MODDIR}/config/config.toml"
|
||||
LOG_FILE="${MODDIR}/log.log"
|
||||
MODULE_PROP="${MODDIR}/module.prop"
|
||||
EASYTIER="${MODDIR}/easytier-core"
|
||||
|
||||
# 更新module.prop文件中的description
|
||||
update_module_description() {
|
||||
local status_message=$1
|
||||
sed -i "/^description=/c\description=[状态]${status_message}" ${MODULE_PROP}
|
||||
}
|
||||
|
||||
if [ ! -e /dev/net/tun ]; then
|
||||
if [ ! -d /dev/net ]; then
|
||||
mkdir -p /dev/net
|
||||
fi
|
||||
|
||||
ln -s /dev/tun /dev/net/tun
|
||||
fi
|
||||
|
||||
while true; do
|
||||
if ls $MODDIR | grep -q "disable"; then
|
||||
update_module_description "关闭中"
|
||||
if pgrep -f 'easytier-core' >/dev/null; then
|
||||
echo "开关控制$(date "+%Y-%m-%d %H:%M:%S") 进程已存在,正在关闭 ..."
|
||||
pkill easytier-core # 关闭进程
|
||||
fi
|
||||
else
|
||||
if ! pgrep -f 'easytier-core' >/dev/null; then
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
update_module_description "config.toml不存在"
|
||||
sleep 3s
|
||||
continue
|
||||
fi
|
||||
|
||||
TZ=Asia/Shanghai ${EASYTIER} -c ${CONFIG_FILE} > ${LOG_FILE} &
|
||||
sleep 5s # 等待easytier-core启动完成
|
||||
update_module_description "已开启(不一定运行成功)"
|
||||
ip rule add from all lookup main
|
||||
else
|
||||
echo "开关控制$(date "+%Y-%m-%d %H:%M:%S") 进程已存在"
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 3s # 暂停3秒后再次执行循环
|
||||
done
|
||||
@@ -1,7 +1,7 @@
|
||||
id=easytier_magisk
|
||||
name=easytier_magisk版
|
||||
version=v2.2.4
|
||||
name=EasyTier_Magisk
|
||||
version=v2.3.1
|
||||
versionCode=1
|
||||
author=EasyTier
|
||||
description=easytier_magisk版模块 作者:EasyTier https://github.com/EasyTier/EasyTier
|
||||
description=easytier magisk module @EasyTier(https://github.com/EasyTier/EasyTier)
|
||||
updateJson=https://raw.githubusercontent.com/EasyTier/EasyTier/refs/heads/main/easytier-contrib/easytier-magisk/magisk_update.json
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
#!/data/adb/magisk/busybox sh
|
||||
MODDIR=${0%/*}
|
||||
# MODDIR="$(dirname $(readlink -f "$0"))"
|
||||
mkdir -p ${MODDIR}/log
|
||||
chmod 755 ${MODDIR}/*
|
||||
|
||||
echo $MODDIR >> ${MODDIR}/log/start.log
|
||||
# 等待系统启动成功
|
||||
while [ "$(getprop sys.boot_completed)" != "1" ]; do
|
||||
sleep 5s
|
||||
done
|
||||
|
||||
echo "Easytier 服务启动" >> ${MODDIR}/log/start.log
|
||||
# 防止系统挂起
|
||||
echo "PowerManagerService.noSuspend" > /sys/power/wake_lock
|
||||
|
||||
# 启动
|
||||
nohup ${MODDIR}/easytier-core -c ${MODDIR}/config/config.conf >> ${MODDIR}/log/start.log 2>&1 &
|
||||
# 修改模块描述
|
||||
sed -i 's/$(description=)$[^"]*/\1[状态]关闭中/' "$MODDIR/module.prop"
|
||||
|
||||
# 等待 3 秒
|
||||
sleep 3s
|
||||
|
||||
"${MODDIR}/easytier_core.sh" &
|
||||
|
||||
# 检查是否启用模块
|
||||
while [ ! -f ${MODDIR}/disable ]; do
|
||||
sleep 2
|
||||
done
|
||||
PID=$(ps -ef|grep "${MODDIR}/easytier-core -c ${MODDIR}/config/config.conf" | awk '{print $2}')
|
||||
kill $PID
|
||||
echo "Easytier 服务停止" >> ${MODDIR}/log/start.log
|
||||
|
||||
pkill easytier-core
|
||||
|
||||
2
easytier-contrib/easytier-magisk/system/etc/resolv.conf
Normal file
2
easytier-contrib/easytier-magisk/system/etc/resolv.conf
Normal file
@@ -0,0 +1,2 @@
|
||||
nameserver 114.114.114.114
|
||||
nameserver 223.5.5.5
|
||||
@@ -1,2 +1,3 @@
|
||||
MODDIR=${0%/*}
|
||||
pkill easytier-core # 结束 easytier-core 进程
|
||||
rm -rf $MODDIR/*
|
||||
@@ -18,7 +18,11 @@ cd ../tauri-plugin-vpnservice
|
||||
pnpm install
|
||||
pnpm build
|
||||
|
||||
cd ../easytier-gui
|
||||
cd ../easytier-web/frontend-lib
|
||||
pnpm install
|
||||
pnpm build
|
||||
|
||||
cd ../../easytier-gui
|
||||
pnpm install
|
||||
pnpm tauri build
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "easytier-gui",
|
||||
"type": "module",
|
||||
"version": "2.2.4",
|
||||
"version": "2.3.1",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "easytier-gui"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
description = "EasyTier GUI"
|
||||
authors = ["you"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -108,7 +108,12 @@ fn set_tun_fd(instance_id: String, fd: i32) -> Result<(), String> {
|
||||
fn toggle_window_visibility<R: tauri::Runtime>(app: &tauri::AppHandle<R>) {
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
if window.is_visible().unwrap_or_default() {
|
||||
let _ = window.hide();
|
||||
if window.is_minimized().unwrap_or_default() {
|
||||
let _ = window.unminimize();
|
||||
let _ = window.set_focus();
|
||||
} else {
|
||||
let _ = window.hide();
|
||||
}
|
||||
} else {
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"createUpdaterArtifacts": false
|
||||
},
|
||||
"productName": "easytier-gui",
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.1",
|
||||
"identifier": "com.kkrainbow.easytier",
|
||||
"plugins": {},
|
||||
"app": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "easytier-web"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
edition = "2021"
|
||||
description = "Config server for easytier. easytier-core gets config from this and web frontend use it as restful api server."
|
||||
|
||||
|
||||
@@ -157,6 +157,7 @@ const bool_flags: BoolFlag[] = [
|
||||
{ field: 'disable_encryption', help: 'disable_encryption_help' },
|
||||
{ field: 'disable_udp_hole_punching', help: 'disable_udp_hole_punching_help' },
|
||||
{ field: 'enable_magic_dns', help: 'enable_magic_dns_help' },
|
||||
{ field: 'enable_private_mode', help: 'enable_private_mode_help' },
|
||||
]
|
||||
|
||||
</script>
|
||||
|
||||
@@ -106,6 +106,10 @@ function ipFormat(info: PeerRoutePair) {
|
||||
return ip ? `${IPv4.fromNumber(ip.address.addr)}/${ip.network_length}` : ''
|
||||
}
|
||||
|
||||
function tunnelProto(info: PeerRoutePair) {
|
||||
return [...new Set(info.peer?.conns.map(c => c.tunnel?.tunnel_type))].join(',')
|
||||
}
|
||||
|
||||
const myNodeInfo = computed(() => {
|
||||
if (!props.curNetworkInst)
|
||||
return {} as NodeInfo
|
||||
@@ -311,7 +315,7 @@ function showEventLogs() {
|
||||
<Timeline v-else :value="dialogContent">
|
||||
<template #opposite="slotProps">
|
||||
<small class="text-surface-500 dark:text-surface-400">{{ useTimeAgo(Date.parse(slotProps.item.time))
|
||||
}}</small>
|
||||
}}</small>
|
||||
</template>
|
||||
<template #content="slotProps">
|
||||
<HumanEvent :event="slotProps.item.event" />
|
||||
@@ -408,6 +412,7 @@ function showEventLogs() {
|
||||
</template>
|
||||
</Column>
|
||||
<Column :field="routeCost" :header="t('route_cost')" />
|
||||
<Column :field="tunnelProto" :header="t('tunnel_proto')" />
|
||||
<Column :field="latencyMs" :header="t('latency')" />
|
||||
<Column :field="txBytes" :header="t('upload_bytes')" />
|
||||
<Column :field="rxBytes" :header="t('download_bytes')" />
|
||||
|
||||
@@ -64,6 +64,7 @@ event_log: 事件日志
|
||||
peer_info: 节点信息
|
||||
hostname: 主机名
|
||||
route_cost: 路由
|
||||
tunnel_proto: 协议
|
||||
latency: 延迟
|
||||
upload_bytes: 上传
|
||||
download_bytes: 下载
|
||||
@@ -116,6 +117,10 @@ enable_magic_dns: 启用魔法DNS
|
||||
enable_magic_dns_help: |
|
||||
启用魔法DNS,允许通过EasyTier的DNS服务器访问其他节点的虚拟IPv4地址, 如 node1.et.net。
|
||||
|
||||
enable_private_mode: 启用私有模式
|
||||
enable_private_mode_help: |
|
||||
启用私有模式,则不允许使用了与本网络不相同的网络名称和密码的节点通过本节点进行握手或中转。
|
||||
|
||||
relay_network_whitelist: 网络白名单
|
||||
relay_network_whitelist_help: |
|
||||
仅转发白名单网络的流量,支持通配符字符串。多个网络名称间可以使用英文空格间隔。
|
||||
|
||||
@@ -62,6 +62,7 @@ show_event_log: Show Event Log
|
||||
event_log: Event Log
|
||||
peer_info: Peer Info
|
||||
route_cost: Route Cost
|
||||
tunnel_proto: Protocol
|
||||
hostname: Hostname
|
||||
latency: Latency
|
||||
upload_bytes: Upload
|
||||
@@ -115,6 +116,10 @@ enable_magic_dns: Enable Magic DNS
|
||||
enable_magic_dns_help: |
|
||||
Enable magic dns, all nodes in the network can access each other by domain name, e.g.: node1.et.net.
|
||||
|
||||
enable_private_mode: Enable Private Mode
|
||||
enable_private_mode_help: |
|
||||
Enable private mode, nodes with different network names or passwords from this network are not allowed to perform handshake or relay through this node.
|
||||
|
||||
relay_network_whitelist: Network Whitelist
|
||||
relay_network_whitelist_help: |
|
||||
Only forward traffic from the whitelist networks, supporting wildcard strings, multiple network names can be separated by spaces.
|
||||
|
||||
@@ -64,6 +64,7 @@ export interface NetworkConfig {
|
||||
mapped_listeners: string[]
|
||||
|
||||
enable_magic_dns?: boolean
|
||||
enable_private_mode?: boolean
|
||||
}
|
||||
|
||||
export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
||||
@@ -121,6 +122,7 @@ export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
||||
mtu: null,
|
||||
mapped_listeners: [],
|
||||
enable_magic_dns: false,
|
||||
enable_private_mode: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<link rel="icon" type="image/png" href="/easytier.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>EasyTier Dashboard</title>
|
||||
<script src="/api_meta.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
const defaultApiHost = 'https://config-server.easytier.cn';
|
||||
|
||||
interface ApiHost {
|
||||
value: string;
|
||||
usedAt: number;
|
||||
}
|
||||
|
||||
let apiMeta: {
|
||||
api_host: string;
|
||||
} | undefined = (window as any).apiMeta;
|
||||
|
||||
// remove trailing slashes from the URL
|
||||
const cleanUrl = (url: string) => url.replace(/\/+$/, '');
|
||||
|
||||
const defaultApiHost = cleanUrl(apiMeta?.api_host ?? `${location.origin}${location.pathname}`);
|
||||
|
||||
const isValidHttpUrl = (s: string): boolean => {
|
||||
let url;
|
||||
|
||||
@@ -45,7 +52,7 @@ const saveApiHost = (host: string) => {
|
||||
}
|
||||
|
||||
let hosts = cleanAndLoadApiHosts();
|
||||
const newHost: ApiHost = {value: host, usedAt: Date.now()};
|
||||
const newHost: ApiHost = { value: host, usedAt: Date.now() };
|
||||
hosts = hosts.filter((h) => h.value !== host);
|
||||
hosts.push(newHost);
|
||||
localStorage.setItem('apiHosts', JSON.stringify(hosts));
|
||||
@@ -61,4 +68,4 @@ const getInitialApiHost = (): string => {
|
||||
}
|
||||
};
|
||||
|
||||
export {getInitialApiHost, cleanAndLoadApiHosts, saveApiHost}
|
||||
export { getInitialApiHost, cleanAndLoadApiHosts, saveApiHost }
|
||||
@@ -3,9 +3,20 @@ import vue from '@vitejs/plugin-vue'
|
||||
// import { viteSingleFile } from "vite-plugin-singlefile"
|
||||
|
||||
const WEB_BASE_URL = process.env.WEB_BASE_URL || '';
|
||||
const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:11211';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
base: WEB_BASE_URL,
|
||||
plugins: [vue(),/* viteSingleFile() */],
|
||||
server: {
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: API_BASE_URL,
|
||||
},
|
||||
"/api_meta.js": {
|
||||
target: API_BASE_URL,
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -27,4 +27,7 @@ cli:
|
||||
zh-CN: "web dashboard 服务器的监听端口, 默认为与 api 服务器端口相同"
|
||||
no_web:
|
||||
en: "Do not run the web dashboard server"
|
||||
zh-CN: "不运行 web dashboard 服务器"
|
||||
zh-CN: "不运行 web dashboard 服务器"
|
||||
api_host:
|
||||
en: "The URL of the API server, used by the web frontend to connect to"
|
||||
zh-CN: "API 服务器的 URL,用于 web 前端连接"
|
||||
@@ -12,7 +12,9 @@ use easytier::{
|
||||
constants::EASYTIER_VERSION,
|
||||
error::Error,
|
||||
},
|
||||
tunnel::{tcp::TcpTunnelListener, udp::UdpTunnelListener, TunnelListener},
|
||||
tunnel::{
|
||||
tcp::TcpTunnelListener, udp::UdpTunnelListener, websocket::WSTunnelListener, TunnelListener,
|
||||
},
|
||||
utils::{init_logger, setup_panic_handler},
|
||||
};
|
||||
|
||||
@@ -27,7 +29,7 @@ mod web;
|
||||
rust_i18n::i18n!("locales", fallback = "en");
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "easytier-core", author, version = EASYTIER_VERSION , about, long_about = None)]
|
||||
#[command(name = "easytier-web", author, version = EASYTIER_VERSION , about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short, long, default_value = "et.db", help = t!("cli.db").to_string())]
|
||||
db: String,
|
||||
@@ -89,12 +91,20 @@ struct Cli {
|
||||
default_value = "false"
|
||||
)]
|
||||
no_web: bool,
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
#[arg(
|
||||
long,
|
||||
help = t!("cli.api_host").to_string()
|
||||
)]
|
||||
api_host: Option<url::Url>,
|
||||
}
|
||||
|
||||
pub fn get_listener_by_url(l: &url::Url) -> Result<Box<dyn TunnelListener>, Error> {
|
||||
Ok(match l.scheme() {
|
||||
"tcp" => Box::new(TcpTunnelListener::new(l.clone())),
|
||||
"udp" => Box::new(UdpTunnelListener::new(l.clone())),
|
||||
"ws" => Box::new(WSTunnelListener::new(l.clone())),
|
||||
_ => {
|
||||
return Err(Error::InvalidUrl(l.to_string()));
|
||||
}
|
||||
@@ -136,36 +146,49 @@ async fn main() {
|
||||
let mgr = Arc::new(mgr);
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
let restful_also_serve_web = !cli.no_web
|
||||
&& (cli.web_server_port.is_none() || cli.web_server_port == Some(cli.api_server_port));
|
||||
|
||||
let (web_router_restful, web_router_static) = if cli.no_web {
|
||||
(None, None)
|
||||
} else {
|
||||
let web_router = web::build_router(cli.api_host.clone());
|
||||
if cli.web_server_port.is_none() || cli.web_server_port == Some(cli.api_server_port) {
|
||||
(Some(web_router), None)
|
||||
} else {
|
||||
(None, Some(web_router))
|
||||
}
|
||||
};
|
||||
#[cfg(not(feature = "embed"))]
|
||||
let restful_also_serve_web = false;
|
||||
let web_router_restful = None;
|
||||
|
||||
let mut restful_server = restful::RestfulServer::new(
|
||||
let _restful_server_tasks = restful::RestfulServer::new(
|
||||
format!("0.0.0.0:{}", cli.api_server_port).parse().unwrap(),
|
||||
mgr.clone(),
|
||||
db,
|
||||
restful_also_serve_web,
|
||||
web_router_restful,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.start()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
restful_server.start().await.unwrap();
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
let mut web_server = web::WebServer::new(
|
||||
format!("0.0.0.0:{}", cli.web_server_port.unwrap_or(0))
|
||||
.parse()
|
||||
let _web_server_task = if let Some(web_router) = web_router_static {
|
||||
Some(
|
||||
web::WebServer::new(
|
||||
format!("0.0.0.0:{}", cli.web_server_port.unwrap_or(0))
|
||||
.parse()
|
||||
.unwrap(),
|
||||
web_router,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.start()
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
if !cli.no_web && !restful_also_serve_web {
|
||||
web_server.start().await.unwrap();
|
||||
}
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
tokio::signal::ctrl_c().await.unwrap();
|
||||
}
|
||||
|
||||
@@ -39,12 +39,11 @@ pub struct RestfulServer {
|
||||
client_mgr: Arc<ClientManager>,
|
||||
db: Db,
|
||||
|
||||
serve_task: Option<ScopedTask<()>>,
|
||||
delete_task: Option<ScopedTask<tower_sessions::session_store::Result<()>>>,
|
||||
|
||||
// serve_task: Option<ScopedTask<()>>,
|
||||
// delete_task: Option<ScopedTask<tower_sessions::session_store::Result<()>>>,
|
||||
network_api: NetworkApi,
|
||||
|
||||
enable_web_embed: bool,
|
||||
web_router: Option<Router>,
|
||||
}
|
||||
|
||||
type AppStateInner = Arc<ClientManager>;
|
||||
@@ -94,7 +93,7 @@ impl RestfulServer {
|
||||
bind_addr: SocketAddr,
|
||||
client_mgr: Arc<ClientManager>,
|
||||
db: Db,
|
||||
enable_web_embed: bool,
|
||||
web_router: Option<Router>,
|
||||
) -> anyhow::Result<Self> {
|
||||
assert!(client_mgr.is_running());
|
||||
|
||||
@@ -104,10 +103,10 @@ impl RestfulServer {
|
||||
bind_addr,
|
||||
client_mgr,
|
||||
db,
|
||||
serve_task: None,
|
||||
delete_task: None,
|
||||
// serve_task: None,
|
||||
// delete_task: None,
|
||||
network_api,
|
||||
enable_web_embed,
|
||||
web_router,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -159,7 +158,15 @@ impl RestfulServer {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(&mut self) -> Result<(), anyhow::Error> {
|
||||
pub async fn start(
|
||||
mut self,
|
||||
) -> Result<
|
||||
(
|
||||
ScopedTask<()>,
|
||||
ScopedTask<tower_sessions::session_store::Result<()>>,
|
||||
),
|
||||
anyhow::Error,
|
||||
> {
|
||||
let listener = TcpListener::bind(self.bind_addr).await?;
|
||||
|
||||
// Session layer.
|
||||
@@ -169,14 +176,13 @@ impl RestfulServer {
|
||||
let session_store = SqliteStore::new(self.db.inner());
|
||||
session_store.migrate().await?;
|
||||
|
||||
self.delete_task.replace(
|
||||
let delete_task: ScopedTask<tower_sessions::session_store::Result<()>> =
|
||||
tokio::task::spawn(
|
||||
session_store
|
||||
.clone()
|
||||
.continuously_delete_expired(tokio::time::Duration::from_secs(60)),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
.into();
|
||||
|
||||
// Generate a cryptographic key to sign the session cookie.
|
||||
let key = Key::generate();
|
||||
@@ -216,19 +222,17 @@ impl RestfulServer {
|
||||
.layer(compression_layer);
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
let app = if self.enable_web_embed {
|
||||
use axum_embed::ServeEmbed;
|
||||
let service = ServeEmbed::<Assets>::new();
|
||||
app.fallback_service(service)
|
||||
let app = if let Some(web_router) = self.web_router.take() {
|
||||
app.merge(web_router)
|
||||
} else {
|
||||
app
|
||||
};
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
let serve_task: ScopedTask<()> = tokio::spawn(async move {
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
});
|
||||
self.serve_task = Some(task.into());
|
||||
})
|
||||
.into();
|
||||
|
||||
Ok(())
|
||||
Ok((serve_task, delete_task))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
use axum::Router;
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::header,
|
||||
response::{IntoResponse, Response},
|
||||
routing, Router,
|
||||
};
|
||||
use axum_embed::ServeEmbed;
|
||||
use easytier::common::scoped_task::ScopedTask;
|
||||
use rust_embed::RustEmbed;
|
||||
use std::net::SocketAddr;
|
||||
use axum_embed::ServeEmbed;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
/// Embed assets for web dashboard, build frontend first
|
||||
@@ -10,30 +15,72 @@ use tokio::net::TcpListener;
|
||||
#[folder = "frontend/dist/"]
|
||||
struct Assets;
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
struct ApiMetaResponse {
|
||||
api_host: String,
|
||||
}
|
||||
|
||||
async fn handle_api_meta(State(api_host): State<url::Url>) -> impl IntoResponse {
|
||||
Response::builder()
|
||||
.header(
|
||||
header::CONTENT_TYPE,
|
||||
"application/javascript; charset=utf-8",
|
||||
)
|
||||
.header(header::CACHE_CONTROL, "no-cache, no-store, must-revalidate")
|
||||
.header(header::PRAGMA, "no-cache")
|
||||
.header(header::EXPIRES, "0")
|
||||
.body(format!(
|
||||
"window.apiMeta = {}",
|
||||
serde_json::to_string(&ApiMetaResponse {
|
||||
api_host: api_host.to_string()
|
||||
})
|
||||
.unwrap(),
|
||||
))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn build_router(api_host: Option<url::Url>) -> Router {
|
||||
let service = ServeEmbed::<Assets>::new();
|
||||
let router = Router::new();
|
||||
|
||||
let router = if let Some(api_host) = api_host {
|
||||
let sub_router = Router::new()
|
||||
.route("/api_meta.js", routing::get(handle_api_meta))
|
||||
.with_state(api_host);
|
||||
router.merge(sub_router)
|
||||
} else {
|
||||
router
|
||||
};
|
||||
|
||||
let router = router.fallback_service(service);
|
||||
|
||||
router
|
||||
}
|
||||
|
||||
pub struct WebServer {
|
||||
bind_addr: SocketAddr,
|
||||
router: Router,
|
||||
serve_task: Option<ScopedTask<()>>,
|
||||
}
|
||||
|
||||
impl WebServer {
|
||||
pub async fn new(bind_addr: SocketAddr) -> anyhow::Result<Self> {
|
||||
pub async fn new(bind_addr: SocketAddr, router: Router) -> anyhow::Result<Self> {
|
||||
Ok(WebServer {
|
||||
bind_addr,
|
||||
router,
|
||||
serve_task: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn start(&mut self) -> Result<(), anyhow::Error> {
|
||||
pub async fn start(self) -> Result<ScopedTask<()>, anyhow::Error> {
|
||||
let listener = TcpListener::bind(self.bind_addr).await?;
|
||||
let service = ServeEmbed::<Assets>::new();
|
||||
let app = Router::new().fallback_service(service);
|
||||
let app = self.router;
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
});
|
||||
})
|
||||
.into();
|
||||
|
||||
self.serve_task = Some(task.into());
|
||||
|
||||
Ok(())
|
||||
Ok(task)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ name = "easytier"
|
||||
description = "A full meshed p2p VPN, connecting all your devices in one network with one command."
|
||||
homepage = "https://github.com/EasyTier/EasyTier"
|
||||
repository = "https://github.com/EasyTier/EasyTier"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
edition = "2021"
|
||||
authors = ["kkrainbow"]
|
||||
keywords = ["vpn", "p2p", "network", "easytier"]
|
||||
@@ -138,6 +138,7 @@ network-interface = "2.0"
|
||||
|
||||
# for ospf route
|
||||
petgraph = "0.8.1"
|
||||
hashbrown = "0.15.3"
|
||||
|
||||
# for wireguard
|
||||
boringtun = { package = "boringtun-easytier", version = "0.6.1", optional = true }
|
||||
@@ -153,7 +154,7 @@ humansize = "2.1.3"
|
||||
|
||||
base64 = "0.22"
|
||||
|
||||
mimalloc-rust = { git = "https://github.com/EasyTier/mimalloc-rust", optional = true }
|
||||
mimalloc = { version = "*", optional = true }
|
||||
|
||||
# mips
|
||||
atomic-shim = "0.2.0"
|
||||
@@ -185,10 +186,7 @@ async-ringbuf = "0.3.1"
|
||||
|
||||
service-manager = { git = "https://github.com/chipsenkbeil/service-manager-rs.git", branch = "main" }
|
||||
|
||||
async-compression = { version = "0.4.17", default-features = false, features = [
|
||||
"zstd",
|
||||
"tokio",
|
||||
] }
|
||||
zstd = { version = "0.13" }
|
||||
|
||||
kcp-sys = { git = "https://github.com/EasyTier/kcp-sys" }
|
||||
|
||||
@@ -260,7 +258,7 @@ prost-reflect-build = { version = "0.14.0" }
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
reqwest = { version = "0.12.12", features = ["blocking"] }
|
||||
zip = "0.6.6"
|
||||
zip = "4.0.0"
|
||||
|
||||
# enable thunk-rs when compiling for x86_64 or i686 windows
|
||||
[target.x86_64-pc-windows-msvc.build-dependencies]
|
||||
@@ -296,7 +294,7 @@ full = [
|
||||
mips = ["aes-gcm", "mimalloc", "wireguard", "tun", "smoltcp", "socks5"]
|
||||
wireguard = ["dep:boringtun", "dep:ring"]
|
||||
quic = ["dep:quinn", "dep:rustls", "dep:rcgen"]
|
||||
mimalloc = ["dep:mimalloc-rust"]
|
||||
mimalloc = ["dep:mimalloc"]
|
||||
aes-gcm = ["dep:aes-gcm"]
|
||||
tun = ["dep:tun"]
|
||||
websocket = [
|
||||
|
||||
@@ -155,6 +155,9 @@ core_clap:
|
||||
accept_dns:
|
||||
en: "if true, enable magic dns. with magic dns, you can access other nodes with a domain name, e.g.: <hostname>.et.net. magic dns will modify your system dns settings, enable it carefully."
|
||||
zh-CN: "如果为true,则启用魔法DNS。使用魔法DNS,您可以使用域名访问其他节点,例如:<hostname>.et.net。魔法DNS将修改您的系统DNS设置,请谨慎启用。"
|
||||
private_mode:
|
||||
en: "if true, nodes with different network names or passwords from this network are not allowed to perform handshake or relay through this node."
|
||||
zh-CN: "如果为true,则不允许使用了与本网络不相同的网络名称和密码的节点通过本节点进行握手或中转"
|
||||
|
||||
core_app:
|
||||
panic_backtrace_save:
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
use async_compression::tokio::write::{ZstdDecoder, ZstdEncoder};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use dashmap::DashMap;
|
||||
use std::cell::RefCell;
|
||||
use zstd::stream::read::Decoder;
|
||||
use zstd::stream::write::Encoder;
|
||||
use zstd::zstd_safe::{CCtx, DCtx};
|
||||
|
||||
use zerocopy::{AsBytes as _, FromBytes as _};
|
||||
|
||||
@@ -29,17 +34,20 @@ impl DefaultCompressor {
|
||||
data: &[u8],
|
||||
compress_algo: CompressorAlgo,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let buf = match compress_algo {
|
||||
match compress_algo {
|
||||
CompressorAlgo::ZstdDefault => {
|
||||
let mut o = ZstdEncoder::new(Vec::new());
|
||||
o.write_all(data).await?;
|
||||
o.shutdown().await?;
|
||||
o.into_inner()
|
||||
let ret = CTX_MAP.with(|map_cell| {
|
||||
let map = map_cell.borrow();
|
||||
let mut ctx_entry = map.entry(compress_algo).or_default();
|
||||
let writer = Vec::new();
|
||||
let mut o = Encoder::with_context(writer, ctx_entry.value_mut());
|
||||
o.write_all(data)?;
|
||||
o.finish()
|
||||
});
|
||||
Ok(ret?)
|
||||
}
|
||||
CompressorAlgo::None => data.to_vec(),
|
||||
};
|
||||
|
||||
Ok(buf)
|
||||
CompressorAlgo::None => Ok(data.to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn decompress_raw(
|
||||
@@ -47,17 +55,17 @@ impl DefaultCompressor {
|
||||
data: &[u8],
|
||||
compress_algo: CompressorAlgo,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let buf = match compress_algo {
|
||||
CompressorAlgo::ZstdDefault => {
|
||||
let mut o = ZstdDecoder::new(Vec::new());
|
||||
o.write_all(data).await?;
|
||||
o.shutdown().await?;
|
||||
o.into_inner()
|
||||
}
|
||||
CompressorAlgo::None => data.to_vec(),
|
||||
};
|
||||
|
||||
Ok(buf)
|
||||
match compress_algo {
|
||||
CompressorAlgo::ZstdDefault => DCTX_MAP.with(|map_cell| {
|
||||
let map = map_cell.borrow();
|
||||
let mut ctx_entry = map.entry(compress_algo).or_default();
|
||||
let mut decoder = Decoder::with_context(data, ctx_entry.value_mut());
|
||||
let mut output = Vec::new();
|
||||
decoder.read_to_end(&mut output)?;
|
||||
Ok(output)
|
||||
}),
|
||||
CompressorAlgo::None => Ok(data.to_vec()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +154,11 @@ impl Compressor for DefaultCompressor {
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static CTX_MAP: RefCell<DashMap<CompressorAlgo, CCtx<'static>>> = RefCell::new(DashMap::new());
|
||||
static DCTX_MAP: RefCell<DashMap<CompressorAlgo, DCtx<'static>>> = RefCell::new(DashMap::new());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
@@ -158,10 +171,21 @@ pub mod tests {
|
||||
|
||||
let compressor = DefaultCompressor {};
|
||||
|
||||
println!(
|
||||
"Uncompressed packet: {:?}, len: {}",
|
||||
packet,
|
||||
packet.payload_len()
|
||||
);
|
||||
|
||||
compressor
|
||||
.compress(&mut packet, CompressorAlgo::ZstdDefault)
|
||||
.await
|
||||
.unwrap();
|
||||
println!(
|
||||
"Compressed packet: {:?}, len: {}",
|
||||
packet,
|
||||
packet.payload_len()
|
||||
);
|
||||
assert_eq!(packet.peer_manager_header().unwrap().is_compressed(), true);
|
||||
|
||||
compressor.decompress(&mut packet).await.unwrap();
|
||||
|
||||
@@ -37,6 +37,7 @@ pub fn gen_default_flags() -> Flags {
|
||||
disable_kcp_input: false,
|
||||
disable_relay_kcp: true,
|
||||
accept_dns: false,
|
||||
private_mode: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::{
|
||||
io::Write as _,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use time::util::refresh_tz;
|
||||
use tokio::{task::JoinSet, time::timeout};
|
||||
use tracing::Instrument;
|
||||
|
||||
@@ -24,9 +25,7 @@ pub mod stun_codec_ext;
|
||||
pub fn get_logger_timer<F: time::formatting::Formattable>(
|
||||
format: F,
|
||||
) -> tracing_subscriber::fmt::time::OffsetTime<F> {
|
||||
unsafe {
|
||||
time::util::local_offset::set_soundness(time::util::local_offset::Soundness::Unsound)
|
||||
};
|
||||
refresh_tz();
|
||||
let local_offset = time::UtcOffset::current_local_offset()
|
||||
.unwrap_or(time::UtcOffset::from_whole_seconds(0).unwrap());
|
||||
tracing_subscriber::fmt::time::OffsetTime::new(local_offset, format)
|
||||
@@ -109,6 +108,9 @@ pub fn get_machine_id() -> uuid::Uuid {
|
||||
))]
|
||||
let gen_mid = machine_uid::get()
|
||||
.map(|x| {
|
||||
if x.is_empty() {
|
||||
return uuid::Uuid::new_v4();
|
||||
}
|
||||
let mut b = [0u8; 16];
|
||||
crate::tunnel::generate_digest_from_str("", x.as_str(), &mut b);
|
||||
uuid::Uuid::from_bytes(b)
|
||||
|
||||
@@ -56,8 +56,8 @@ impl From<NatType> for UdpNatType {
|
||||
fn from(nat_type: NatType) -> Self {
|
||||
match nat_type {
|
||||
NatType::Unknown => UdpNatType::Unknown,
|
||||
NatType::NoPat | NatType::OpenInternet => UdpNatType::Open(nat_type),
|
||||
NatType::FullCone | NatType::Restricted | NatType::PortRestricted => {
|
||||
NatType::OpenInternet => UdpNatType::Open(nat_type),
|
||||
NatType::NoPat | NatType::FullCone | NatType::Restricted | NatType::PortRestricted => {
|
||||
UdpNatType::Cone(nat_type)
|
||||
}
|
||||
NatType::Symmetric | NatType::SymUdpFirewall => UdpNatType::HardSymmetric(nat_type),
|
||||
|
||||
@@ -24,7 +24,7 @@ use easytier::{
|
||||
scoped_task::ScopedTask,
|
||||
stun::MockStunInfoCollector,
|
||||
},
|
||||
connector::{create_connector_by_url, dns_connector::DNSTunnelConnector},
|
||||
connector::create_connector_by_url,
|
||||
launcher,
|
||||
proto::{
|
||||
self,
|
||||
@@ -39,11 +39,11 @@ use easytier::{
|
||||
windows_service::define_windows_service!(ffi_service_main, win_service_main);
|
||||
|
||||
#[cfg(all(feature = "mimalloc", not(feature = "jemalloc")))]
|
||||
use mimalloc_rust::GlobalMiMalloc;
|
||||
use mimalloc::MiMalloc;
|
||||
|
||||
#[cfg(all(feature = "mimalloc", not(feature = "jemalloc")))]
|
||||
#[global_allocator]
|
||||
static GLOBAL_MIMALLOC: GlobalMiMalloc = GlobalMiMalloc;
|
||||
static GLOBAL_MIMALLOC: MiMalloc = MiMalloc;
|
||||
|
||||
#[cfg(feature = "jemalloc")]
|
||||
use jemalloc_ctl::{epoch, stats, Access as _, AsName as _};
|
||||
@@ -452,6 +452,13 @@ struct Cli {
|
||||
help = t!("core_clap.accept_dns").to_string(),
|
||||
)]
|
||||
accept_dns: Option<bool>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
env = "ET_PRIVATE_MODE",
|
||||
help = t!("core_clap.private_mode").to_string(),
|
||||
)]
|
||||
private_mode: Option<bool>,
|
||||
}
|
||||
|
||||
rust_i18n::i18n!("locales", fallback = "en");
|
||||
@@ -770,6 +777,7 @@ impl TryFrom<&Cli> for TomlConfigLoader {
|
||||
f.enable_kcp_proxy = cli.enable_kcp_proxy.unwrap_or(f.enable_kcp_proxy);
|
||||
f.disable_kcp_input = cli.disable_kcp_input.unwrap_or(f.disable_kcp_input);
|
||||
f.accept_dns = cli.accept_dns.unwrap_or(f.accept_dns);
|
||||
f.private_mode = cli.private_mode.unwrap_or(f.private_mode);
|
||||
cfg.set_flags(f);
|
||||
|
||||
if !cli.exit_nodes.is_empty() {
|
||||
@@ -1079,7 +1087,6 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
|
||||
hostname,
|
||||
);
|
||||
tokio::signal::ctrl_c().await.unwrap();
|
||||
DNSTunnelConnector::new("".parse().unwrap(), global_ctx);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
@@ -676,6 +676,10 @@ impl NetworkConfig {
|
||||
flags.mtu = mtu as u32;
|
||||
}
|
||||
|
||||
if let Some(enable_private_mode) = self.enable_private_mode {
|
||||
flags.private_mode = enable_private_mode;
|
||||
}
|
||||
|
||||
cfg.set_flags(flags);
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
179
easytier/src/peers/graph_algo.rs
Normal file
179
easytier/src/peers/graph_algo.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
use core::cmp::Ordering;
|
||||
use hashbrown::hash_map::{
|
||||
Entry::{Occupied, Vacant},
|
||||
HashMap,
|
||||
};
|
||||
use petgraph::{
|
||||
algo::Measure,
|
||||
visit::{EdgeRef as _, IntoEdges, VisitMap as _, Visitable},
|
||||
};
|
||||
use std::{collections::BinaryHeap, hash::Hash};
|
||||
|
||||
/// `MinScored<K, T>` holds a score `K` and a scored object `T` in
|
||||
/// a pair for use with a `BinaryHeap`.
|
||||
///
|
||||
/// `MinScored` compares in reverse order by the score, so that we can
|
||||
/// use `BinaryHeap` as a min-heap to extract the score-value pair with the
|
||||
/// least score.
|
||||
///
|
||||
/// **Note:** `MinScored` implements a total order (`Ord`), so that it is
|
||||
/// possible to use float types as scores.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MinScored<K, T>(pub K, pub T);
|
||||
|
||||
impl<K: PartialOrd, T> PartialEq for MinScored<K, T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &MinScored<K, T>) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: PartialOrd, T> Eq for MinScored<K, T> {}
|
||||
|
||||
impl<K: PartialOrd, T> PartialOrd for MinScored<K, T> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &MinScored<K, T>) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: PartialOrd, T> Ord for MinScored<K, T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &MinScored<K, T>) -> Ordering {
|
||||
let a = &self.0;
|
||||
let b = &other.0;
|
||||
if a == b {
|
||||
Ordering::Equal
|
||||
} else if a < b {
|
||||
Ordering::Greater
|
||||
} else if a > b {
|
||||
Ordering::Less
|
||||
} else if a.ne(a) && b.ne(b) {
|
||||
// these are the NaN cases
|
||||
Ordering::Equal
|
||||
} else if a.ne(a) {
|
||||
// Order NaN less, so that it is last in the MinScore order
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dijkstra_with_first_hop<G, F, K>(
|
||||
graph: G,
|
||||
start: G::NodeId,
|
||||
mut edge_cost: F,
|
||||
) -> (
|
||||
HashMap<G::NodeId, K>,
|
||||
HashMap<G::NodeId, (G::NodeId, usize)>,
|
||||
)
|
||||
where
|
||||
G: IntoEdges + Visitable,
|
||||
G::NodeId: Eq + Hash + Clone,
|
||||
F: FnMut(G::EdgeRef) -> K,
|
||||
K: Measure + Copy,
|
||||
{
|
||||
let mut visited = graph.visit_map();
|
||||
let mut scores = HashMap::new();
|
||||
let mut first_hop = HashMap::new();
|
||||
let mut visit_next = BinaryHeap::new();
|
||||
let zero_score = K::default();
|
||||
scores.insert(start.clone(), zero_score);
|
||||
visit_next.push(MinScored(zero_score, start.clone()));
|
||||
first_hop.insert(start.clone(), (start.clone(), 0));
|
||||
|
||||
while let Some(MinScored(node_score, node)) = visit_next.pop() {
|
||||
if visited.is_visited(&node) {
|
||||
continue;
|
||||
}
|
||||
for edge in graph.edges(node.clone()) {
|
||||
let next = edge.target();
|
||||
if visited.is_visited(&next) {
|
||||
continue;
|
||||
}
|
||||
let next_score = node_score + edge_cost(edge);
|
||||
match scores.entry(next.clone()) {
|
||||
Occupied(mut ent) => {
|
||||
if next_score < *ent.get() {
|
||||
*ent.get_mut() = next_score;
|
||||
visit_next.push(MinScored(next_score, next.clone()));
|
||||
// 继承前驱的 first_hop,或自己就是第一跳
|
||||
let hop = if node == start {
|
||||
(next.clone(), 0)
|
||||
} else {
|
||||
first_hop[&node].clone()
|
||||
};
|
||||
first_hop.insert(next.clone(), (hop.0, hop.1 + 1));
|
||||
}
|
||||
}
|
||||
Vacant(ent) => {
|
||||
ent.insert(next_score);
|
||||
visit_next.push(MinScored(next_score, next.clone()));
|
||||
let hop = if node == start {
|
||||
(next.clone(), 0)
|
||||
} else {
|
||||
first_hop[&node].clone()
|
||||
};
|
||||
first_hop.insert(next.clone(), (hop.0, hop.1 + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
visited.visit(node);
|
||||
}
|
||||
|
||||
(scores, first_hop)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use petgraph::graph::DiGraph;
|
||||
|
||||
#[test]
|
||||
fn test_dijkstra_with_first_hop_4node() {
|
||||
let mut graph = DiGraph::<&str, u32>::new();
|
||||
let a = graph.add_node("a");
|
||||
let b = graph.add_node("b");
|
||||
let c = graph.add_node("c");
|
||||
let d = graph.add_node("d");
|
||||
|
||||
graph.extend_with_edges(&[(a, b, 1)]);
|
||||
graph.extend_with_edges(&[(b, c, 1)]);
|
||||
graph.extend_with_edges(&[(c, d, 2)]);
|
||||
|
||||
let (scores, first_hop) = dijkstra_with_first_hop(&graph, a, |edge| *edge.weight());
|
||||
|
||||
assert_eq!(scores[&b], 1);
|
||||
assert_eq!(scores[&c], 2);
|
||||
assert_eq!(scores[&d], 4);
|
||||
|
||||
assert_eq!(first_hop[&b], (b, 1));
|
||||
assert_eq!(first_hop[&c], (b, 2));
|
||||
assert_eq!(first_hop[&d], (b, 3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dijkstra_with_first_hop() {
|
||||
let mut graph = DiGraph::<&str, u32>::new();
|
||||
let a = graph.add_node("a");
|
||||
let b = graph.add_node("b");
|
||||
let c = graph.add_node("c");
|
||||
let d = graph.add_node("d");
|
||||
let e = graph.add_node("e");
|
||||
|
||||
graph.extend_with_edges(&[(a, b, 1), (a, c, 2), (b, d, 1), (c, d, 3), (d, e, 1)]);
|
||||
|
||||
let (scores, first_hop) = dijkstra_with_first_hop(&graph, a, |edge| *edge.weight());
|
||||
|
||||
assert_eq!(scores[&b], 1);
|
||||
assert_eq!(scores[&c], 2);
|
||||
assert_eq!(scores[&d], 2);
|
||||
assert_eq!(scores[&e], 3);
|
||||
|
||||
assert_eq!(first_hop[&b], (b, 1));
|
||||
assert_eq!(first_hop[&c], (c, 1));
|
||||
assert_eq!(first_hop[&d], (b, 2)); // d is reached via b
|
||||
assert_eq!(first_hop[&e], (b, 3)); // e is reached via d
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
mod graph_algo;
|
||||
|
||||
pub mod peer;
|
||||
// pub mod peer_conn;
|
||||
pub mod peer_conn;
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use dashmap::DashMap;
|
||||
|
||||
use tokio::{select, sync::mpsc, task::JoinHandle};
|
||||
use tokio::{select, sync::mpsc};
|
||||
|
||||
use tracing::Instrument;
|
||||
|
||||
@@ -32,7 +32,7 @@ pub struct Peer {
|
||||
packet_recv_chan: PacketRecvChan,
|
||||
|
||||
close_event_sender: mpsc::Sender<PeerConnId>,
|
||||
close_event_listener: JoinHandle<()>,
|
||||
close_event_listener: ScopedTask<()>,
|
||||
|
||||
shutdown_notifier: Arc<tokio::sync::Notify>,
|
||||
|
||||
@@ -87,7 +87,8 @@ impl Peer {
|
||||
"peer_close_event_listener",
|
||||
?peer_node_id,
|
||||
)),
|
||||
);
|
||||
)
|
||||
.into();
|
||||
|
||||
let default_conn_id = Arc::new(AtomicCell::new(PeerConnId::default()));
|
||||
|
||||
@@ -118,8 +119,14 @@ impl Peer {
|
||||
}
|
||||
|
||||
pub async fn add_peer_conn(&self, mut conn: PeerConn) {
|
||||
let close_event_sender = self.close_event_sender.clone();
|
||||
let close_notifier = conn.get_close_notifier();
|
||||
let conn_info = conn.get_conn_info();
|
||||
|
||||
conn.start_recv_loop(self.packet_recv_chan.clone()).await;
|
||||
conn.start_pingpong();
|
||||
self.conns.insert(conn.get_conn_id(), Arc::new(conn));
|
||||
|
||||
let close_event_sender = self.close_event_sender.clone();
|
||||
tokio::spawn(async move {
|
||||
let conn_id = close_notifier.get_conn_id();
|
||||
if let Some(mut waiter) = close_notifier.get_waiter().await {
|
||||
@@ -130,12 +137,8 @@ impl Peer {
|
||||
}
|
||||
});
|
||||
|
||||
conn.start_recv_loop(self.packet_recv_chan.clone()).await;
|
||||
conn.start_pingpong();
|
||||
|
||||
self.global_ctx
|
||||
.issue_event(GlobalCtxEvent::PeerConnAdded(conn.get_conn_info()));
|
||||
self.conns.insert(conn.get_conn_id(), Arc::new(conn));
|
||||
.issue_event(GlobalCtxEvent::PeerConnAdded(conn_info));
|
||||
}
|
||||
|
||||
async fn select_conn(&self) -> Option<ArcPeerConn> {
|
||||
@@ -186,7 +189,13 @@ impl Peer {
|
||||
|
||||
let mut ret = Vec::new();
|
||||
for conn in conns {
|
||||
ret.push(conn.get_conn_info());
|
||||
let info = conn.get_conn_info();
|
||||
if !info.is_closed {
|
||||
ret.push(info);
|
||||
} else {
|
||||
let conn_id = info.conn_id.parse().unwrap();
|
||||
let _ = self.close_peer_conn(&conn_id).await;
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
@@ -432,6 +432,7 @@ impl PeerConn {
|
||||
loss_rate: (f64::from(self.loss_rate_stats.load(Ordering::Relaxed)) / 100.0) as f32,
|
||||
is_client: self.is_client.unwrap_or_default(),
|
||||
network_name: info.network_name.clone(),
|
||||
is_closed: self.close_event_notifier.is_closed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ impl std::fmt::Debug for PingIntervalController {
|
||||
|
||||
impl PingIntervalController {
|
||||
fn new(throughput: Arc<Throughput>, loss_counter: Arc<AtomicU32>) -> Self {
|
||||
let last_throughput = *throughput;
|
||||
let last_throughput = (*throughput).clone();
|
||||
|
||||
Self {
|
||||
throughput,
|
||||
@@ -92,7 +92,7 @@ impl PingIntervalController {
|
||||
self.backoff_idx = 0;
|
||||
}
|
||||
|
||||
self.last_throughput = *self.throughput;
|
||||
self.last_throughput = (*self.throughput).clone();
|
||||
|
||||
if (self.logic_time - self.last_send_logic_time) < (1 << self.backoff_idx) {
|
||||
return false;
|
||||
|
||||
@@ -422,6 +422,14 @@ impl PeerManager {
|
||||
tracing::info!("add tunnel as server start");
|
||||
let mut peer = PeerConn::new(self.my_peer_id, self.global_ctx.clone(), tunnel);
|
||||
peer.do_handshake_as_server().await?;
|
||||
if self.global_ctx.config.get_flags().private_mode
|
||||
&& peer.get_network_identity().network_name
|
||||
!= self.global_ctx.get_network_identity().network_name
|
||||
{
|
||||
return Err(Error::SecretKeyError(
|
||||
"private mode is turned on, network identity not match".to_string(),
|
||||
));
|
||||
}
|
||||
if peer.get_network_identity().network_name
|
||||
== self.global_ctx.get_network_identity().network_name
|
||||
{
|
||||
@@ -1078,7 +1086,8 @@ mod tests {
|
||||
use crate::{
|
||||
common::{config::Flags, global_ctx::tests::get_mock_global_ctx},
|
||||
connector::{
|
||||
create_connector_by_url, udp_hole_punch::tests::create_mock_peer_manager_with_mock_stun,
|
||||
create_connector_by_url, direct::PeerManagerForDirectConnector,
|
||||
udp_hole_punch::tests::create_mock_peer_manager_with_mock_stun,
|
||||
},
|
||||
instance::listeners::get_listener_by_url,
|
||||
peers::{
|
||||
@@ -1089,7 +1098,12 @@ mod tests {
|
||||
tests::{connect_peer_manager, wait_route_appear, wait_route_appear_with_cost},
|
||||
},
|
||||
proto::common::{CompressionAlgoPb, NatType, PeerFeatureFlag},
|
||||
tunnel::{common::tests::wait_for_condition, TunnelConnector, TunnelListener},
|
||||
tunnel::{
|
||||
common::tests::wait_for_condition,
|
||||
filter::{tests::DropSendTunnelFilter, TunnelWithFilter},
|
||||
ring::create_ring_tunnel_pair,
|
||||
TunnelConnector, TunnelListener,
|
||||
},
|
||||
};
|
||||
|
||||
use super::PeerManager;
|
||||
@@ -1268,6 +1282,12 @@ mod tests {
|
||||
let peer_mgr_d = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
|
||||
let peer_mgr_e = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
|
||||
|
||||
println!("peer_mgr_a: {}", peer_mgr_a.my_peer_id);
|
||||
println!("peer_mgr_b: {}", peer_mgr_b.my_peer_id);
|
||||
println!("peer_mgr_c: {}", peer_mgr_c.my_peer_id);
|
||||
println!("peer_mgr_d: {}", peer_mgr_d.my_peer_id);
|
||||
println!("peer_mgr_e: {}", peer_mgr_e.my_peer_id);
|
||||
|
||||
connect_peer_manager(peer_mgr_a.clone(), peer_mgr_b.clone()).await;
|
||||
connect_peer_manager(peer_mgr_b.clone(), peer_mgr_c.clone()).await;
|
||||
|
||||
@@ -1323,4 +1343,36 @@ mod tests {
|
||||
.await;
|
||||
assert_eq!(ret, Some(peer_mgr_b.my_peer_id));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_client_inbound_blackhole() {
|
||||
let peer_mgr_a = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
|
||||
let peer_mgr_b = create_mock_peer_manager_with_mock_stun(NatType::Unknown).await;
|
||||
|
||||
// a is client, b is server
|
||||
|
||||
let (a_ring, b_ring) = create_ring_tunnel_pair();
|
||||
let a_ring = Box::new(TunnelWithFilter::new(
|
||||
a_ring,
|
||||
DropSendTunnelFilter::new(2, 50000),
|
||||
));
|
||||
|
||||
let a_mgr_copy = peer_mgr_a.clone();
|
||||
tokio::spawn(async move {
|
||||
a_mgr_copy.add_client_tunnel(a_ring).await.unwrap();
|
||||
});
|
||||
let b_mgr_copy = peer_mgr_b.clone();
|
||||
tokio::spawn(async move {
|
||||
b_mgr_copy.add_tunnel_as_server(b_ring, true).await.unwrap();
|
||||
});
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
let peers = peer_mgr_a.list_peers().await;
|
||||
peers.is_empty()
|
||||
},
|
||||
Duration::from_secs(10),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::{
|
||||
collections::BTreeSet,
|
||||
fmt::Debug,
|
||||
hash::RandomState,
|
||||
net::Ipv4Addr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU32, Ordering},
|
||||
@@ -13,9 +12,10 @@ use std::{
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use dashmap::DashMap;
|
||||
use petgraph::{
|
||||
algo::{all_simple_paths, astar, dijkstra},
|
||||
graph::NodeIndex,
|
||||
Directed, Graph,
|
||||
algo::dijkstra,
|
||||
graph::{Graph, NodeIndex},
|
||||
visit::{EdgeRef, IntoNodeReferences},
|
||||
Directed,
|
||||
};
|
||||
use prost::Message;
|
||||
use prost_reflect::{DynamicMessage, ReflectMessage};
|
||||
@@ -49,6 +49,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
graph_algo::dijkstra_with_first_hop,
|
||||
peer_rpc::PeerRpcManager,
|
||||
route_trait::{
|
||||
DefaultRouteCostCalculator, ForeignNetworkRouteInfoMap, NextHopPolicy, RouteCostCalculator,
|
||||
@@ -60,7 +61,8 @@ use super::{
|
||||
static SERVICE_ID: u32 = 7;
|
||||
static UPDATE_PEER_INFO_PERIOD: Duration = Duration::from_secs(3600);
|
||||
static REMOVE_DEAD_PEER_INFO_AFTER: Duration = Duration::from_secs(3660);
|
||||
static AVOID_RELAY_COST: i32 = i32::MAX / 512;
|
||||
// the cost (latency between two peers) is i32, i32::MAX is large enough.
|
||||
static AVOID_RELAY_COST: usize = i32::MAX as usize;
|
||||
|
||||
type Version = u32;
|
||||
|
||||
@@ -80,14 +82,13 @@ impl AtomicVersion {
|
||||
self.0.store(version, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn inc(&self) {
|
||||
self.0.fetch_add(1, Ordering::Relaxed);
|
||||
fn inc(&self) -> Version {
|
||||
self.0.fetch_add(1, Ordering::Relaxed) + 1
|
||||
}
|
||||
|
||||
fn set_if_larger(&self, version: Version) {
|
||||
if self.get() < version {
|
||||
self.set(version);
|
||||
}
|
||||
fn set_if_larger(&self, version: Version) -> bool {
|
||||
// return true if the version is set.
|
||||
self.0.fetch_max(version, Ordering::Relaxed) < version
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,13 +284,25 @@ impl RouteConnBitmap {
|
||||
type Error = SyncRouteInfoError;
|
||||
|
||||
// constructed with all infos synced from all peers.
|
||||
#[derive(Debug)]
|
||||
struct SyncedRouteInfo {
|
||||
peer_infos: DashMap<PeerId, RoutePeerInfo>,
|
||||
// prost doesn't support unknown fields, so we use DynamicMessage to store raw infos and progate them to other peers.
|
||||
raw_peer_infos: DashMap<PeerId, DynamicMessage>,
|
||||
conn_map: DashMap<PeerId, (BTreeSet<PeerId>, AtomicVersion)>,
|
||||
foreign_network: DashMap<ForeignNetworkRouteInfoKey, ForeignNetworkRouteInfoEntry>,
|
||||
|
||||
version: AtomicVersion,
|
||||
}
|
||||
|
||||
impl Debug for SyncedRouteInfo {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SyncedRouteInfo")
|
||||
.field("peer_infos", &self.peer_infos)
|
||||
.field("conn_map", &self.conn_map)
|
||||
.field("foreign_network", &self.foreign_network)
|
||||
.field("version", &self.version.get())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncedRouteInfo {
|
||||
@@ -305,17 +318,24 @@ impl SyncedRouteInfo {
|
||||
self.raw_peer_infos.remove(&peer_id);
|
||||
self.conn_map.remove(&peer_id);
|
||||
self.foreign_network.retain(|k, _| k.peer_id != peer_id);
|
||||
self.version.inc();
|
||||
}
|
||||
|
||||
fn fill_empty_peer_info(&self, peer_ids: &BTreeSet<PeerId>) {
|
||||
let mut need_inc_version = false;
|
||||
for peer_id in peer_ids {
|
||||
self.peer_infos
|
||||
.entry(*peer_id)
|
||||
.or_insert_with(|| RoutePeerInfo::new());
|
||||
self.peer_infos.entry(*peer_id).or_insert_with(|| {
|
||||
need_inc_version = true;
|
||||
RoutePeerInfo::new()
|
||||
});
|
||||
|
||||
self.conn_map
|
||||
.entry(*peer_id)
|
||||
.or_insert_with(|| (BTreeSet::new(), AtomicVersion::new()));
|
||||
self.conn_map.entry(*peer_id).or_insert_with(|| {
|
||||
need_inc_version = true;
|
||||
(BTreeSet::new(), AtomicVersion::new())
|
||||
});
|
||||
}
|
||||
if need_inc_version {
|
||||
self.version.inc();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,6 +397,7 @@ impl SyncedRouteInfo {
|
||||
peer_infos: &Vec<RoutePeerInfo>,
|
||||
raw_peer_infos: &Vec<DynamicMessage>,
|
||||
) -> Result<(), Error> {
|
||||
let mut need_inc_version = false;
|
||||
for (idx, route_info) in peer_infos.iter().enumerate() {
|
||||
let mut route_info = route_info.clone();
|
||||
let raw_route_info = &raw_peer_infos[idx];
|
||||
@@ -410,22 +431,28 @@ impl SyncedRouteInfo {
|
||||
self.raw_peer_infos
|
||||
.insert(route_info.peer_id, raw_route_info.clone());
|
||||
*old_entry = route_info.clone();
|
||||
need_inc_version = true;
|
||||
}
|
||||
})
|
||||
.or_insert_with(|| {
|
||||
need_inc_version = true;
|
||||
self.raw_peer_infos
|
||||
.insert(route_info.peer_id, raw_route_info.clone());
|
||||
route_info.clone()
|
||||
});
|
||||
}
|
||||
if need_inc_version {
|
||||
self.version.inc();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_conn_map(&self, conn_bitmap: &RouteConnBitmap) {
|
||||
self.fill_empty_peer_info(&conn_bitmap.peer_ids.iter().map(|x| x.0).collect());
|
||||
|
||||
let mut need_inc_version = false;
|
||||
|
||||
for (peer_idx, (peer_id, version)) in conn_bitmap.peer_ids.iter().enumerate() {
|
||||
assert!(self.peer_infos.contains_key(peer_id));
|
||||
let connceted_peers = conn_bitmap.get_connected_peers(peer_idx);
|
||||
self.fill_empty_peer_info(&connceted_peers);
|
||||
|
||||
@@ -433,17 +460,19 @@ impl SyncedRouteInfo {
|
||||
.entry(*peer_id)
|
||||
.and_modify(|(old_conn_bitmap, old_version)| {
|
||||
if *version > old_version.get() {
|
||||
*old_conn_bitmap = conn_bitmap.get_connected_peers(peer_idx);
|
||||
*old_conn_bitmap = connceted_peers.clone();
|
||||
need_inc_version = true;
|
||||
old_version.set(*version);
|
||||
}
|
||||
})
|
||||
.or_insert_with(|| {
|
||||
(
|
||||
conn_bitmap.get_connected_peers(peer_idx),
|
||||
version.clone().into(),
|
||||
)
|
||||
need_inc_version = true;
|
||||
(connceted_peers, version.clone().into())
|
||||
});
|
||||
}
|
||||
if need_inc_version {
|
||||
self.version.inc();
|
||||
}
|
||||
}
|
||||
|
||||
fn update_foreign_network(&self, foreign_network: &RouteForeignNetworkInfos) {
|
||||
@@ -483,7 +512,12 @@ impl SyncedRouteInfo {
|
||||
let old_version = old.version;
|
||||
*old = new;
|
||||
|
||||
new_version != old_version
|
||||
if new_version != old_version {
|
||||
self.version.inc();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn update_my_conn_info(&self, my_peer_id: PeerId, connected_peers: BTreeSet<PeerId>) -> bool {
|
||||
@@ -499,6 +533,7 @@ impl SyncedRouteInfo {
|
||||
} else {
|
||||
let _ = std::mem::replace(&mut my_conn_info.value_mut().0, connected_peers);
|
||||
my_conn_info.value().1.inc();
|
||||
self.version.inc();
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -557,6 +592,10 @@ impl SyncedRouteInfo {
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if updated {
|
||||
self.version.inc();
|
||||
}
|
||||
|
||||
updated
|
||||
}
|
||||
|
||||
@@ -573,13 +612,14 @@ impl SyncedRouteInfo {
|
||||
}
|
||||
}
|
||||
|
||||
type PeerGraph = Graph<PeerId, i32, Directed>;
|
||||
type PeerGraph = Graph<PeerId, usize, Directed>;
|
||||
type PeerIdToNodexIdxMap = DashMap<PeerId, NodeIndex>;
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct NextHopInfo {
|
||||
next_hop_peer_id: PeerId,
|
||||
path_latency: i32,
|
||||
path_len: usize, // path includes src and dst.
|
||||
version: Version,
|
||||
}
|
||||
// dst_peer_id -> (next_hop_peer_id, cost, path_len)
|
||||
type NextHopMap = DashMap<PeerId, NextHopInfo>;
|
||||
@@ -591,6 +631,7 @@ struct RouteTable {
|
||||
next_hop_map: NextHopMap,
|
||||
ipv4_peer_id_map: DashMap<Ipv4Addr, PeerId>,
|
||||
cidr_peer_id_map: DashMap<cidr::IpCidr, PeerId>,
|
||||
next_hop_map_version: AtomicVersion,
|
||||
}
|
||||
|
||||
impl RouteTable {
|
||||
@@ -600,15 +641,23 @@ impl RouteTable {
|
||||
next_hop_map: DashMap::new(),
|
||||
ipv4_peer_id_map: DashMap::new(),
|
||||
cidr_peer_id_map: DashMap::new(),
|
||||
next_hop_map_version: AtomicVersion::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_hop(&self, dst_peer_id: PeerId) -> Option<NextHopInfo> {
|
||||
self.next_hop_map.get(&dst_peer_id).map(|x| *x)
|
||||
let cur_version = self.next_hop_map_version.get();
|
||||
self.next_hop_map.get(&dst_peer_id).and_then(|x| {
|
||||
if x.version >= cur_version {
|
||||
Some(*x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn peer_reachable(&self, peer_id: PeerId) -> bool {
|
||||
self.next_hop_map.contains_key(&peer_id)
|
||||
self.get_next_hop(peer_id).is_some()
|
||||
}
|
||||
|
||||
fn get_nat_type(&self, peer_id: PeerId) -> Option<NatType> {
|
||||
@@ -617,158 +666,16 @@ impl RouteTable {
|
||||
.map(|x| NatType::try_from(x.udp_stun_info as i32).unwrap_or_default())
|
||||
}
|
||||
|
||||
// return graph and start node index (node of my peer id).
|
||||
fn build_peer_graph_from_synced_info<T: RouteCostCalculatorInterface>(
|
||||
peers: Vec<PeerId>,
|
||||
synced_info: &SyncedRouteInfo,
|
||||
cost_calc: &mut T,
|
||||
) -> (PeerGraph, PeerIdToNodexIdxMap) {
|
||||
let mut graph: PeerGraph = Graph::new();
|
||||
let peer_id_to_node_index = PeerIdToNodexIdxMap::new();
|
||||
for peer_id in peers.iter() {
|
||||
peer_id_to_node_index.insert(*peer_id, graph.add_node(*peer_id));
|
||||
}
|
||||
|
||||
for peer_id in peers.iter() {
|
||||
let connected_peers = synced_info
|
||||
.get_connected_peers(*peer_id)
|
||||
.unwrap_or(BTreeSet::new());
|
||||
|
||||
// if avoid relay, just set all outgoing edges to a large value: AVOID_RELAY_COST.
|
||||
let peer_avoid_relay_data = synced_info.get_avoid_relay_data(*peer_id);
|
||||
|
||||
for dst_peer_id in connected_peers.iter() {
|
||||
let Some(dst_idx) = peer_id_to_node_index.get(dst_peer_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
graph.add_edge(
|
||||
*peer_id_to_node_index.get(&peer_id).unwrap(),
|
||||
*dst_idx,
|
||||
if peer_avoid_relay_data {
|
||||
AVOID_RELAY_COST
|
||||
} else {
|
||||
cost_calc.calculate_cost(*peer_id, *dst_peer_id)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
(graph, peer_id_to_node_index)
|
||||
}
|
||||
|
||||
fn gen_next_hop_map_with_least_hop<T: RouteCostCalculatorInterface>(
|
||||
my_peer_id: PeerId,
|
||||
graph: &PeerGraph,
|
||||
idx_map: &PeerIdToNodexIdxMap,
|
||||
cost_calc: &mut T,
|
||||
) -> NextHopMap {
|
||||
let res = dijkstra(&graph, *idx_map.get(&my_peer_id).unwrap(), None, |_| 1);
|
||||
let next_hop_map = NextHopMap::new();
|
||||
for (node_idx, cost) in res.iter() {
|
||||
if *cost == 0 {
|
||||
continue;
|
||||
}
|
||||
let mut all_paths = all_simple_paths::<Vec<_>, _, RandomState>(
|
||||
graph,
|
||||
*idx_map.get(&my_peer_id).unwrap(),
|
||||
*node_idx,
|
||||
*cost - 1,
|
||||
Some(*cost + 1), // considering having avoid relay, the max cost could be a bit larger.
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert!(!all_paths.is_empty());
|
||||
all_paths.sort_by(|a, b| a.len().cmp(&b.len()));
|
||||
|
||||
// find a path with least cost.
|
||||
let mut min_cost = i32::MAX;
|
||||
let mut min_path_len = usize::MAX;
|
||||
let mut min_path = Vec::new();
|
||||
for path in all_paths.iter() {
|
||||
if min_path_len < path.len() && min_cost < AVOID_RELAY_COST {
|
||||
// the min path does not contain avoid relay node.
|
||||
break;
|
||||
}
|
||||
|
||||
let mut cost = 0;
|
||||
for i in 0..path.len() - 1 {
|
||||
let src_peer_id = *graph.node_weight(path[i]).unwrap();
|
||||
let dst_peer_id = *graph.node_weight(path[i + 1]).unwrap();
|
||||
let edge_weight = *graph
|
||||
.edge_weight(graph.find_edge(path[i], path[i + 1]).unwrap())
|
||||
.unwrap();
|
||||
if edge_weight != 1 {
|
||||
// means avoid relay.
|
||||
cost += edge_weight;
|
||||
} else {
|
||||
cost += cost_calc.calculate_cost(src_peer_id, dst_peer_id);
|
||||
}
|
||||
}
|
||||
|
||||
if cost <= min_cost {
|
||||
min_cost = cost;
|
||||
min_path = path.clone();
|
||||
min_path_len = path.len();
|
||||
}
|
||||
}
|
||||
next_hop_map.insert(
|
||||
*graph.node_weight(*node_idx).unwrap(),
|
||||
NextHopInfo {
|
||||
next_hop_peer_id: *graph.node_weight(min_path[1]).unwrap(),
|
||||
path_latency: min_cost,
|
||||
path_len: min_path_len,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
next_hop_map
|
||||
}
|
||||
|
||||
fn gen_next_hop_map_with_least_cost(
|
||||
my_peer_id: PeerId,
|
||||
graph: &PeerGraph,
|
||||
idx_map: &PeerIdToNodexIdxMap,
|
||||
) -> NextHopMap {
|
||||
let next_hop_map = NextHopMap::new();
|
||||
for item in idx_map.iter() {
|
||||
if *item.key() == my_peer_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
let dst_peer_node_idx = *item.value();
|
||||
|
||||
let Some((cost, path)) = astar::astar(
|
||||
graph,
|
||||
*idx_map.get(&my_peer_id).unwrap(),
|
||||
|node_idx| node_idx == dst_peer_node_idx,
|
||||
|e| *e.weight(),
|
||||
|_| 0,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
next_hop_map.insert(
|
||||
*item.key(),
|
||||
NextHopInfo {
|
||||
next_hop_peer_id: *graph.node_weight(path[1]).unwrap(),
|
||||
path_latency: cost,
|
||||
path_len: path.len(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
next_hop_map
|
||||
}
|
||||
|
||||
fn build_from_synced_info<T: RouteCostCalculatorInterface>(
|
||||
&self,
|
||||
my_peer_id: PeerId,
|
||||
synced_info: &SyncedRouteInfo,
|
||||
policy: NextHopPolicy,
|
||||
mut cost_calc: T,
|
||||
) {
|
||||
// build peer_infos
|
||||
self.peer_infos.clear();
|
||||
cost_calc: &T,
|
||||
) -> (PeerGraph, NodeIndex) {
|
||||
let mut graph: PeerGraph = PeerGraph::new();
|
||||
|
||||
let mut start_node_idx = None;
|
||||
let peer_id_to_node_index: PeerIdToNodexIdxMap = DashMap::new();
|
||||
for item in synced_info.peer_infos.iter() {
|
||||
let peer_id = item.key();
|
||||
let info = item.value();
|
||||
@@ -777,49 +684,175 @@ impl RouteTable {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.peer_infos.insert(*peer_id, info.clone());
|
||||
let node_idx = graph.add_node(*peer_id);
|
||||
|
||||
peer_id_to_node_index.insert(*peer_id, node_idx);
|
||||
if *peer_id == my_peer_id {
|
||||
start_node_idx = Some(node_idx);
|
||||
}
|
||||
}
|
||||
|
||||
if self.peer_infos.is_empty() {
|
||||
if start_node_idx.is_none() {
|
||||
return (graph, NodeIndex::end());
|
||||
}
|
||||
|
||||
for item in peer_id_to_node_index.iter() {
|
||||
let src_peer_id = item.key();
|
||||
let src_node_idx = item.value();
|
||||
let connected_peers = synced_info
|
||||
.get_connected_peers(*src_peer_id)
|
||||
.unwrap_or(BTreeSet::new());
|
||||
|
||||
// if avoid relay, just set all outgoing edges to a large value: AVOID_RELAY_COST.
|
||||
let peer_avoid_relay_data = synced_info.get_avoid_relay_data(*src_peer_id);
|
||||
|
||||
for dst_peer_id in connected_peers.iter() {
|
||||
let Some(dst_node_idx) = peer_id_to_node_index.get(dst_peer_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut cost = cost_calc.calculate_cost(*src_peer_id, *dst_peer_id) as usize;
|
||||
if peer_avoid_relay_data {
|
||||
cost += AVOID_RELAY_COST;
|
||||
}
|
||||
|
||||
graph.add_edge(*src_node_idx, *dst_node_idx, cost);
|
||||
}
|
||||
}
|
||||
|
||||
(graph, start_node_idx.unwrap())
|
||||
}
|
||||
|
||||
fn clean_expired_route_info(&self) {
|
||||
let cur_version = self.next_hop_map_version.get();
|
||||
self.next_hop_map.retain(|_, v| {
|
||||
// remove next hop map for peers we cannot reach.
|
||||
v.version >= cur_version
|
||||
});
|
||||
self.peer_infos.retain(|k, _| {
|
||||
// remove peer info for peers we cannot reach.
|
||||
self.next_hop_map.contains_key(k)
|
||||
});
|
||||
self.ipv4_peer_id_map.retain(|_, v| {
|
||||
// remove ipv4 map for peers we cannot reach.
|
||||
self.next_hop_map.contains_key(v)
|
||||
});
|
||||
self.cidr_peer_id_map.retain(|_, v| {
|
||||
// remove cidr map for peers we cannot reach.
|
||||
self.next_hop_map.contains_key(v)
|
||||
});
|
||||
}
|
||||
|
||||
fn gen_next_hop_map_with_least_hop(
|
||||
&self,
|
||||
graph: &PeerGraph,
|
||||
start_node: &NodeIndex,
|
||||
version: Version,
|
||||
) {
|
||||
let normalize_edge_cost = |e: petgraph::graph::EdgeReference<usize>| {
|
||||
if *e.weight() >= AVOID_RELAY_COST {
|
||||
AVOID_RELAY_COST + 1
|
||||
} else {
|
||||
1
|
||||
}
|
||||
};
|
||||
// Step 1: 第一次 Dijkstra - 计算最短跳数
|
||||
let path_len_map = dijkstra(&graph, *start_node, None, normalize_edge_cost);
|
||||
|
||||
// Step 2: 构建最短跳数子图(只保留属于最短路径和 AVOID RELAY 的边)
|
||||
let mut subgraph: PeerGraph = PeerGraph::new();
|
||||
let mut start_node_idx = None;
|
||||
for (node_idx, peer_id) in graph.node_references() {
|
||||
let new_node_idx = subgraph.add_node(*peer_id);
|
||||
if node_idx == *start_node {
|
||||
start_node_idx = Some(new_node_idx);
|
||||
}
|
||||
}
|
||||
|
||||
for edge in graph.edge_references() {
|
||||
let (src, tgt) = graph.edge_endpoints(edge.id()).unwrap();
|
||||
let Some(src_path_len) = path_len_map.get(&src) else {
|
||||
continue;
|
||||
};
|
||||
let Some(tgt_path_len) = path_len_map.get(&tgt) else {
|
||||
continue;
|
||||
};
|
||||
if *src_path_len + normalize_edge_cost(edge) == *tgt_path_len {
|
||||
subgraph.add_edge(src, tgt, *edge.weight());
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: 第二次 Dijkstra - 在子图上找代价最小的路径
|
||||
self.gen_next_hop_map_with_least_cost(&subgraph, &start_node_idx.clone().unwrap(), version);
|
||||
}
|
||||
|
||||
fn gen_next_hop_map_with_least_cost(
|
||||
&self,
|
||||
graph: &PeerGraph,
|
||||
start_node: &NodeIndex,
|
||||
version: Version,
|
||||
) {
|
||||
let (costs, next_hops) = dijkstra_with_first_hop(&graph, *start_node, |e| *e.weight());
|
||||
|
||||
for (dst, (next_hop, path_len)) in next_hops.iter() {
|
||||
let info = NextHopInfo {
|
||||
next_hop_peer_id: *graph.node_weight(*next_hop).unwrap(),
|
||||
path_latency: (*costs.get(dst).unwrap() % AVOID_RELAY_COST) as i32,
|
||||
path_len: *path_len as usize,
|
||||
version,
|
||||
};
|
||||
let dst_peer_id = *graph.node_weight(*dst).unwrap();
|
||||
self.next_hop_map
|
||||
.entry(dst_peer_id)
|
||||
.and_modify(|x| {
|
||||
if x.version < version {
|
||||
*x = info;
|
||||
}
|
||||
})
|
||||
.or_insert(info);
|
||||
}
|
||||
|
||||
self.next_hop_map_version.set_if_larger(version);
|
||||
}
|
||||
|
||||
fn build_from_synced_info<T: RouteCostCalculatorInterface>(
|
||||
&self,
|
||||
my_peer_id: PeerId,
|
||||
synced_info: &SyncedRouteInfo,
|
||||
policy: NextHopPolicy,
|
||||
cost_calc: &T,
|
||||
) {
|
||||
let version = synced_info.version.get();
|
||||
|
||||
// build next hop map
|
||||
let (graph, start_node) =
|
||||
Self::build_peer_graph_from_synced_info(my_peer_id, &synced_info, cost_calc);
|
||||
|
||||
if graph.node_count() == 0 {
|
||||
tracing::warn!("no peer in graph, cannot build next hop map");
|
||||
return;
|
||||
}
|
||||
|
||||
// build next hop map
|
||||
self.next_hop_map.clear();
|
||||
self.next_hop_map.insert(
|
||||
my_peer_id,
|
||||
NextHopInfo {
|
||||
next_hop_peer_id: my_peer_id,
|
||||
path_latency: 0,
|
||||
path_len: 1,
|
||||
},
|
||||
);
|
||||
let (graph, idx_map) = Self::build_peer_graph_from_synced_info(
|
||||
self.peer_infos.iter().map(|x| *x.key()).collect(),
|
||||
&synced_info,
|
||||
&mut cost_calc,
|
||||
);
|
||||
let next_hop_map = if matches!(policy, NextHopPolicy::LeastHop) {
|
||||
Self::gen_next_hop_map_with_least_hop(my_peer_id, &graph, &idx_map, &mut cost_calc)
|
||||
if matches!(policy, NextHopPolicy::LeastHop) {
|
||||
self.gen_next_hop_map_with_least_hop(&graph, &start_node, version);
|
||||
} else {
|
||||
Self::gen_next_hop_map_with_least_cost(my_peer_id, &graph, &idx_map)
|
||||
self.gen_next_hop_map_with_least_cost(&graph, &start_node, version);
|
||||
};
|
||||
for item in next_hop_map.iter() {
|
||||
self.next_hop_map.insert(*item.key(), *item.value());
|
||||
}
|
||||
// build graph
|
||||
|
||||
// build ipv4_peer_id_map, cidr_peer_id_map
|
||||
self.ipv4_peer_id_map.clear();
|
||||
self.cidr_peer_id_map.clear();
|
||||
for item in self.peer_infos.iter() {
|
||||
// only set ipv4 map for peers we can reach.
|
||||
if !self.next_hop_map.contains_key(item.key()) {
|
||||
// build peer_infos, ipv4_peer_id_map, cidr_peer_id_map
|
||||
// only set map for peers we can reach.
|
||||
for item in self.next_hop_map.iter() {
|
||||
if item.version < version {
|
||||
// skip if the next hop entry is outdated. (peer is unreachable)
|
||||
continue;
|
||||
}
|
||||
|
||||
let peer_id = item.key();
|
||||
let info = item.value();
|
||||
let Some(info) = synced_info.peer_infos.get(peer_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
self.peer_infos.insert(*peer_id, info.clone());
|
||||
|
||||
if let Some(ipv4_addr) = info.ipv4_addr {
|
||||
self.ipv4_peer_id_map.insert(ipv4_addr.into(), *peer_id);
|
||||
@@ -1022,12 +1055,13 @@ struct PeerRouteServiceImpl {
|
||||
|
||||
interface: Mutex<Option<RouteInterfaceBox>>,
|
||||
|
||||
cost_calculator: std::sync::Mutex<Option<RouteCostCalculator>>,
|
||||
cost_calculator: std::sync::RwLock<Option<RouteCostCalculator>>,
|
||||
route_table: RouteTable,
|
||||
route_table_with_cost: RouteTable,
|
||||
foreign_network_owner_map: DashMap<NetworkIdentity, Vec<PeerId>>,
|
||||
synced_route_info: SyncedRouteInfo,
|
||||
cached_local_conn_map: std::sync::Mutex<RouteConnBitmap>,
|
||||
cached_local_conn_map_version: AtomicVersion,
|
||||
|
||||
last_update_my_foreign_network: AtomicCell<Option<std::time::Instant>>,
|
||||
|
||||
@@ -1063,7 +1097,7 @@ impl PeerRouteServiceImpl {
|
||||
|
||||
interface: Mutex::new(None),
|
||||
|
||||
cost_calculator: std::sync::Mutex::new(Some(Box::new(DefaultRouteCostCalculator))),
|
||||
cost_calculator: std::sync::RwLock::new(Some(Box::new(DefaultRouteCostCalculator))),
|
||||
|
||||
route_table: RouteTable::new(),
|
||||
route_table_with_cost: RouteTable::new(),
|
||||
@@ -1074,8 +1108,10 @@ impl PeerRouteServiceImpl {
|
||||
raw_peer_infos: DashMap::new(),
|
||||
conn_map: DashMap::new(),
|
||||
foreign_network: DashMap::new(),
|
||||
version: AtomicVersion::new(),
|
||||
},
|
||||
cached_local_conn_map: std::sync::Mutex::new(RouteConnBitmap::new()),
|
||||
cached_local_conn_map_version: AtomicVersion::new(),
|
||||
|
||||
last_update_my_foreign_network: AtomicCell::new(None),
|
||||
|
||||
@@ -1171,23 +1207,37 @@ impl PeerRouteServiceImpl {
|
||||
}
|
||||
|
||||
fn update_route_table(&self) {
|
||||
let mut calc_locked = self.cost_calculator.lock().unwrap();
|
||||
self.cost_calculator
|
||||
.write()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_update();
|
||||
|
||||
let calc_locked = self.cost_calculator.read().unwrap();
|
||||
|
||||
calc_locked.as_mut().unwrap().begin_update();
|
||||
self.route_table.build_from_synced_info(
|
||||
self.my_peer_id,
|
||||
&self.synced_route_info,
|
||||
NextHopPolicy::LeastHop,
|
||||
calc_locked.as_mut().unwrap(),
|
||||
calc_locked.as_ref().unwrap(),
|
||||
);
|
||||
|
||||
self.route_table_with_cost.build_from_synced_info(
|
||||
self.my_peer_id,
|
||||
&self.synced_route_info,
|
||||
NextHopPolicy::LeastCost,
|
||||
calc_locked.as_mut().unwrap(),
|
||||
calc_locked.as_ref().unwrap(),
|
||||
);
|
||||
calc_locked.as_mut().unwrap().end_update();
|
||||
|
||||
drop(calc_locked);
|
||||
|
||||
self.cost_calculator
|
||||
.write()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.end_update();
|
||||
}
|
||||
|
||||
fn update_foreign_network_owner_map(&self) {
|
||||
@@ -1221,7 +1271,7 @@ impl PeerRouteServiceImpl {
|
||||
|
||||
fn cost_calculator_need_update(&self) -> bool {
|
||||
self.cost_calculator
|
||||
.lock()
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.map(|x| x.need_update())
|
||||
@@ -1234,6 +1284,8 @@ impl PeerRouteServiceImpl {
|
||||
// update route table first because we want to filter out unreachable peers.
|
||||
self.update_route_table();
|
||||
|
||||
let synced_version = self.synced_route_info.version.get();
|
||||
|
||||
// the conn_bitmap should contain complete list of directly connected peers.
|
||||
// use union of dst peers can preserve this property.
|
||||
let all_dst_peer_ids = self
|
||||
@@ -1259,7 +1311,9 @@ impl PeerRouteServiceImpl {
|
||||
|
||||
let all_peer_ids = &conn_bitmap.peer_ids;
|
||||
for (peer_idx, (peer_id, _)) in all_peer_ids.iter().enumerate() {
|
||||
let connected = self.synced_route_info.conn_map.get(peer_id).unwrap();
|
||||
let Some(connected) = self.synced_route_info.conn_map.get(peer_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for (idx, (other_peer_id, _)) in all_peer_ids.iter().enumerate() {
|
||||
if connected.0.contains(other_peer_id) {
|
||||
@@ -1269,7 +1323,13 @@ impl PeerRouteServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
*self.cached_local_conn_map.lock().unwrap() = conn_bitmap;
|
||||
let mut locked = self.cached_local_conn_map.lock().unwrap();
|
||||
if self
|
||||
.cached_local_conn_map_version
|
||||
.set_if_larger(synced_version)
|
||||
{
|
||||
*locked = conn_bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
fn build_route_info(&self, session: &SyncRouteSession) -> Option<Vec<RoutePeerInfo>> {
|
||||
@@ -1411,6 +1471,9 @@ impl PeerRouteServiceImpl {
|
||||
for p in to_remove.iter() {
|
||||
self.synced_route_info.foreign_network.remove(p);
|
||||
}
|
||||
|
||||
self.route_table.clean_expired_route_info();
|
||||
self.route_table_with_cost.clean_expired_route_info();
|
||||
}
|
||||
|
||||
fn build_sync_route_raw_req(
|
||||
@@ -2022,6 +2085,7 @@ impl PeerRoute {
|
||||
|
||||
if service_impl.cost_calculator_need_update() {
|
||||
tracing::debug!("cost_calculator_need_update");
|
||||
service_impl.synced_route_info.version.inc();
|
||||
service_impl.update_route_table();
|
||||
}
|
||||
|
||||
@@ -2136,7 +2200,7 @@ impl Route for PeerRoute {
|
||||
let next_hop_peer_latency_first = route_table_with_cost.get_next_hop(*item.key());
|
||||
let mut route: crate::proto::cli::Route = item.value().clone().into();
|
||||
route.next_hop_peer_id = next_hop_peer.next_hop_peer_id;
|
||||
route.cost = (next_hop_peer.path_len - 1) as i32;
|
||||
route.cost = next_hop_peer.path_len as i32;
|
||||
route.path_latency = next_hop_peer.path_latency;
|
||||
|
||||
route.next_hop_peer_id_latency_first =
|
||||
@@ -2166,7 +2230,8 @@ impl Route for PeerRoute {
|
||||
}
|
||||
|
||||
async fn set_route_cost_fn(&self, _cost_fn: RouteCostCalculator) {
|
||||
*self.service_impl.cost_calculator.lock().unwrap() = Some(_cost_fn);
|
||||
*self.service_impl.cost_calculator.write().unwrap() = Some(_cost_fn);
|
||||
self.service_impl.synced_route_info.version.inc();
|
||||
self.service_impl.update_route_table();
|
||||
}
|
||||
|
||||
@@ -2307,7 +2372,10 @@ mod tests {
|
||||
|
||||
for r in vec![r_a.clone(), r_b.clone()].iter() {
|
||||
wait_for_condition(
|
||||
|| async { r.list_routes().await.len() == 1 },
|
||||
|| async {
|
||||
println!("route: {:?}", r.list_routes().await);
|
||||
r.list_routes().await.len() == 1
|
||||
},
|
||||
Duration::from_secs(5),
|
||||
)
|
||||
.await;
|
||||
@@ -2348,6 +2416,8 @@ mod tests {
|
||||
assert_eq!(i_a.0, i_b.1);
|
||||
assert_eq!(i_b.0, i_a.1);
|
||||
|
||||
println!("after drop p_b, r_b");
|
||||
|
||||
drop(r_b);
|
||||
drop(p_b);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ message PeerConnInfo {
|
||||
float loss_rate = 7;
|
||||
bool is_client = 8;
|
||||
string network_name = 9;
|
||||
bool is_closed = 10;
|
||||
}
|
||||
|
||||
message PeerInfo {
|
||||
|
||||
@@ -33,6 +33,8 @@ message FlagsInConfig {
|
||||
|
||||
// enable magic dns or not
|
||||
bool accept_dns = 22;
|
||||
// enable private mode
|
||||
bool private_mode = 23;
|
||||
}
|
||||
|
||||
message RpcDescriptor {
|
||||
|
||||
@@ -65,6 +65,7 @@ message NetworkConfig {
|
||||
repeated string mapped_listeners = 41;
|
||||
|
||||
optional bool enable_magic_dns = 42;
|
||||
optional bool enable_private_mode = 43;
|
||||
}
|
||||
|
||||
message MyNodeInfo {
|
||||
|
||||
@@ -234,7 +234,7 @@ pub struct AesGcmTail {
|
||||
}
|
||||
pub const AES_GCM_ENCRYPTION_RESERVED: usize = std::mem::size_of::<AesGcmTail>();
|
||||
|
||||
#[derive(AsBytes, FromZeroes, Clone, Debug, Copy)]
|
||||
#[derive(AsBytes, FromZeroes, Clone, Debug, Copy, PartialEq, Hash, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum CompressorAlgo {
|
||||
None = 0,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::sync::atomic::{AtomicU32, Ordering::Relaxed};
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
sync::atomic::{AtomicU32, Ordering::Relaxed},
|
||||
};
|
||||
|
||||
pub struct WindowLatency {
|
||||
latency_us_window: Vec<AtomicU32>,
|
||||
@@ -58,13 +61,38 @@ impl WindowLatency {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct Throughput {
|
||||
tx_bytes: u64,
|
||||
rx_bytes: u64,
|
||||
tx_bytes: UnsafeCell<u64>,
|
||||
rx_bytes: UnsafeCell<u64>,
|
||||
tx_packets: UnsafeCell<u64>,
|
||||
rx_packets: UnsafeCell<u64>,
|
||||
}
|
||||
|
||||
tx_packets: u64,
|
||||
rx_packets: u64,
|
||||
impl Clone for Throughput {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
tx_bytes: UnsafeCell::new(unsafe { *self.tx_bytes.get() }),
|
||||
rx_bytes: UnsafeCell::new(unsafe { *self.rx_bytes.get() }),
|
||||
tx_packets: UnsafeCell::new(unsafe { *self.tx_packets.get() }),
|
||||
rx_packets: UnsafeCell::new(unsafe { *self.rx_packets.get() }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add sync::Send and sync::Sync traits to Throughput
|
||||
unsafe impl Send for Throughput {}
|
||||
unsafe impl Sync for Throughput {}
|
||||
|
||||
impl Default for Throughput {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tx_bytes: UnsafeCell::new(0),
|
||||
rx_bytes: UnsafeCell::new(0),
|
||||
tx_packets: UnsafeCell::new(0),
|
||||
rx_packets: UnsafeCell::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Throughput {
|
||||
@@ -73,34 +101,32 @@ impl Throughput {
|
||||
}
|
||||
|
||||
pub fn tx_bytes(&self) -> u64 {
|
||||
self.tx_bytes
|
||||
unsafe { *self.tx_bytes.get() }
|
||||
}
|
||||
|
||||
pub fn rx_bytes(&self) -> u64 {
|
||||
self.rx_bytes
|
||||
unsafe { *self.rx_bytes.get() }
|
||||
}
|
||||
|
||||
pub fn tx_packets(&self) -> u64 {
|
||||
self.tx_packets
|
||||
unsafe { *self.tx_packets.get() }
|
||||
}
|
||||
|
||||
pub fn rx_packets(&self) -> u64 {
|
||||
self.rx_packets
|
||||
unsafe { *self.rx_packets.get() }
|
||||
}
|
||||
|
||||
pub fn record_tx_bytes(&self, bytes: u64) {
|
||||
#[allow(invalid_reference_casting)]
|
||||
unsafe {
|
||||
*(&self.tx_bytes as *const u64 as *mut u64) += bytes;
|
||||
*(&self.tx_packets as *const u64 as *mut u64) += 1;
|
||||
*self.tx_bytes.get() += bytes;
|
||||
*self.tx_packets.get() += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_rx_bytes(&self, bytes: u64) {
|
||||
#[allow(invalid_reference_casting)]
|
||||
unsafe {
|
||||
*(&self.rx_bytes as *const u64 as *mut u64) += bytes;
|
||||
*(&self.rx_packets as *const u64 as *mut u64) += 1;
|
||||
*self.rx_bytes.get() += bytes;
|
||||
*self.rx_packets.get() += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,8 +183,6 @@ impl WSTunnelConnector {
|
||||
) -> Result<Box<dyn Tunnel>, TunnelError> {
|
||||
let is_wss = is_wss(&addr)?;
|
||||
let socket_addr = SocketAddr::from_url(addr.clone(), ip_version).await?;
|
||||
let domain = addr.domain();
|
||||
let host = socket_addr.ip();
|
||||
let stream = tcp_socket.connect(socket_addr).await?;
|
||||
|
||||
let info = TunnelInfo {
|
||||
@@ -204,13 +202,11 @@ impl WSTunnelConnector {
|
||||
init_crypto_provider();
|
||||
let tls_conn =
|
||||
tokio_rustls::TlsConnector::from(Arc::new(get_insecure_tls_client_config()));
|
||||
let domain_or_ip = match domain {
|
||||
None => host.to_string(),
|
||||
Some(domain) => domain.to_string(),
|
||||
};
|
||||
let stream = tls_conn
|
||||
.connect(domain_or_ip.try_into().unwrap(), stream)
|
||||
.await?;
|
||||
// Modify SNI logic: always use "localhost" as SNI to avoid IP blocking.
|
||||
let sni = "localhost";
|
||||
let server_name = rustls::pki_types::ServerName::try_from(sni)
|
||||
.map_err(|_| TunnelError::InvalidProtocol("Invalid SNI".to_string()))?;
|
||||
let stream = tls_conn.connect(server_name, stream).await?;
|
||||
MaybeTlsStream::Rustls(stream)
|
||||
} else {
|
||||
MaybeTlsStream::Plain(stream)
|
||||
|
||||
@@ -205,7 +205,7 @@ pub fn setup_panic_handler() {
|
||||
|
||||
// backtrace is risky, so use it last
|
||||
let backtrace = backtrace::Backtrace::force_capture();
|
||||
write_err(format!("backtrace: {:?}", backtrace));
|
||||
write_err(format!("backtrace: {:#?}", backtrace));
|
||||
|
||||
std::process::exit(1);
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user